Mercurial > hg > xemacs-beta
diff lisp/w3/w3-draw.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | ac2d302a0011 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/w3/w3-draw.el Mon Aug 13 08:45:50 2007 +0200 @@ -0,0 +1,2165 @@ +;;; w3-draw.el,v --- Emacs-W3 drawing functions for new display engine +;; Author: wmperry +;; Created: 1996/06/03 16:59:57 +;; Version: 1.365 +;; Keywords: faces, help, hypermedia + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Copyright (c) 1993, 1994, 1995 by William M. Perry (wmperry@spry.com) +;;; +;;; This file is not part of GNU Emacs, but the same permissions apply. +;;; +;;; GNU Emacs is free software; you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 2, or (at your option) +;;; any later version. +;;; +;;; GNU Emacs is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Emacs; see the file COPYING. If not, write to +;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; This function will take a stream of HTML from w3-preparse-buffer +;;; and draw it out +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'w3-vars) +(require 'w3-imap) +(require 'w3-widget) +(require 'widget) +(require 'cl) + +(if (featurep 'mule) (fset 'string-width 'length)) + +(defmacro w3-get-state (tag) + (or (symbolp tag) + (error "Bad argument: %s" tag)) + (let ((index (length (memq tag w3-state-locator-variable)))) + (` (aref w3-state-vector (, index))))) +(put 'w3-get-state 'edebug-form-spec '(symbolp)) + +(defmacro w3-put-state (tag val) + (or (symbolp tag) + (error "Bad argument: %s" tag)) + (let ((index (length (memq tag w3-state-locator-variable)))) + (` (aset w3-state-vector (, index) (, val))))) +(put 'w3-put-state 'edebug-form-spec '(symbolp form)) + +(defsubst w3-push-alignment (align) + (if align + (w3-put-state :align (cons (cons tag align) (w3-get-state :align))))) + +(defsubst w3-pop-alignment () + (let ((flubber (memq (assq tag (w3-get-state :align)) + (w3-get-state :align)))) + (cond + ((null flubber) nil) + ((cdr flubber) + (w3-put-state :align (cdr flubber))) + (t (w3-put-state :align nil))))) + +(defsubst w3-current-alignment () + (cdr-safe (car-safe (w3-get-state :align)))) + +(defconst w3-fill-prefixes-vector + (let ((len 0) + (prefix-vector (make-vector 80 nil))) + (while (< len 80) + (aset prefix-vector len (make-string len ? )) + (setq len (1+ len))) + prefix-vector)) + +(defsubst w3-set-fill-prefix-length (len) + (let ((len len)) + (setq fill-prefix (if (< len 80) + (aref w3-fill-prefixes-vector len) + (make-string len ? ))))) + +(defsubst w3-get-default-style-info (info) + (and w3-current-stylesheet + (or + ;; Check for tag/class first! + (cdr-safe (assq info + (cdr-safe + (assoc (cdr-safe (assq 'class args)) + (cdr-safe + (assq tag w3-current-stylesheet)))))) + + ;; Then for global stuff with 'class' + (cdr-safe (assq info + (cdr-safe + (assoc (cdr-safe (assq 'class args)) + (cdr-safe + (assq 'doc w3-current-stylesheet)))))) + + ;; Fall back on the default styles for just this tag. + (cdr-safe (assq info + (cdr-safe + (assq 'internal + (cdr-safe + (assq tag w3-current-stylesheet))))))))) + +(defun w3-normalize-color (color) + (cond + ((valid-color-name-p color) + color) + ((valid-color-name-p (concat "#" color)) + (concat "#" color)) + ((string-match "[ \t\r\n]" color) + (w3-normalize-color + (mapconcat (function (lambda (x) (if (memq x '(?\t ?\r ?\n ? )) "" + (char-to-string x)))) color ""))) + (t + (w3-warn 'html (format "Bad color specification: %s" color)) + nil))) + +(defun w3-pause () + (cond + (w3-running-FSF19 (sit-for 0)) + (w3-running-xemacs + (if (and (not (sit-for 0)) (input-pending-p)) + (condition-case () + (dispatch-event (next-command-event)) + (error nil)))) + (t (sit-for 0)))) + +(defvar w3-end-tags + '((/ul . ul) + (/lit . lit) + (/li . li) + (/h1 . h1) + (/h2 . h2) + (/h3 . h3) + (/h4 . h4) + (/h5 . h5) + (/h6 . h6) + (/font0 . font0) + (/font1 . font1) + (/font2 . font2) + (/font3 . font3) + (/font4 . font4) + (/font5 . font5) + (/font6 . font6) + (/font7 . font7) + (/ol . ol) + (/dl . dl) + (/menu . menu) + (/dir . dir) + (/a . a))) + +(defvar w3-face-cache nil + "Cache for w3-face-for-element") + +;; This is just for if we don't have Emacspeak loaded so we do not +;; get compile/run-time errors. +(defvar dtk-voice-table nil + "Association between symbols and strings to set dtk voices. +The string can set any dtk parameter. ") + +(defsubst w3-valid-voice-p (voice) + (cadr (assq voice dtk-voice-table))) + +(defsubst w3-voice-for-element () + (let ((temporary-voice (w3-get-default-style-info 'voice-spec))) + (and temporary-voice (w3-valid-voice-p temporary-voice) + (cons tag temporary-voice)))) + +(defsubst w3-face-for-element () + (let* ((font-spec (w3-get-default-style-info 'font-spec)) + (foreground (w3-get-default-style-info 'color)) + (background (w3-get-default-style-info 'background)) + ;;(pixmap (w3-get-default-style-info 'pixmap)) + (descr (list font-spec foreground background)) + (face (cdr-safe (assoc descr w3-face-cache)))) + (if (or face (not (or foreground background font-spec))) + nil ; Do nothing, we got it already + (setq face (intern (format "%s" descr))) + (cond + ((not (fboundp 'make-face)) nil) ; Do nothing + ((and (fboundp 'face-property) ; XEmacs 19.14 + (not (get 'face-property 'sysdep-defined-this))) + (setq face (make-face face + "An Emacs-W3 face... don't edit by hand." t))) + (t (make-face face))) + + (and font-spec (set-face-font face font-spec)) + (and foreground (set-face-foreground face foreground)) + (and background (set-face-background face background)) + ;(set-face-background-pixmap face pixmap) + (setq w3-face-cache (cons (cons descr face) w3-face-cache))) + (cons tag face))) + +(defun w3-handle-single-tag (tag &optional args) + (save-excursion + (and w3-draw-buffer (set-buffer w3-draw-buffer)) + (let ((opos (point)) + (id (and (listp args) + (or (cdr-safe (assq 'name args)) + (cdr-safe (assq 'id args)))))) + ;; This allows _ANY_ tag, whether it is known or not, to be + ;; the target of a # reference in a URL + (if id + (progn + (setq w3-id-positions (cons + (cons (intern id) + (set-marker (make-marker) + (point-max))) + w3-id-positions)))) + (goto-char (point-max)) + (if (and (w3-get-state :next-break) + (not (memq tag + '(p h1 h2 h3 h4 h5 h6 ol ul dl menu dir pre)))) + (w3-handle-p)) + (w3-put-state :next-break nil) + (setq w3-current-formatter (get tag 'w3-formatter)) + (cond + ((eq 'w3-handle-text w3-current-formatter) + (w3-handle-text args)) + (t + (let ((data-before nil) + (data-after nil)) + (if (and (not (eq tag 'text)) w3-current-stylesheet) + (progn + (setq data-before (w3-get-default-style-info + 'insert.before)) + (let ((tag (cdr-safe (assq tag w3-end-tags)))) + (setq data-after (and tag + (w3-get-default-style-info + 'insert.after)))))) + (if data-before (w3-handle-single-tag 'text data-before)) + (setq w3-current-formatter (get tag 'w3-formatter)) + (cond + ((eq w3-current-formatter 'ack) nil) + ((null w3-current-formatter) (w3-handle-unknown-tag tag args)) + (t (funcall w3-current-formatter args))) + (if data-after (w3-handle-single-tag 'text data-after))))) + (if (not (eq tag 'text)) + (setq w3-last-tag tag)) + (goto-char opos)))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Set up basic fonts/stuff +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun w3-init-state () + ;; Reset the state of an HTML drawing buffer + (setq w3-state-vector (copy-sequence w3-state-vector)) + (setq w3-current-stylesheet (copy-tree w3-user-stylesheet)) + (let* ((tag 'html) + (args nil) + (face (cdr (w3-face-for-element)))) + (and face + (if (not (fboundp 'valid-specifier-locale-p)) + nil + (w3-my-safe-copy-face face 'default (current-buffer))))) + (setq w3-form-labels nil) + (make-local-variable 'w3-image-widgets-waiting) + (make-local-variable 'w3-active-voices) + (make-local-variable 'inhibit-read-only) + (setq w3-image-widgets-waiting nil + inhibit-read-only t) + (if (not (get 'w3-state 'init)) (w3-draw-setup)) + (fillarray w3-state-vector 0) + (w3-put-state :bogus nil) ; Make all fake ones return nil + (w3-put-state :text-mangler nil) ; Any text mangling routine + (w3-put-state :next-break nil) ; Next item needs a paragraph break + (w3-put-state :background nil) ; Netscapism - gag + (w3-put-state :table nil) ; Table args + (w3-put-state :figdata nil) ; Data for <fig> tag + (w3-put-state :figalt nil) ; Alt data for <fig> tag + (w3-put-state :pre-start nil) ; Where current <pre> seg starts + (w3-put-state :zone nil) ; Zone of current href? + (w3-put-state :center nil) ; netscape tag + (w3-put-state :select nil) ; Data for current select field + (w3-put-state :options nil) ; Options in current select field + (w3-put-state :nofill nil) ; non-nil if in pre or xmp + (w3-put-state :nowrap nil) ; non-nil if in <p nowrap> + (w3-put-state :href nil) ; Current link destination + (w3-put-state :name nil) ; Current link ID tag + (w3-put-state :image nil) ; Current image destination + (w3-put-state :mpeg nil) ; Current mpeg destination + (w3-put-state :form nil) ; Current form information + (w3-put-state :optarg nil) ; Option arguments + (w3-put-state :w3-graphic nil) ; Image stuff for non-xemacs + (w3-put-state :lists '()) ; Types of list currently in. + (w3-put-state :align nil) ; Current alignment of paragraphs + (w3-put-state :title nil) ; Whether we can have a title or not + (w3-put-state :seen-this-url nil) ; whether we have seen this url or not + (w3-put-state :needspace 'never) ; Spacing info + (setq w3-active-faces nil) ; Face attributes to use + (setq w3-active-voices nil) ; voice attributes to use + ) + +(defun w3-draw-setup () + (put 'w3-state 'init t) + (w3-init-state)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Mapping HTML tags to functions +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(put 'lit 'w3-formatter 'w3-handle-pre) +(put '/lit 'w3-formatter 'w3-handle-/pre) +(put 'li 'w3-formatter 'w3-handle-list-item) +(put 'ul 'w3-formatter 'w3-handle-list-opening) +(put 'ol 'w3-formatter 'w3-handle-list-opening) +(put 'dl 'w3-formatter 'w3-handle-list-opening) +(put '/dl 'w3-formatter 'w3-handle-list-ending) +(put '/ul 'w3-formatter 'w3-handle-list-ending) +(put '/ol 'w3-formatter 'w3-handle-list-ending) +(put 'menu 'w3-formatter 'w3-handle-list-opening) +(put '/menu 'w3-formatter 'w3-handle-list-ending) +(put 'dir 'w3-formatter 'w3-handle-list-opening) +(put '/dir 'w3-formatter 'w3-handle-list-ending) +(put 'dt 'w3-formatter 'w3-handle-table-term) +(put 'dd 'w3-formatter 'w3-handle-table-definition) +(put 'a 'w3-formatter 'w3-handle-hyperlink) +(put '/a 'w3-formatter 'w3-handle-hyperlink-end) +(put 'h1 'w3-formatter 'w3-handle-header) +(put 'h2 'w3-formatter 'w3-handle-header) +(put 'h3 'w3-formatter 'w3-handle-header) +(put 'h4 'w3-formatter 'w3-handle-header) +(put 'h5 'w3-formatter 'w3-handle-header) +(put 'h6 'w3-formatter 'w3-handle-header) +(put '/h1 'w3-formatter 'w3-handle-header-end) +(put '/h2 'w3-formatter 'w3-handle-header-end) +(put '/h3 'w3-formatter 'w3-handle-header-end) +(put '/h4 'w3-formatter 'w3-handle-header-end) +(put '/h5 'w3-formatter 'w3-handle-header-end) +(put '/h6 'w3-formatter 'w3-handle-header-end) +(put 'img 'w3-formatter 'w3-handle-image) +(put 'kill_sgml 'w3-formatter 'w3-handle-kill-sgml) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; The main drawing routines +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun w3-handle-unknown-tag (tag args) + ;; A generic formatter for an unkown HTML tag. This will only be + ;; called if a formatter was not found in TAGs property list. + ;; If a function named `w3-handle-TAG' is defined, then it will be + ;; stored in TAGs property list, so it will be found next time + ;; the tag is run across. + + (let ((handler (intern-soft (concat "w3-handle-" (symbol-name tag)))) + (end-tag-p (= (string-to-char (symbol-name tag)) ?/))) + + ;; This stores the info in w3-end-tags for future use by the display + ;; engine. + (if end-tag-p + (setq w3-end-tags (cons (cons tag + (intern (substring (symbol-name tag) + 1))) + w3-end-tags))) + + ;; For proper use of stylesheets, if no tag is found, then we should + ;; at least call w3-handle-emphasis + (cond + ((and handler (fboundp handler)) + (put tag 'w3-formatter handler) + (funcall handler args)) + (end-tag-p + (put tag 'w3-formatter 'w3-handle-emphasis-end)) + (t + (put tag 'w3-formatter 'w3-handle-emphasis))))) + +(defun w3-handle-text (&optional args) + ;; This is the main workhorse of the display engine. + ;; It will figure out how a chunk of text should be displayed and + ;; put all the necessary extents/overlays/regions around it." + (or args (error "Impossible")) + (if (string= args "") + (w3-put-state :needspace nil) + (let ((st (point)) + (mangler (w3-get-state :text-mangler)) + (sym nil)) + (insert args) + ;;(goto-char st) + (cond ((w3-get-state :nofill) + (goto-char st) + (if (not (search-forward "\n" nil t)) + (subst-char-in-region st (point-max) ?\r ?\n) + (subst-char-in-region st (point-max) ?\r ? )) + (goto-char (point-max))) + (t + (goto-char st) + (while (re-search-forward + " [ \t\n\r]+\\|[\t\n\r][ \t\n\r]*" + nil 'move) + (replace-match " ")) + (goto-char st) + (if (and (= ? (following-char)) + (or (bolp) + (eq 'never (w3-get-state :needspace)))) + (delete-char 1)) + (goto-char (point-max)))) + (and mangler w3-delimit-emphasis + (fboundp mangler) (funcall mangler st (point))) + (let ((faces nil) + (todo w3-active-faces) + (voices w3-active-voices) + (val nil) + (cur nil)) + (while todo + (setq cur (car todo) + todo (cdr todo)) + (cond + ((symbolp cur) + nil) + ((listp (cdr-safe cur)) + (let ((x (cdr cur))) + (while x + (if (not (memq (car x) faces)) + (setq faces (cons (car x) faces))) + (setq x (cdr x))))) + ((and (consp cur) (not (memq (cdr cur) faces))) + (setq faces (cons (cdr cur) faces))) + (t nil))) + (add-text-properties st (point) (list 'face faces)) + (if (car voices) + (add-text-properties st (point) (list 'personality (car voices)))) + ) + (if (not (memq (char-after (1- (point))) '(? ?.))) + (w3-put-state :needspace t)) + ))) + +(defun w3-handle-plaintext (&optional args) + (let ((x (w3-get-state :nofill))) + (w3-put-state :nofill t) + (and args (cdr-safe (assq 'data args)) + (w3-handle-text (cdr-safe (assq 'data args)))) + (setq w3-last-fill-pos (point)))) + +(defun w3-handle-/plaintext (&optional args) + (w3-put-state :nofill nil)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Paragraph breaks, and other things that can cause linebreaks and +;;; alignment changes. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun w3-handle-header (&optional args) + ;; Handle the creation of a header (of any level). Causes a full + ;; paragraph break. + (w3-handle-emphasis args) + (let ((name (or (cdr-safe (assq 'name args)) + (cdr-safe (assq 'id args)))) + (align (cdr-safe (assq 'align args))) + (mangler (nth 2 (cdr-safe (assq tag w3-header-chars-assoc))))) + (w3-handle-p) + (if align + (setq align (intern (downcase align))) + (setq align (w3-get-default-style-info 'align))) + (let ((tag 'p)) + (w3-pop-alignment)) + (w3-push-alignment align) + (w3-put-state :text-mangler mangler) + (if name (w3-put-state :name name)))) + +(defun w3-handle-header-end (&optional args) + ;; Handle the closing of a header (of any level). Causes a full + ;; paragraph break. + (w3-handle-emphasis-end) + (let ((mangler (w3-get-state :text-mangler))) + (and mangler (funcall mangler nil nil t))) + (w3-put-state :text-mangler nil) + (goto-char (point-max)) + (w3-handle-p) + (let* ((info (car-safe (w3-get-state :lists))) + (type (and info (car-safe info)))) + (if (and type fill-prefix) + (insert fill-prefix (cond + ((memq type '(ol dl)) " ") + (t " "))))) + (let ((tag (cdr-safe (assoc tag w3-end-tags)))) + (w3-pop-alignment))) + +(defun w3-handle-pre (&optional args) + ;; Marks the start of a preformatted section of text. No paragraph + ;; filling should be done from this point until a matching /pre has + ;; been encountered. + (w3-handle-p) + (w3-put-state :nofill t) + (w3-put-state :needspace t) + (w3-put-state :pre-start (set-marker (make-marker) (point))) + ) + +(defun w3-handle-xmp (&optional args) + ;; Marks the start of a preformatted section of text. No paragraph + ;; filling should be done from this point until a matching /pre has + ;; been encountered. + (w3-handle-p) + (w3-put-state :nofill t) + (w3-put-state :needspace t) + (w3-put-state :pre-start (set-marker (make-marker) (point))) + (if (and args (cdr-safe (assq 'data args))) + (progn + (w3-handle-text (cdr-safe (assq 'data args))) + (w3-handle-/xmp)))) + +(defun w3-handle-/pre (&optional args) + (if (not (w3-get-state :nofill)) + (w3-handle-p) + (w3-put-state :nofill nil) + (let* ((info (car-safe (w3-get-state :lists))) + (type (and info (car-safe info))) + (st (w3-get-state :pre-start))) + (if (not (bolp)) (insert "\n")) + (if (and type fill-prefix st) + (progn + (save-excursion + (goto-char st) + (while (re-search-forward "^" nil t) + (insert fill-prefix (cond + ((memq type '(ol dl)) " ") + (t " "))))) + (setq w3-last-fill-pos (point)) + (insert fill-prefix (cond + ((memq type '(ol dl)) " ") + (t " ")))) + (setq w3-last-fill-pos (point)))) + (let ((tag 'p)) + (w3-handle-p)) + (setq w3-active-faces nil) + (w3-put-state :pre-start nil))) + +(fset 'w3-handle-/xmp 'w3-handle-/pre) + +(defun w3-handle-blockquote (&optional args) + ;; Start a section of quoted text. This is done by causing the text + ;; to be indented from the right and left margins. Nested + ;; blockquotes will cause further indentation. + (let ((align (or (w3-get-default-style-info 'align) 'indent))) + (w3-handle-p) + (w3-push-alignment align)) + (w3-put-state :fillcol fill-column) + (setq fill-column (max (- (or fill-column + (1- (or w3-strict-width (window-width)))) 8) + 10))) + +(defun w3-handle-/blockquote (&optional args) + (w3-handle-paragraph) + (let ((tag (cdr-safe (assoc tag w3-end-tags)))) + (w3-pop-alignment)) + (setq fill-column (or (w3-get-state :fillcol) (1- (or w3-strict-width + (window-width))))) + (w3-put-state :fillcol nil)) + +(defun w3-handle-align (&optional args) + ;; Cause a single line break (like <BR>) and replace the current + ;; alignment. + (let ((align (intern (or (cdr-safe (assq 'role args)) + (cdr-safe (assq 'align args)) + (cdr-safe (assq 'style args)))))) + (w3-handle-paragraph) + (w3-push-alignment align))) + +(defun w3-handle-/align (&optional args) + (w3-handle-paragraph) + (w3-pop-alignment)) + +(defun w3-handle-hr (&optional args) + ;; Cause a line break and insert a horizontal rule across the page. + (w3-handle-paragraph) + (let* ((perc (or (cdr-safe (assq 'width args)) + (w3-get-default-style-info 'width) + "100%")) + (old-align (w3-current-alignment)) + (talign (or (cdr-safe (assq 'textalign args)) + (cdr-safe (assq 'text-align args)) + (w3-get-default-style-info 'textalign) + (w3-get-default-style-info 'text-align) + (and old-align (symbol-name old-align)) + "center")) + (text (cdr-safe (assq 'label args))) + (align (or (cdr-safe (assq 'align args)) + (w3-get-default-style-info 'align) + old-align + 'center)) + (rule nil) + (width nil)) + (if (stringp talign) + (setq talign (intern (downcase talign)))) + (if (stringp align) + (setq align (intern (downcase align)))) + (w3-push-alignment align) + + (setq perc (min (string-to-int perc) 100) + width (/ (* (- (or w3-strict-width + (window-width)) + w3-right-border) perc) 100)) + (if text + (cond + ((>= (length text) width) + (setq rule (concat "-" text "-"))) + ((eq talign 'right) + (setq rule (concat (make-string (- width 1 (length text)) + w3-horizontal-rule-char) + text "-"))) + ((eq talign 'center) + (let ((half (make-string (/ (- width (length text)) 2) + w3-horizontal-rule-char))) + (setq rule (concat half text half)))) + ((eq talign 'left) + (setq rule (concat "-" text (make-string (- width 1 + (length text)) + w3-horizontal-rule-char))))) + (setq rule (make-string width w3-horizontal-rule-char))) + (w3-handle-text rule) + (condition-case () + (w3-handle-paragraph) + (error nil)) + (w3-pop-alignment) + (setq w3-last-fill-pos (point)) + (let* ((info (car-safe (w3-get-state :lists))) + (type (and info (car-safe info))) + (cur (w3-current-alignment))) + (cond + ;;((eq cur 'indent) + ;;(insert (make-string w3-indent-level ? ))) + ((and type fill-prefix (eq w3-last-tag 'dt)) + (insert fill-prefix)) + ((and type fill-prefix) + (insert fill-prefix (if (eq type 'ol) " " " "))) + (t nil))))) + +(defun w3-handle-/p (&optional args) + ;; Marks the end of a paragraph. Only causes a paragraph break if + ;; it is not followed by another paragraph or similar markup + ;; (headers, list openings, etc) that will already cause a new + ;; paragraph to be started. + (w3-handle-emphasis-end) + (let ((tag (cdr-safe (assoc tag w3-end-tags)))) + (w3-handle-p) + (w3-pop-alignment))) + +(defun w3-handle-p (&optional args) + (if (or (not (memq w3-last-tag '(li dt dd))) + (memq tag '(ol ul dl menu dir))) + (let ((name (or (cdr-safe (assq 'name args)) + (cdr-safe (assq 'id args)))) + (align (cdr-safe (assoc 'align args)))) + (w3-handle-emphasis-end) + (w3-handle-emphasis args) + (w3-handle-paragraph) + (w3-put-state :nowrap (assq 'nowrap args)) + (setq align (if align + (intern (downcase align)) + (w3-get-default-style-info 'align))) + (and (eq tag 'p) (progn + (w3-pop-alignment) + (w3-push-alignment align))) + (if (not (bobp)) + (progn + (insert (cond + ((and (eolp) (bolp)) "\n") + ((eolp) "\n\n") + (t "\n"))) + (setq w3-last-fill-pos (point)) + (cond + ((null fill-prefix)) + ((string= fill-prefix "")) + ((eq (car (car (w3-get-state :lists))) 'ol) + (insert fill-prefix " ")) + (t (insert fill-prefix " "))))) + (if name (w3-put-state :name name))))) + +(defun w3-handle-br (&optional args) + ;; Cause a single line break. + ;; The alignment will only effect the chunk of text (generally to + ;; the last <br> or <p> tag) immediately before the <br>. After + ;; that, the alignment will revert to the containers alignment. + (w3-handle-paragraph) + (let* ((info (car-safe (w3-get-state :lists))) + (type (and info (car-safe info))) + (cur (w3-current-alignment))) + (cond + ;;((eq cur 'indent) + ;;(insert (make-string w3-indent-level ? ))) + ((and type fill-prefix (eq w3-last-tag 'dt)) + (insert fill-prefix)) + ((and type fill-prefix) + (insert fill-prefix (if (eq type 'ol) " " " "))) + (t nil)))) + +(defun w3-handle-paragraph (&optional args) + (if (not (bobp)) + (let ((align (w3-current-alignment)) + (fill-prefix fill-prefix)) + (cond + ((eq align 'indent) + (w3-set-fill-prefix-length + (+ (length fill-prefix);; works even if fill-prefix is nil + w3-indent-level))) + ((null fill-prefix) + (setq fill-prefix "")) + ((string= fill-prefix "")) + ((eq (car (car (w3-get-state :lists))) 'ol) + (w3-set-fill-prefix-length (+ 4 (length fill-prefix)))) + (t + (w3-set-fill-prefix-length (+ 2 (length fill-prefix))))) + (if (eq align 'indent) + (progn + (goto-char w3-last-fill-pos) + (insert fill-prefix) + (goto-char (point-max)))) + (if (and (> (current-column) fill-column) + (not (w3-get-state :nowrap)) + (not (w3-get-state :nofill))) + (fill-region-as-paragraph w3-last-fill-pos (point) + (eq align 'justify))) + (if (not w3-last-fill-pos) + (setq w3-last-fill-pos (point-min))) + (goto-char (point-max)) + (skip-chars-backward " \t\n") + (delete-region (point) (point-max)) + (if (< w3-last-fill-pos (point)) + (cond + ((or (eq align 'center) (w3-get-state :center)) + (center-region w3-last-fill-pos (point))) + ((eq align 'right) + (let ((x (point))) + (catch 'fill-exit + (save-excursion + (goto-char w3-last-fill-pos) + (while (re-search-forward "$" x t) + (if (/= (current-column) fill-column) + (let ((buff (- fill-column (current-column)))) + (beginning-of-line) + (setq x (+ x buff)) + (if (> buff 0) + (insert (make-string buff ? ))) + (end-of-line)) + (end-of-line)) + (if (eobp) (throw 'fill-exit t)) + (condition-case () + (forward-char 1) + (error (throw 'fill-exit t)))))))))) + (insert "\n") + (setq w3-last-fill-pos (point)) + (w3-put-state :needspace 'never)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; List handling code +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun w3-handle-list-ending (&optional args) + ;; Handles all the list terminators (/ol /ul /dl). + ;; This just fills the last paragrpah, then reduces the depth in + ;; `w3-state' and truncates `fill-prefix'" + (w3-handle-paragraph) + (w3-put-state :depth (max 0 (1- (w3-get-state :depth)))) + (w3-put-state :next-break t) + (w3-set-fill-prefix-length (* (w3-get-state :depth) w3-indent-level)) + (w3-put-state :lists (cdr (w3-get-state :lists))) + (if (/= 0 (length fill-prefix)) + (insert fill-prefix " "))) + +(defun w3-handle-list-opening (&optional args) + ;; Handles all the list openers (ol ul dl). + ;; This just fills the last paragraph, then increases the depth in + ;; `w3-state' and adds to `fill-prefix' + (w3-handle-p) + (let ((style (and (not (assq 'style args)) + (w3-get-default-style-info 'style)))) + (if style + (setq args (cons (cons 'style style) args)))) + ;; Default VALUE attribute for OL is 1. + (if (eq tag 'ol) + (or (assq 'value args) + (setq args (cons (cons 'value 1) args)))) + (w3-put-state :depth (1+ (w3-get-state :depth))) + (w3-set-fill-prefix-length (* (w3-get-state :depth) w3-indent-level)) + (insert "\n\n" fill-prefix " ") + (w3-put-state :lists (cons (cons tag (copy-alist args)) + (w3-get-state :lists)))) + +(defun w3-handle-table-definition (&optional args) + (w3-handle-paragraph) + (insert fill-prefix " ")) + +(defun w3-handle-table-term (&optional args) + (w3-handle-paragraph) + (insert "\n" fill-prefix)) + +(defun w3-handle-list-item (&optional args) + (w3-handle-paragraph) + (let* ((info (car (w3-get-state :lists))) + (type (car info)) + (endr (or (nth (1- (or (w3-get-state :depth) 1)) + (cdr (or (assoc type w3-list-chars-assoc) + (car w3-list-chars-assoc)))) + "*"))) + (setq info (cdr info)) + (cond + ((assq 'plain info) + ;; We still need to indent from the left margin for lists without + ;; bullets. This is especially important with nested lists. + ;; Question: Do we want this to be equivalent to replacing the + ;; bullet by a space (" ") or by indenting so that the text starts + ;; where the bullet would have been? I've chosen the latter after + ;; looking at both kinds of output. + (insert fill-prefix)) + ((eq type 'ol) + (let ((next (or (assq 'seqnum info) (assq 'value info))) + (type (cdr-safe (assq 'style info))) + (uppr (assq 'upper info)) + (tokn nil)) + (if (stringp (cdr next)) (setcdr next (string-to-int (cdr next)))) + (cond + ((or (assq 'roman info) + (member type '("i" "I"))) + (setq tokn (concat + (w3-pad-string (w3-decimal-to-roman (cdr next)) 3 ? + 'left) + endr))) + ((or (assq 'arabic info) + (member type '("a" "A"))) + (setq tokn (concat (w3-pad-string + (w3-decimal-to-alpha (cdr next)) 3 ? 'left) + endr))) + (t + (setq tokn (concat (w3-pad-string (int-to-string (cdr next)) + 2 ? 'left) + endr)))) + (if (assq 'uppercase info) + (setq tokn (upcase tokn))) + (insert fill-prefix tokn " ") + (setcdr next (1+ (cdr next))) + (w3-put-state :needspace 'never))) + (t + (insert fill-prefix endr " "))))) + +(defun w3-pad-string (str len pad side) + ;; Pads a string STR to a certain length LEN, using fill character + ;; PAD by concatenating PAD to SIDE of the string. + (let ((strlen (length str))) + (cond + ((>= strlen len) str) + ((eq side 'right) (concat str (make-string (- len strlen) pad))) + ((eq side 'left) (concat (make-string (- len strlen) pad) str))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Routines to handle character-level formatting +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun w3-handle-q (&optional args) + (w3-handle-emphasis) + (w3-handle-text (or (w3-get-default-style-info 'startquote) "\""))) + +(defun w3-handle-/q (&optional args) + (let ((tag (cdr-safe (assoc tag w3-end-tags)))) + (w3-handle-text (or (w3-get-default-style-info 'endquote) "\""))) + (w3-handle-emphasis-end)) + +(defun w3-handle-emphasis (&optional args) + ;; Generic handler for character-based emphasis. Increments the state + ;; of TAG (which must be bound by the calling procedure). This + ;; checks all the various stylesheet mechanisms that may cause an + ;; alignment shift as well. + (let ((align (or (w3-get-default-style-info 'align) + (and (eq tag 'address) w3-right-justify-address 'right)))) + (if (and align (not (memq tag '(h1 h2 h3 h4 h5 h6)))) + (progn + (w3-handle-paragraph) + (w3-push-alignment align)))) + (let* ((spec (and w3-delimit-emphasis (assoc tag w3-style-tags-assoc))) + (class (cdr-safe (assq 'class args))) + (face (w3-face-for-element)) + (voice (w3-voice-for-element)) + (beg (and spec (car (cdr spec))))) + (if spec + (insert beg)) + (if voice + (setq w3-active-voices (cons voice w3-active-voices))) + (if face + (setq w3-active-faces (cons face w3-active-faces))))) + +(defun w3-handle-emphasis-end (&optional args) + ;; Generic handler for ending character-based emphasis. Decrements + ;; the state of TAG (which must be bound by the calling procedure). + ;; Stylesheet mechanisms may cause arbitrary alignment changes. + (let* ((tag (cdr-safe (assq tag w3-end-tags))) + (spec (and w3-delimit-emphasis (assq tag w3-style-tags-assoc))) + (end (and spec (cdr (cdr spec))))) + (if (assq tag w3-active-voices) + (setq w3-active-voices (cdr (memq (assq tag w3-active-voices) + w3-active-voices))) + (setq w3-active-voices (delq tag w3-active-voices))) + (if (assq tag w3-active-faces) + (setq w3-active-faces (cdr (memq (assq tag w3-active-faces) + w3-active-faces))) + (setq w3-active-faces (delq tag w3-active-faces))) + (if spec (insert end)) + (if (eq tag 'address) + (progn + (w3-handle-paragraph) + (w3-pop-alignment))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; HTML 3.0 compliance +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun w3-handle-math (&optional args) + (w3-handle-br) + (w3-handle-text "[START MATH - Not Implemented (Yet)]") + (w3-handle-br)) + +(defun w3-handle-/math (&optional args) + (w3-handle-br) + (w3-handle-text "[END MATH]") + (w3-handle-br)) + +(defun w3-handle-table (&optional args) + (w3-handle-br) + (w3-handle-text "[START TABLE - Not Implemented (Yet)]") + (w3-handle-br)) + +(defun w3-handle-/table (&optional args) + (w3-handle-br) + (w3-handle-text "[END TABLE]") + (w3-handle-br)) + +(defun w3-handle-div (&optional args) + (let ((align (cdr-safe (assq 'align args)))) + (w3-handle-emphasis args) + (w3-handle-paragraph) + (setq align (and align (intern (downcase align)))) + (w3-push-alignment align))) + +(defun w3-handle-/div (&optional args) + (w3-handle-emphasis-end) + (let ((tag (cdr-safe (assq tag w3-end-tags)))) + (w3-handle-paragraph) + (w3-pop-alignment))) + +(defun w3-handle-note (&optional args) + (w3-handle-emphasis) + (w3-handle-paragraph) + (let ((align (or (w3-get-default-style-info 'align) 'indent))) + (w3-push-alignment align)) + (w3-handle-text (concat (or (cdr-safe (assq 'role args)) "CAUTION") ":"))) + +(defun w3-handle-/note (&optional args) + (w3-handle-paragraph) + (w3-handle-emphasis-end) + (let ((tag (cdr-safe (assoc tag w3-end-tags)))) + (w3-pop-alignment))) + +(defun w3-handle-fig (&optional args) + (w3-put-state :figdata args) + (w3-put-state :figalt (set-marker (make-marker) (point))) + ) + +(defun w3-handle-caption (&optional args) + ) + +(defun w3-handle-/caption (&optional args) + ) + +(defun w3-handle-/fig (&optional args) + (let* ((data (w3-get-state :figdata)) + (src (cdr-safe (assq 'src data))) + (aln (cdr-safe (assq 'align data))) + (alt (if (w3-get-state :figalt) + (prog1 + (buffer-substring (w3-get-state :figalt) (point)) + (delete-region (w3-get-state :figalt) (point))))) + (ack nil)) + (setq w3-last-fill-pos (point)) + (if (not src) + (w3-warn 'html "Malformed <fig> tag.") + (setq ack (list (cons 'src src) + (cons 'alt alt) + (cons 'align aln))) + (w3-handle-pre nil) + (w3-handle-image ack) + (w3-handle-/pre nil)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Netscape Compatibility +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; For some reason netscape treats </br> like <br> - ugh. +(fset 'w3-handle-/br 'w3-handle-br) + +(defun w3-handle-font (&optional args) + (let* ((sizearg (cdr-safe (assq 'size args))) + (sizenum (cond + ((null sizearg) nil) + ((= ?+ (string-to-char sizearg)) + (min (+ 3 (string-to-int (substring sizearg 1))) 7)) + ((= ?- (string-to-char sizearg)) + (max (- 3 (string-to-int (substring sizearg 1))) 0)) + ((string= sizearg (int-to-string (string-to-int sizearg))) + (string-to-int sizearg)) + (t nil))) + (color (cdr-safe (assq 'color args))) + (normcolor (if color (w3-normalize-color color))) + (w3-current-stylesheet (` ((font + (internal + (font-size-index . (, sizenum)) + (foreground . (, normcolor)))))))) + (w3-generate-stylesheet-faces w3-current-stylesheet) + (w3-handle-emphasis args))) + +(defun w3-handle-/font (&optional args) + (w3-handle-emphasis-end)) + +(defun w3-handle-center (&optional args) + (w3-handle-paragraph) + (w3-push-alignment 'center)) + +(defun w3-handle-/center (&optional args) + (w3-handle-paragraph) + (let ((tag 'center)) + (w3-pop-alignment))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Bonus HTML Tags just for fun :) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun w3-handle-embed (&optional args) + (let* ((buf (url-generate-new-buffer-name " *embed*")) + (w3-draw-buffer (current-buffer)) + (url-working-buffer buf) + (data (cdr-safe (assq 'data args))) + (href (and (not data) + (url-expand-file-name + (or (cdr-safe (assq 'src args)) + (cdr-safe (assq 'href args))) + (cdr-safe (assoc (cdr-safe (assq 'base args)) + w3-base-alist))))) + (type (or (cdr-safe (assq 'type args)) "text/plain")) + (parse nil)) + (if (and href (not (string= type "video/mpeg"))) + ;; MPEG movies can be _HUGE_, delay loading them as + ;; long as possible + (save-excursion + (set-buffer (get-buffer-create buf)) + (setq url-be-asynchronous nil) + (url-retrieve href) + (setq data (buffer-string)) + (kill-buffer (current-buffer)))) + (cond + ((string= type "text/plain") + (insert data)) + ((string-match "^text/html" type) + (save-excursion + (set-buffer (get-buffer-create + (url-generate-new-buffer-name " *embed*"))) + (erase-buffer) + (insert data) + (setq parse (w3-preparse-buffer (current-buffer) t)) + (kill-buffer (current-buffer))) + (while parse + (w3-handle-single-tag (car (car parse)) (cdr (car parse))) + (setq parse (cdr parse)))) + ((string= type "video/mpeg") + (let ((width (cdr-safe (assq 'width args))) + (height (cdr-safe (assq 'height args)))) + (setq width (if width (string-to-int width)) + height (if height (string-to-int height))) + (w3-add-delayed-mpeg href (point) width height)))))) + +(defun w3-handle-blink (&optional args) + ;; Keep track of all the buffers with blinking in them, and do GC + ;; of this list whenever a new <blink> tag is encountered. The + ;; timer checks this list to see if any of the buffers are visible, + ;; and only blinks the face if there are any visible. This cuts + ;; down tremendously on the amount of X traffic, and frame !@#!age + ;; due to lots of face munging. + (w3-handle-emphasis args) + (let ((buffs w3-blinking-buffs) + (name1 (buffer-name)) + (name2 nil) + (add t)) + (setq w3-blinking-buffs nil) + ;; Get rid of old buffers + (while buffs + (setq name2 (buffer-name (car buffs))) + (if (null name2) + nil + (setq w3-blinking-buffs (cons (car buffs) w3-blinking-buffs)) + (if (string= name1 name2) + (setq add nil))) + (setq buffs (cdr buffs))) + (if add + (setq w3-blinking-buffs (cons (current-buffer) w3-blinking-buffs))))) + +(defun w3-handle-/blink (&optional args) + (w3-handle-emphasis-end args)) + +(defun w3-handle-peek (&optional args) + ;; Handle the peek tag. Valid attributes are: + ;; VARIABLE:: any valid lisp variable + ;; If VARIABLE is bound and non-nil, then the value of the variable is + ;; inserted at point. This can handle variables whos values are any + ;; arbitrary lisp type. + (let* ((var-name (cdr-safe (assq 'variable args))) + (var-sym (and var-name (intern var-name))) + (val (and var-sym (boundp var-sym) (symbol-value var-sym)))) + (cond + ((null val) nil) + ((stringp val) (w3-handle-text val)) + (t (w3-handle-text (format "%S" val)))))) + +(defun w3-rotate-region (st nd &optional rotation) + "Ceasar rotate a region between ST and ND using ROTATION as the +amount to rotate the text. Defaults to caesar (13)." + (setq rotation (or rotation 13)) + (save-excursion + (let (x) + (while (< st nd) + (setq x (char-after st)) + (cond + ((and (>= x ?a) (<= x ?z)) + (setq x (- x ?a) + x (char-to-string (+ (% (+ x rotation) 26) ?a)))) + ((and (>= x ?A) (<= x ?Z)) + (setq x (- x ?A) + x (char-to-string (+ (% (+ x rotation) 26) ?A)))) + (t (setq x nil))) + (if x (progn (goto-char st) (delete-char 1) (insert x))) + (setq st (1+ st)))))) + +(defun w3-handle-kill-sgml (&optional args) + (w3-handle-text "SGML is the spawn of evil! It must be stopped!")) + +(defun w3-handle-secret (&optional args) + (if (fboundp 'valid-specifier-locale-p) + (let ((tag 'rot13)) + (w3-handle-emphasis)) + (w3-put-state :secret (set-marker (make-marker) (point))))) + +(defun w3-handle-/secret (&optional args) + "Close a secret region of text." + (if (fboundp 'valid-specifier-locale-p) + (let ((tag '/rot13)) + (w3-handle-emphasis-end)) + (if (integer-or-marker-p (w3-get-state :secret)) + (progn + (w3-rotate-region (w3-get-state :secret) (point)) + (w3-put-state :secret nil))))) + +(defun w3-handle-hype (&optional args) + (if (and (or (featurep 'nas-sound) (featurep 'native-sound)) + (assoc 'hype sound-alist)) + (play-sound 'hype 100) + (w3-handle-text "Hey, has Marca A. told you how cool he is?"))) + +(defun w3-handle-yogsothoth (&optional args) + (w3-handle-image (list (cons 'src "href-to-yogsothoth-pic") + (cons 'alt "YOGSOTHOTH LIVES!!!")))) + +(defun w3-handle-roach (&optional args) + (w3-handle-text "Man, I am so wasted...")) + +(defun w3-handle-/roach (&optional args) + (w3-handle-text (concat "So, you wanna get some " + (or (cdr-safe (assq 'munchy args)) + "nachos") "? "))) + +(defun w3-invert-face (face) + (let ((buffs w3-blinking-buffs) + (blink nil) + (buff nil)) + (if buffs + (while buffs + (setq buff (car buffs)) + (cond + ((bufferp buff) + (if (buffer-name buff) + (setq buff (car buffs)) + (setq buff nil))) + ((stringp buff) + (setq buff (get-buffer buff))) + (t + (setq buff nil))) + (setq buffs (cdr buffs) + buff (and buff (get-buffer-window buff 'visible)) + buff (and buff (window-live-p buff))) + (if buff (setq buffs nil + blink t)))) + (if blink (invert-face face)))) + +(autoload 'sentence-ify "flame") +(autoload 'string-ify "flame") +(autoload '*flame "flame") +(if (not (fboundp 'flatten)) (autoload 'flatten "flame")) + +(defvar w3-cookie-cache nil) + +(defun w3-handle-cookie (&optional args) + (if (not (fboundp 'cookie)) + (w3-handle-text "Sorry, no cookies today.") + (let* ((url-working-buffer (url-generate-new-buffer-name " *cookie*")) + (href (url-expand-file-name + (or (cdr-safe (assq 'src args)) + (cdr-safe (assq 'href args))) + (cdr-safe (assoc (cdr-safe (assq 'base args)) + w3-base-alist)))) + (fname (or (cdr-safe (assoc href w3-cookie-cache)) + (url-generate-unique-filename "%s.cki"))) + (st (or (cdr-safe (assq 'start args)) "Loading cookies...")) + (nd (or (cdr-safe (assq 'end args)) + "Loading cookies... done."))) + (if (not (assoc href w3-cookie-cache)) + (save-excursion + (url-clear-tmp-buffer) + (setq url-be-asynchronous nil) + (url-retrieve href) + (url-uncompress) + (write-region (point-min) (point-max) fname 5) + (setq w3-cookie-cache (cons (cons href fname) w3-cookie-cache)))) + (w3-handle-text (cookie fname st nd))))) + +(defun w3-handle-flame (&optional args) + (condition-case () + (w3-handle-text + (concat + (sentence-ify + (string-ify + (append-suffixes-hack (flatten (*flame))))))) + (error nil))) + +(defun w3-handle-pinhead (&optional args) + (if (fboundp 'yow) + (w3-handle-text (yow)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Client-side Imagemaps +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun w3-handle-map (&optional args) + (w3-put-state :map (cons (or (cdr-safe (assq 'name args)) + (cdr-safe (assq 'id args)) + "unnamed") nil))) + +(defun w3-handle-/map (&optional args) + (and (w3-get-state :map) + (setq w3-imagemaps (cons (w3-get-state :map) w3-imagemaps))) + (w3-put-state :map nil)) + +(defun w3-decode-area-coords (str) + (let (retval) + (while (string-match "\\([ \t0-9]+\\),\\([ \t0-9]+\\)" str) + (setq retval (cons (vector (string-to-int (match-string 1 str)) + (string-to-int (match-string 2 str))) retval) + str (substring str (match-end 0) nil))) + (if (string-match "\\([0-9]+\\)" str) + (setq retval (cons (vector (+ (aref (car retval) 0) + (string-to-int (match-string 1 str))) + (aref (car retval) 1)) retval))) + (nreverse retval))) + +(defun w3-handle-area (&optional args) + (let ((type (downcase (or (cdr-safe (assq 'shape args)) "rect"))) + (coords (w3-decode-area-coords (or (cdr-safe (assq 'coords args)) ""))) + (alt (cdr-safe (assq 'alt args))) + (href (if (assq 'nohref args) + t + (url-expand-file-name + (or (cdr-safe (assq 'src args)) + (cdr-safe (assq 'href args))) + (cdr-safe (assoc (cdr-safe (assq 'base args)) + w3-base-alist))))) + (map (w3-get-state :map))) + ;; data structure in storage is a vector + ;; if (href == t) then no action should be taken + ;; [ type coordinates href (hopefully)descriptive-text] + (setcdr map (cons (vector type coords href alt) (cdr map))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Tags that don't really get drawn, etc. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun w3-handle-body (&optional args) + (if (not w3-user-colors-take-precedence) + (let* ((vlink (cdr-safe (assq 'vlink args))) + (alink (cdr-safe (assq 'alink args))) + (link (cdr-safe (assq 'link args))) + (text (cdr-safe (assq 'text args))) + (backg (cdr-safe (assq 'background args))) + (rgb (or (cdr-safe (assq 'bgcolor args)) + (cdr-safe (assq 'rgb args)))) + (temp-face nil) + (sheet "")) + (setq backg (url-expand-file-name + backg + (cdr-safe (assoc (cdr-safe (assq 'base args)) + w3-base-alist)))) + (if (or text rgb backg) + (progn + (setq sheet "html {") + (if text (setq sheet (format "%scolor: %s; " sheet + (w3-normalize-color text)))) + (if rgb (setq sheet (format "%sbackground: %s; " + sheet (w3-normalize-color rgb)))) + (if backg (setq sheet (format "%sbackdrop: %s; " + sheet backg))) + (setq sheet (concat sheet " }\n")))) + (if link + (setq sheet (format "%sa.link { color: %s }\n" sheet + (w3-normalize-color link)))) + (if vlink + (setq sheet (format "%sa.visited { color: %s }\n" sheet + (w3-normalize-color vlink)))) + (if alink + (setq sheet (format "%sa.active { color: %s }\n" sheet + (w3-normalize-color alink)))) + (if (/= (length sheet) 0) + (w3-handle-style (list (cons 'data sheet) + (cons 'notation "css"))))))) + +(defun w3-handle-cryptopts (&optional args) + (put 'text 'w3-formatter 'ack)) + +(defun w3-handle-/cryptopts (&optional args) + (put 'text 'w3-formatter nil)) + +(defun w3-handle-certs (&optional args) + (put 'text 'w3-formatter 'ack)) + +(defun w3-handle-/certs (&optional args) + (put 'text 'w3-formatter nil)) + +(defun w3-handle-base (&optional args) + (setq w3-base-alist (cons + (cons (or (cdr-safe (assq 'name args)) + (cdr-safe (assq 'id args))) + (or (cdr-safe (assq 'href args)) + (cdr-safe (assq 'src args)) + (url-view-url t))) + w3-base-alist))) + +(defun w3-handle-isindex (&optional args) + (let ((prompt (or (cdr-safe (assq 'prompt args)) + "Search on (+ separates keywords): ")) + action) + (setq action (url-expand-file-name + (or (cdr-safe (assq 'src args)) + (cdr-safe (assq 'href args)) + (url-view-url t)) + (cdr-safe (assoc (cdr-safe (assq 'base args)) + w3-base-alist)))) + (if (and prompt (string-match "[^: \t-]+$" prompt)) + (setq prompt (concat prompt ": "))) + (if w3-use-forms-index + (progn + (w3-handle-hr) + (w3-handle-form (list (cons 'action action) + (cons 'enctype "application/x-w3-isindex") + (cons 'method "get"))) + (w3-handle-text (concat prompt " ")) + (w3-handle-input (list (cons 'type "text") + (cons 'name "isindex"))))) + (setq w3-current-isindex (cons action prompt)))) + +(defun w3-handle-meta (&optional args) + (let* ((equiv (cdr-safe (assq 'http-equiv args))) + (value (cdr-safe (assq 'content args))) + (node (and equiv (assoc (setq equiv (downcase equiv)) + url-current-mime-headers)))) + (if equiv + (setq url-current-mime-headers (cons (cons equiv value) + url-current-mime-headers))) + ;; Special-case the Set-Cookie header + (if (and equiv (string= (downcase equiv) "set-cookie")) + (url-cookie-handle-set-cookie value)) + ;; Special-case the refresh header + (if (and equiv (string= (downcase equiv) "refresh")) + (url-handle-refresh-header value)))) + +(defun w3-handle-link (&optional args) + (let* ((dest (cdr-safe (assq 'href args))) + (type (if (assq 'rel args) "Parent of" "Child of")) + (desc (or (cdr-safe (assq 'rel args)) + (cdr-safe (assq 'rev args)))) + (node-1 (assoc type w3-current-links)) + (node-2 (and node-1 desc (assoc desc (cdr node-1)))) + (base (cdr-safe (assq 'base args)))) + (if dest + (progn + (setq dest (url-expand-file-name + dest + (cdr-safe (assoc base w3-base-alist)))) + (cond + (node-2 ; Add to old value + (setcdr node-2 (cons dest (cdr node-2)))) + (node-1 ; first rel/rev + (setcdr node-1 (cons (cons desc (list dest)) (cdr node-1)))) + (t (setq w3-current-links + (cons (cons type (list (cons desc (list dest)))) + w3-current-links)))) + (if (and dest desc (member (downcase desc) + '("style" "stylesheet"))) + (w3-handle-style (list (cons 'src dest)))))))) + +(defun w3-maybe-start-image-download (widget) + (let* ((src (widget-get widget 'src)) + (cached-glyph (w3-image-cached-p src))) + (if (and cached-glyph (w3-glyphp cached-glyph)) + (setq w3-image-widgets-waiting (cons widget + w3-image-widgets-waiting)) + (cond + ((or w3-delay-image-loads (not (fboundp 'valid-specifier-domain-p))) + nil) ; Do nothing, cannot do images + ((not (w3-image-loadable-p src nil)) ; Hey, we can't load it! + (w3-warn 'images (format "Skipping image %s" (url-basepath src t)))) + (t ; Grab the images + (let ( + (url-request-method "GET") + (old-asynch url-be-asynchronous) + (url-request-data nil) + (url-request-extra-headers nil) + (url-source t) + (url-mime-accept-string (substring + (mapconcat + (function + (lambda (x) + (if x + (concat (car x) ",") + ""))) + w3-allowed-image-types "") + 0 -1)) + (url-working-buffer (generate-new-buffer-name " *W3GRAPH*"))) + (setq-default url-be-asynchronous t) + (setq w3-graphics-list (cons (cons src (make-glyph)) + w3-graphics-list)) + (save-excursion + (set-buffer (get-buffer-create url-working-buffer)) + (setq url-current-callback-data (list widget) + url-be-asynchronous t + url-current-callback-func 'w3-finalize-image-download) + (url-retrieve src)) + (setq-default url-be-asynchronous old-asynch))))))) + +(defun w3-finalize-image-download (widget) + (let ((glyph nil) + (url (widget-get widget 'src)) + (node nil) + (buffer (widget-get widget 'buffer))) + (message "Enhancing image...") + (setq glyph (image-normalize (cdr-safe (assoc url-current-mime-type + w3-image-mappings)) + (buffer-string))) + (message "Enhancing image... done") + (kill-buffer (current-buffer)) + (cond + ((w3-image-invalid-glyph-p glyph) + (w3-warn 'image (format "Reading of %s failed." url))) + ((eq (aref glyph 0) 'xbm) + (let ((temp-fname (url-generate-unique-filename "%s.xbm"))) + (save-excursion + (set-buffer (generate-new-buffer " *xbm-garbage*")) + (erase-buffer) + (insert (aref glyph 2)) + (setq glyph temp-fname) + (write-region (point-min) (point-max) temp-fname) + (kill-buffer (current-buffer))) + (setq glyph (make-glyph (list (cons 'x glyph)))) + (condition-case () + (delete-file temp-fname) + (error nil)))) + (t + (setq glyph (make-glyph glyph)))) + (setq node (assoc url w3-graphics-list)) + (if node + (set-glyph-image (cdr node) (glyph-image glyph)) + (setq w3-graphics-list (cons (cons url glyph) w3-graphics-list))) + + (if (and (buffer-name buffer) ; Dest. buffer exists + (w3-glyphp glyph)) ; got a valid glyph + (save-excursion + (set-buffer buffer) + (if (eq major-mode 'w3-mode) + (widget-value-set widget glyph) + (setq w3-image-widgets-waiting + (cons widget w3-image-widgets-waiting))))))) + +(defun w3-handle-image (&optional args) + (let* ((parms args) + (height (cdr-safe (assq 'height parms))) + (width (cdr-safe (assq 'width parms))) + (src (or (cdr-safe (assq 'src parms)) + "Error Image")) + (our-alt (cond + ((null w3-auto-image-alt) "") + ((eq t w3-auto-image-alt) + (concat "[IMAGE(" (url-basepath src t) ")] ")) + ((stringp w3-auto-image-alt) + (format w3-auto-image-alt (url-basepath src t))))) + (alt (or (cdr-safe (assq 'alt parms)) + our-alt)) + (ismap (and (assq 'ismap args) 'ismap)) + (usemap (cdr-safe (assq 'usemap args))) + (dest (w3-get-state :href)) + (base (cdr-safe (assq 'base args))) + (widget nil) + (zone (w3-get-state :zone)) + (align (intern (or (cdr-safe (assq 'align parms)) "middle")))) + (setq src (url-expand-file-name src + (cdr-safe (assoc base w3-base-alist)))) + (if dest + (w3-handle-hyperlink-end)) + (setq widget + (widget-create 'image + 'src src ; Where to load the image from + 'alt alt ; Textual replacement + 'ismap ismap ; Is it a server-side map? + 'usemap usemap ; Is it a client-side map? + 'href dest ; Hyperlink destination + )) + (widget-put widget 'buffer (current-buffer)) + (w3-maybe-start-image-download widget) + (goto-char (point-max)) + (if dest + (w3-handle-hyperlink (list (cons 'href dest)))))) + +(defun w3-handle-title (&optional args) + (if (w3-get-state :title) + (w3-put-state :title nil)) + (put 'text 'w3-formatter 'w3-handle-title-text)) + +(defun w3-handle-title-text (&optional args) + (w3-put-state :title + (concat (w3-get-state :title) args))) + +(defun w3-handle-/title (&optional args) + (put 'text 'w3-formatter nil) + (let ((ttl (w3-get-state :title))) + (cond + ((and (symbolp ttl) (eq ttl t)) + nil) + ((stringp ttl) + (setq ttl (w3-fix-spaces ttl)) + (if (and ttl (string= ttl "")) + (setq ttl (w3-fix-spaces (url-view-url t)))) + (rename-buffer (url-generate-new-buffer-name ttl)) + ;; Make the URL show in list-buffers output + (make-local-variable 'list-buffers-directory) + (setq list-buffers-directory (url-view-url t)) + (w3-put-state :title t)) + (t nil)))) + +(fset 'w3-handle-/head 'w3-handle-/title) + +(defun w3-handle-hyperlink (&optional args) + (let* ((href-node (assq 'href args)) + (href (cdr href-node)) + (title (cdr-safe (assq 'title args))) + (base (cdr-safe (assq 'base args))) + (name (or (cdr-safe (assq 'id args)) + (cdr-safe (assq 'name args))))) + (if href + (progn + (setq href (url-expand-file-name href (cdr-safe + (assoc base w3-base-alist)))) + (setcdr href-node href))) + (w3-put-state :seen-this-url (url-have-visited-url href)) + (if (and w3-delimit-links (not (eq w3-delimit-links 'linkname)) href) + (progn + (if (w3-get-state :seen-this-url) + (w3-handle-text (cdr w3-link-start-delimiter)) + (w3-handle-text (car w3-link-start-delimiter))) + (w3-put-state :needspace 'never))) + (w3-put-state :zone (point)) + (w3-put-state :link-args args) + (if title (w3-put-state :link-title title)) + (if href (w3-put-state :href href)) + (if name (w3-put-state :name name)))) + +(defun w3-follow-hyperlink (widget &rest ignore) + (let ((target (widget-get widget 'target)) + (href (widget-get widget 'href))) + (if target (setq target (intern (downcase target)))) + (case target + ((_blank external) + (w3-fetch-other-frame href)) + (_top + (delete-other-windows) + (w3-fetch href)) + (otherwise + (w3-fetch href))))) + +(defun w3-handle-hyperlink-end (&optional args) + (let* ((href (w3-get-state :href)) + (old-args (w3-get-state :link-args)) + (name (w3-get-state :name)) + (zone (w3-get-state :zone)) + (btdt (and href (w3-get-state :seen-this-url))) + (tag 'a) + (args (list (cons 'class (if btdt "visited" "link")))) + (face (cdr (w3-face-for-element))) + (old-face (and zone (get-text-property zone 'face))) + (faces (cond + ((and old-face (consp old-face)) (cons face old-face)) + (old-face (cons face (list old-face))) + (t (list face))))) + (if (not href) + nil + (add-text-properties zone (point) + (list 'mouse-face 'highlight + 'button + (append + (list 'push :args nil :value "" :tag "" + :notify 'w3-follow-hyperlink + :from (set-marker (make-marker) zone) + :to (set-marker (make-marker) (point)) + :help-echo (case w3-echo-link + (text + (buffer-substring + zone (point))) + (url href) + (otherwise nil))) + (alist-to-plist old-args)) + 'face faces + 'title (cons + (set-marker (make-marker) zone) + (set-marker (make-marker) (point))) + 'help-echo href)) + (w3-put-state :zone nil) + (w3-put-state :href nil) + (w3-put-state :name nil) + + (if (and w3-delimit-links href) + (progn + (delete-region (point) (progn (skip-chars-backward " ") + (point))) + (if (eq w3-delimit-links 'linkname) + (w3-handle-text (concat (if btdt (cdr w3-link-start-delimiter) + (car w3-link-start-delimiter)) + (or name "noname") + (if btdt (cdr w3-link-end-delimiter) + (car w3-link-end-delimiter)))) + (if btdt + (w3-handle-text (cdr w3-link-end-delimiter)) + (w3-handle-text (car w3-link-end-delimiter))))) + (goto-char (point-max))) + (if (and w3-link-info-display-function + (fboundp w3-link-info-display-function)) + (let ((info (condition-case () + (funcall w3-link-info-display-function href) + (error nil)))) + (if (and info (stringp info)) + (w3-handle-text info))))))) + +(defvar w3-tab-alist nil + "An assoc list of tab stops and their respective IDs") +(make-variable-buffer-local 'w3-tab-alist) + +(defun w3-handle-tab (&optional args) + (let* ((id (cdr-safe (assq 'id args))) + (to (cdr-safe (assq 'to args))) + (pos (cdr-safe (assoc to w3-tab-alist)))) + (cond + (id ; Define a new tab stop + (setq w3-tab-alist (cons (cons id (current-column)) w3-tab-alist))) + ((and to pos) ; Go to a currently defined tabstop + (while (<= (current-column) pos) + (insert " "))) + (to ; Tabstop 'to' is no defined yet + (w3-warn 'html (format "Unkown tab stop -- `%s'" to))) + (t ; Just do a tab + (insert (make-string w3-indent-level ? )))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Some bogus shit for pythia +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun w3-handle-margin (&optional args) + (if (assq 'reset args) + (w3-handle-/blockquote nil) + (w3-handle-blockquote nil))) + +(fset 'w3-handle-l 'w3-handle-br) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Guts of the forms interface for the new display engine +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun w3-handle-form (&optional args) + (let ((actn (cdr-safe (assq 'action args))) + (enct (cdr-safe (assq 'enctype args))) + (meth (cdr-safe (assq 'method args)))) + (if (not meth) (setq args (cons (cons 'method "GET") args))) + (if (not actn) + (setq args (cons (cons 'action + (or + (cdr-safe (assoc (cdr-safe (assq 'base args)) + w3-base-alist)) + (url-view-url t))) args)) + (setcdr (assq 'action args) + (url-expand-file-name + actn + (cdr-safe (assoc (cdr-safe (assq 'base args)) + w3-base-alist))))) + (if (not enct) + (setq args + (cons (cons 'enctype "application/x-www-form-urlencoded") + args))) + (w3-put-state :form args))) + +(defun w3-handle-/form (&optional args) + (w3-handle-paragraph) + (w3-put-state :form nil) + (w3-put-state :formnum (1+ (w3-get-state :formnum))) + ) + +(defun w3-handle-keygen (&optional args) + (w3-form-add-element 'keygen + (or (cdr-safe (assq 'name args)) "") + nil + nil + 1000 + nil + (w3-get-state :form) + nil + (w3-get-state :formnum) + nil + (w3-face-for-element))) + +(defun w3-handle-input (&optional args) + (if (or (not (w3-get-state :form)) + (w3-get-state :select)) + (w3-warn + 'html + "<input> outside of a <form> or inside <select> construct - ERROR!!") + (let* ((type (intern (downcase (or (cdr-safe (assq 'type args)) "text")))) + (name (cdr-safe (assq 'name args))) + (value (or (cdr-safe (assq 'value args)) "")) + (size (string-to-int (or (cdr-safe (assq 'size args)) "20"))) + (maxlength (cdr (assoc 'maxlength args))) + (default value) + (action (w3-get-state :form)) + (options) + (num (w3-get-state :formnum)) + (id (cdr-safe (assq 'id args))) + (checked (assq 'checked args)) + (face (w3-face-for-element))) + (if (and (string-match "^[ \t\n\r]+$" value) + (not (eq type 'hidden))) + (setq value "")) + (if maxlength (setq maxlength (string-to-int maxlength))) + (if (and name (string-match "[\r\n]" name)) + (setq name (mapconcat (function + (lambda (x) + (if (memq x '(?\r ?\n)) + "" + (char-to-string x)))) + name ""))) + (if (memq type '(checkbox radio)) (setq default checked)) + (if (and (eq type 'checkbox) (string= value "")) + (setq value "on")) + (w3-form-add-element type name value size maxlength default action + options num id checked face)))) + +(defun w3-handle-/select (&optional args) + (if (not (and (w3-get-state :form) + (w3-get-state :select))) + (w3-warn 'html + "</select> outside of a <form> or <select> construct - ERROR!!") + (put 'text 'w3-formatter 'w3-handle-text) + (let* ((args (w3-get-state :select)) + (tag 'input) + (face (w3-face-for-element)) + (opts (w3-get-state :options)) + (form (w3-get-state :form)) + (max-size nil) + (type "OPTION") + (default nil) + (tmp nil) + (id (cdr-safe (assq 'id args))) + (checked nil) + ) + (setq tmp (reverse opts)) + (if (assq 'multiple args) + (let ((tag 'ul) ; Convert to a list of checkboxes + (nam (or (cdr-safe (assq 'name args)) "option")) + (old (w3-get-state :align)) + (first nil)) + (w3-put-state :options nil) + (w3-put-state :select nil) + (w3-handle-list-opening) + (w3-put-state :align nil) + (while tmp + (w3-handle-list-item) + (w3-handle-input (list (cons 'type "checkbox") + (cons 'name nam) + (cons 'value + (or (cdr-safe + (assq 'value (car tmp))) + (cdr-safe + (assoc 'ack (car tmp))) + "unknown")) + (if (or (assq 'checked (car tmp)) + (assq 'selected (car tmp))) + (cons 'checked "checked")))) + (w3-handle-text (concat " " (or + (cdr-safe (assq 'ack (car tmp))) + "unknown"))) + (setq tmp (cdr tmp))) + (w3-handle-list-ending) + (w3-put-state :align old)) + (while (and (not default) tmp) + (if (or (assq 'checked (car tmp)) + (assq 'selected (car tmp))) + (setq default (car tmp))) + (setq tmp (cdr tmp))) + (setq default (cdr (assq 'ack (or default + (nth (1- (length opts)) opts)))) + checked (mapcar + (function + (lambda (x) + (cons (cdr-safe (assq 'ack x)) + (or (cdr-safe (assq 'value x)) + (cdr-safe (assq 'ack x)))))) + opts) + max-size (car (sort (mapcar + (function + (lambda (x) + (length (cdr-safe (assq 'ack x))))) + opts) + '>))) + (if (and form args opts) + (let ((pos (point)) + (siz (max max-size + (string-to-int + (or (cdr-safe (assq 'size args)) "0"))))) + (w3-form-add-element 'option + (or (cdr-safe (assq 'name args)) "option") + default + siz + (string-to-int + (or (cdr-safe (assq 'maxlength args)) + "1000")) + default + (w3-get-state :form) + checked + (w3-get-state :formnum) + nil checked face))))) + (w3-put-state :options nil) + (w3-put-state :select nil))) + +(defun w3-handle-option-data (&optional args) + (let ((text (cond + ((null args) nil) + ((stringp args) args) + ((listp args) (mapconcat 'identity args " "))))) + (if text + (progn + (setq text (url-strip-leading-spaces + (url-eat-trailing-space text))) + (w3-put-state :options (cons (cons (cons 'ack text) + (w3-get-state :optargs)) + (w3-get-state :options)))))) + (put 'text 'w3-formatter 'w3-handle-text)) + +(defun w3-handle-option (&optional args) + (if (not (and (w3-get-state :form) + (w3-get-state :select))) + (w3-warn 'html + "<option> outside of a <form> or <select> construct - ERROR!!") + (w3-put-state :optargs args) + (put 'text 'w3-formatter 'w3-handle-option-data))) + +(defun w3-handle-select (&optional args) + (if (not (w3-get-state :form)) + (w3-warn 'html "<select> outside of a <FORM> construct - ERROR!!") + (w3-put-state :select args)) + ) + +(defun w3-handle-textarea (&optional args) + (if (not (w3-get-state :form)) + (w3-warn 'html "<textarea> outside of a <FORM> construct - ERROR!!") + (let ((node (assq 'maxlength args))) + (cond + ((null node) + (setq args (cons (cons 'maxlength nil) args))) + ((null (cdr-safe node)) + nil) + ((string= (downcase (cdr-safe node)) "unlimited") + (setcdr node nil)))) + (let* ( + (face (let ((tag 'input) + (args nil)) + (w3-face-for-element))) + (value (cdr-safe (assq 'data args))) + (type "TEXTAREA") + (name (cdr-safe (assq 'name args))) + (size (string-to-int (or (cdr-safe (assq 'size args)) "20"))) + (maxlength (string-to-int + (or (cdr (assq 'maxlength args)) "10000"))) + (default nil) + (action (w3-get-state :form)) + (options) + (pos) + (num (w3-get-state :formnum)) + (id (cdr-safe (assq 'id args))) + (checked (assq 'checked args))) + (setq default value + pos (point)) + (put 'text 'w3-formatter 'w3-handle-text) + (w3-form-add-element 'multiline name value size maxlength default + action options num id checked face)))) + +(defun w3-handle-label-text (&optional args) + (setcdr (w3-get-state :label-text) + (concat (cdr (w3-get-state :label-text)) args)) + (w3-handle-text args)) + +(defun w3-handle-/label (&optional args) + (let ((num (w3-get-state :formnum)) + (dat (w3-get-state :label-text))) + (setq w3-form-labels (cons (cons (format "%d:%s" num (car dat)) + (cdr dat)) + w3-form-labels)) + (put 'text 'w3-formatter 'w3-handle-text))) + +(defun w3-handle-label (&optional args) + (if (not (w3-get-state :form)) + (w3-warn 'html "<label> outside of a <FORM> construct - ERROR!!") + (put 'text 'w3-formatter 'w3-handle-label-text) + (w3-put-state :label-text (cons (or (cdr-safe (assq 'for args)) + "Unknown label") "")))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; For displaying the buffer +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun w3-show-buffer () + (let ((potential-title + (and (not (w3-get-state :title)) + (url-generate-new-buffer-name + (url-basepath url-current-file t))))) + (if (and potential-title (string= potential-title "")) + (setq potential-title + (url-generate-new-buffer-name url-current-file))) + (if (and potential-title (not (string= potential-title ""))) + (rename-buffer potential-title))) + (setq inhibit-read-only nil) + (if url-find-this-link + (w3-find-specific-link url-find-this-link)) + (let* ((tag 'html) + (args nil) + (face (cdr (w3-face-for-element)))) + (and face + (if (not (fboundp 'valid-specifier-locale-p)) + nil + (w3-my-safe-copy-face face 'default (current-buffer)))))) + +(defun w3-parse-header-link-items () + ;; Parse `url-current-mime-headers' and look for any <link> items + (let ((items url-current-mime-headers) + (node nil) + (url nil) + (type nil) + (args nil) + (title nil) + (label nil)) + (while items + (setq node (car items) + items (cdr items)) + (if (string= (car node) "link") + (progn + (setq args (mm-parse-args (cdr node)) + type (if (assoc "rel" args) "rel" "rev") + label (cdr-safe (assoc type args)) + title (cdr-safe (assoc "title" args)) + url (car-safe (rassoc nil args))) + (if (string-match "^<.*>$" url) + (setq url (substring url 1 -1))) + (and url label type + (w3-handle-link (list (cons "href" url) + (cons type label) + (cons "title" title))))))))) + +(defun w3-refresh-buffer (&rest args) + "Redraw the current buffer - this does not refetch or reparse the current +document, but uses the stored parse data." + (interactive) + (let ((buffer-read-only nil)) + (if (get-buffer url-working-buffer) + (kill-buffer url-working-buffer)) + (error "Not yet reimplemented... sorry."))) + +(defun w3-prepare-buffer (&rest args) + ;; The text/html viewer - does all the drawing and displaying of the buffer + ;; that is necessary to go from raw HTML to a good presentation. + (let ((active-minibuffer-window + (if (minibuffer-window-active-p (minibuffer-window)) + (minibuffer-window)))) + (let ((pop-up-windows nil)) + (if active-minibuffer-window + (let* ((current-buffer (current-buffer)) + (window (get-buffer-window current-buffer t))) + (cond (window + (and (fboundp 'select-frame) + (fboundp 'window-frame) + (select-frame (window-frame window))) + (select-window window)) + ((and (fboundp 'selected-frame) + (fboundp 'window-frame) + (eq (selected-frame) + (window-frame (minibuffer-window)))) + ;; on minibuffer-only-frame + (select-frame (previous-frame)) + (select-window (frame-first-window (selected-frame)))) + ((fboundp 'frame-first-window) + (select-window (frame-first-window)))) + (set-buffer current-buffer)))) + (let* ((source (buffer-string)) + (parse (w3-preparse-buffer (current-buffer))) + (buff (car parse))) + (set-buffer-modified-p nil) + (kill-buffer (current-buffer)) + (set-buffer buff) + (setq w3-current-source source + w3-current-parse w3-last-parse-tree) + (w3-parse-header-link-items) + (save-excursion + (goto-char (point-max)) + (w3-handle-paragraph) + (if (and (boundp 'w3-image-widgets-waiting) w3-image-widgets-waiting) + (let (url glyph widget) + (while w3-image-widgets-waiting + (setq widget (car w3-image-widgets-waiting) + w3-image-widgets-waiting (cdr w3-image-widgets-waiting) + url (widget-get widget 'src) + glyph (cdr-safe (assoc url w3-graphics-list))) + (widget-value-set widget glyph)))) + (w3-mode) + (w3-handle-annotations) + (w3-handle-headers) + (set-buffer-modified-p nil) + ) + (switch-to-buffer (current-buffer)) + (or active-minibuffer-window + (let ((window nil) + (pop-up-windows nil)) + (display-buffer (current-buffer)) + (if (or w3-running-FSF19 w3-running-xemacs) + (setq window (get-buffer-window (current-buffer) t)) + (setq window (get-buffer-window (current-buffer)))) + (select-window window) + (if (and (fboundp 'select-frame) + (fboundp 'window-frame)) + (select-frame (window-frame window))))) + (goto-char (point-min)) + (w3-show-buffer) + (if url-keep-history + (let ((url (url-view-url t))) + (if (not (url-hashtablep url-history-list)) + (setq url-history-list (url-make-hashtable 131))) + (url-puthash url (buffer-name) url-history-list) + (if (fboundp 'w3-shuffle-history-menu) + (w3-shuffle-history-menu))))) + (cond (active-minibuffer-window + (select-window active-minibuffer-window) + (sit-for 0))))) + +(defun w3-handle-headers () + ;; Insert any headers the user wants to see into the current buffer. + (let ((show w3-show-headers) + (cur nil) + (hdrs nil) + (tag 'ol) + (header nil) + (w3-last-fill-pos (point-max)) + (val nil) + (first t)) + (goto-char (point-max)) + (if (eq show t) (setq show '(".*"))) + (while show + (setq cur (car show) + show (cdr show) + hdrs url-current-mime-headers) + (while hdrs + (setq header (car (car hdrs)) + val (cdr (car hdrs)) + hdrs (cdr hdrs)) + (if (numberp val) (setq val (int-to-string val))) + (if (and (/= 0 (length header)) + (string-match cur header)) + (progn + (if first + (progn + (w3-handle-hr) + (w3-handle-list-opening '(("value" . 1))) + (setq tag 'li + first nil))) + (w3-handle-list-item) + (w3-handle-text (concat (capitalize header) + ": " val)))))) + (if (not first) ; We showed some headers + (setq tag '/ol + tag (w3-handle-list-ending))))) + +(defun w3-handle-annotations () + ;; Insert personal annotations into the current buffer + (let ((annos (w3-fetch-personal-annotations)) + (tag nil)) + (if (not annos) + nil ; No annotations + (goto-char (cond + ((eq w3-annotation-position 'bottom) (point-max)) + ((eq w3-annotation-position 'top) (point-min)) + (t (message "Bad value for w3-annotation-position") + (point-max)))) + (w3-handle-div '((class . "annotations"))) + (w3-handle-hr '((width . "75%") + (label . " Personal Annotations ") + (align . "center"))) + (setq tag 'ol) + (w3-handle-list-opening) + (while annos + (w3-handle-list-item) + (w3-handle-hyperlink (list (cons 'href (car (car annos))))) + (w3-handle-text (cdr (car annos))) + (w3-handle-hyperlink-end) + (setq annos (cdr annos))) + (w3-handle-list-ending) + (w3-handle-hr '((width . "75%") + (align . "center"))) + (w3-handle-/div) + ))) + +(defun w3-fetch-personal-annotations () + ;; Grab any personal annotations for the current url + (let ((url (url-view-url t)) + (anno w3-personal-annotations) + (annolist nil)) + (if (assoc url anno) + (while anno + (if (equal (car (car anno)) url) + (setq annolist + (cons + (cons + (format "file:%s%s/PAN-%s.html" + (if (= ?/ (string-to-char + w3-personal-annotation-directory)) "" + "/") + w3-personal-annotation-directory + (car (car (cdr (car anno))))) + (car (cdr (car (cdr (car anno)))))) + annolist))) + (setq anno (cdr anno)))) + annolist)) + +(defun w3-normalize-spaces (string) + ;; nuke spaces at the beginning + (if (string-match "^[ \t\r\n]+" string) + (setq string (substring string (match-end 0)))) + + ;; nuke spaces in the middle + (while (string-match "[ \t\r\n][ \r\t\n]+" string) + (setq string (concat (substring string 0 (1+ (match-beginning 0))) + (substring string (match-end 0))))) + + ;; nuke spaces at the end + (if (string-match "[ \t\n\r]+$" string) + (setq string (substring string 0 (match-beginning 0)))) + string) + +(defun w3-upcase-region (st nd &optional end) + (and st nd (upcase-region st nd))) + +(provide 'w3-draw) +