1 ;;; w3-forms.el --- Emacs-w3 forms parsing code for new display engine
2 ;; Author: $Author: wmperry $
3 ;; Created: $Date: 2002/10/23 03:33:41 $
4 ;; Version: $Revision: 1.11 $
5 ;; Keywords: faces, help, comm, data, languages
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8 ;;; Copyright (c) 1996 - 1999, 2008 Free Software Foundation, Inc.
9 ;;; Copyright (c) 1996 by William M. Perry <wmperry@cs.indiana.edu>
11 ;;; This file is part of GNU Emacs.
13 ;;; GNU Emacs is free software; you can redistribute it and/or modify
14 ;;; it under the terms of the GNU General Public License as published by
15 ;;; the Free Software Foundation; either version 2, or (at your option)
16 ;;; any later version.
18 ;;; GNU Emacs is distributed in the hope that it will be useful,
19 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;;; GNU General Public License for more details.
23 ;;; You should have received a copy of the GNU General Public License
24 ;;; along with GNU Emacs; see the file COPYING. If not, write to the
25 ;;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 ;;; Boston, MA 02111-1307, USA.
27 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
29 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
30 ;;; FORMS processing for HTML
31 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
44 (autoload 'custom-magic-reset "cus-edit")
45 (autoload 'w3-warn "w3")
47 (defvar w3-form-use-old-style nil
48 "*Non-nil means use the old way of interacting for form fields.")
50 (defvar w3-form-keymap
51 ;; Fixme: Why doesn't this use inheritance? -- fx
52 (let ((map (copy-keymap global-map))
53 (eol-loc (where-is-internal 'end-of-line global-map t)))
54 (substitute-key-definition 'widget-backward 'w3-widget-backward
56 (substitute-key-definition 'widget-forward 'w3-widget-forward
58 (define-key map [return] 'w3-form-maybe-submit-by-keypress)
59 (define-key map "\r" 'w3-form-maybe-submit-by-keypress)
60 (define-key map "\n" 'w3-form-maybe-submit-by-keypress)
61 (define-key map "\t" 'w3-widget-forward)
62 (define-key map "\C-k" 'widget-kill-line)
63 (define-key map "\C-a" 'widget-beginning-of-line)
64 (define-key map (vector w3-mouse-button3) 'w3-popup-menu)
66 (define-key map eol-loc 'widget-end-of-line))
69 ;; A form entry area is a vector
70 ;; [ type name default-value value maxlength options widget plist]
72 ;; type = symbol defining what type of form entry area it is
74 ;; name = the name of the form element
75 ;; default-value = the value this started out with
77 (defsubst w3-form-element-type (obj) (aref obj 0))
78 (defsubst w3-form-element-name (obj) (aref obj 1))
79 (defsubst w3-form-element-default-value (obj) (aref obj 2))
80 (defsubst w3-form-element-value (obj) (aref obj 3))
81 (defsubst w3-form-element-size (obj) (aref obj 4))
82 (defsubst w3-form-element-maxlength (obj) (aref obj 5))
83 (defsubst w3-form-element-options (obj) (aref obj 6))
84 (defsubst w3-form-element-action (obj) (aref obj 7))
85 (defsubst w3-form-element-widget (obj) (aref obj 8))
86 (defsubst w3-form-element-plist (obj) (aref obj 9))
88 (defsubst w3-form-element-set-type (obj val) (aset obj 0 val))
89 (defsubst w3-form-element-set-name (obj val) (aset obj 1 val))
90 (defsubst w3-form-element-set-default-value (obj val) (aset obj 2 val))
91 (defsubst w3-form-element-set-value (obj val) (aset obj 3 val))
92 (defsubst w3-form-element-set-size (obj val) (aset obj 4 val))
93 (defsubst w3-form-element-set-maxlength (obj val) (aset obj 5 val))
94 (defsubst w3-form-element-set-options (obj val) (aset obj 6 val))
95 (defsubst w3-form-element-set-action (obj val) (aset obj 7 val))
96 (defsubst w3-form-element-set-widget (obj val) (aset obj 8 val))
97 (defsubst w3-form-element-set-plist (obj val) (aset obj 9 val))
99 (defvar w3-form-valid-key-sizes
101 ("1024 (Premium)" . 1024)
102 ("896 (Regular)" . 896)
103 ("768 (Unleaded)" . 768)
104 ("512 (Low Grade)" . 512)
106 ("256 (Test Grade)" . 256)
108 "An assoc list of available key sizes and meaningful descriptions.")
110 (defun w3-form-determine-size (el size)
113 (case (w3-form-element-type el)
116 ((reset submit) (+ 2 (length (or (w3-form-element-value el)
118 (w3-form-element-type el))))))
122 ((float password text int)
123 (if w3-form-use-old-style
126 (image (+ 2 (length (or
127 (plist-get (w3-form-element-plist el) 'alt)
130 (let ((options (copy-sequence (w3-form-element-options el))))
131 (length (caar (sort options
135 (length (car y))))))))))
137 (+ (length "Key Length: ")
139 (mapcar (function (lambda (pair)
140 (length (car pair))))
141 w3-form-valid-key-sizes))))
142 (otherwise (or size 22))))
145 (defun w3-form-add-element (plist face)
146 (let* ((action (plist-get plist 'action))
147 (el (vector (plist-get plist 'type)
148 (plist-get plist 'name)
149 (plist-get plist 'default)
150 (plist-get plist 'value)
151 (plist-get plist 'size)
152 (plist-get plist 'maxlength)
153 (plist-get plist 'options)
157 (size (w3-form-determine-size el (plist-get plist 'size)))
158 (node (assoc action w3-form-elements)))
159 (if (not (assq '*table-autolayout w3-display-open-element-stack))
161 (setcdr node (cons el (cdr node)))
162 (setq w3-form-elements (cons (cons action (list el))
165 (set-text-properties (point)
166 (progn (insert-char ?T size) (point))
167 (list 'w3-form-info (cons el face)
170 'rear-nonsticky t)))))
173 (defun w3-form-resurrect-widgets ()
174 (let ((st (point-min))
175 ;; FIXME! For some reason this loses on long lines right now.
176 (widget-push-button-gui nil)
177 info nd node action face)
179 (if (setq info (get-text-property st 'w3-form-info))
181 (setq nd (or (next-single-property-change st 'w3-form-info)
185 action (w3-form-element-action info)
186 node (assoc action w3-form-elements))
188 (delete-region st nd)
189 (if (not (w3-form-element-size info))
190 (w3-form-element-set-size info 20))
191 (w3-form-add-element-internal info face)
192 (setq st (next-single-property-change st 'w3-form-info)))
193 (setq st (next-single-property-change st 'w3-form-info))))))
195 (defsubst w3-form-mark-widget (widget el)
196 (let ((widgets (list widget))
197 (children (widget-get widget :children))
198 (parent (widget-get widget :parent)))
199 (w3-form-element-set-widget el widget)
200 ;; Get _all_ the children associated with this widget
202 (setq widgets (cons (car children) widgets))
203 (if (widget-get (car children) :children)
204 (setq children (append children
205 (widget-get (car children) :children))))
206 (setq children (cdr children)))
207 (while (widget-get widget :parent)
208 (setq widget (widget-get widget :parent)
209 widgets (cons widget widgets)))
210 (setq children (widget-get widget :buttons))
211 ;; Special case for radio buttons
213 (setq widgets (cons (car children) widgets))
214 (if (widget-get (car children) :children)
215 (setq children (append children
216 (widget-get (car children) :children))))
217 (setq children (cdr children)))
219 (setq widget (pop widgets))
220 (widget-put widget :emacspeak-help 'w3-form-summarize-field)
221 (widget-put widget :help-echo 'w3-form-summarize-field)
222 (widget-put widget :w3-form-data el))))
224 (defun w3-form-add-element-internal (el face)
226 (buffer-read-only nil)
227 (inhibit-read-only t)
228 (widget-creation-function nil))
229 (setq widget-creation-function (or (get (w3-form-element-type el)
230 'w3-widget-creation-function)
231 'w3-form-default-widget-creator)
232 widget (and (fboundp widget-creation-function)
233 (funcall widget-creation-function el face)))
236 (w3-form-mark-widget widget el))))
238 ;; These properties tell the add-element function how to actually create
239 ;; each type of widget.
240 (put 'checkbox 'w3-widget-creation-function 'w3-form-create-checkbox)
241 (put 'multiline 'w3-widget-creation-function 'w3-form-create-multiline)
242 (put 'radio 'w3-widget-creation-function 'w3-form-create-radio-button)
243 (put 'reset 'w3-widget-creation-function 'w3-form-create-submit-button)
244 (put 'submit 'w3-widget-creation-function 'w3-form-create-submit-button)
245 (put 'hidden 'w3-widget-creation-function 'ignore)
246 (put 'file 'w3-widget-creation-function 'w3-form-create-file-browser)
247 (put 'option 'w3-widget-creation-function 'w3-form-create-option-list)
248 (put 'keygen 'w3-widget-creation-function 'w3-form-create-keygen-list)
249 (put 'button 'w3-widget-creation-function 'w3-form-create-button)
250 (put 'image 'w3-widget-creation-function 'w3-form-create-image)
251 (put 'int 'w3-widget-creation-function 'w3-form-create-integer)
252 (put 'float 'w3-widget-creation-function 'w3-form-create-float)
253 (put 'custom 'w3-widget-creation-function 'w3-form-create-custom)
254 (put 'text 'w3-widget-creation-function 'w3-form-create-text)
255 (put 'password 'w3-widget-creation-function 'w3-form-create-password)
258 (defvar w3-custom-options nil)
259 (make-variable-buffer-local 'w3-custom-options)
261 (defun w3-form-create-custom (el face)
263 (let* ((name (w3-form-element-name el))
264 (var-name (w3-form-element-value el))
265 (type (plist-get (w3-form-element-plist el) 'custom-type))
266 (widget (widget-create (cond ((string-equal type "variable")
268 ((string-equal type "face")
270 ((string-equal type "group")
272 (t 'item)) (intern var-name))))
273 (custom-magic-reset widget)
274 (push widget w3-custom-options)
277 (defun w3-form-create-checkbox (el face)
278 (widget-create 'checkbox
280 (and (w3-form-element-default-value el) t)))
282 (defun w3-form-radio-button-update (widget child event)
283 (widget-radio-action widget child event)
284 (w3-form-mark-widget widget (widget-get widget :w3-form-data)))
286 (defun w3-form-create-radio-button (el face)
287 (let* ((name (w3-form-element-name el))
288 (action (w3-form-element-action el))
289 (uniqid (cons name action))
290 (formobj (cdr (assoc uniqid w3-form-radio-elements)))
295 (setq widget (w3-form-element-widget formobj))
296 (widget-radio-add-item widget
301 :value (w3-form-element-value el)))
302 (w3-form-mark-widget widget el)
303 (if (w3-form-element-default-value el)
305 (widget-put widget 'w3-form-default-value
306 (w3-form-element-value el))
307 (widget-value-set widget (w3-form-element-value el))))
309 (setq widget (widget-create
311 :value (w3-form-element-value el)
312 :action 'w3-form-radio-button-update
317 :value (w3-form-element-value el)))
318 w3-form-radio-elements (cons (cons uniqid el)
319 w3-form-radio-elements))
320 (widget-put widget 'w3-form-default-value (w3-form-element-value el))
323 (defun w3-form-create-button (el face)
324 ;; This handles dealing with the bogus Netscape 'button' input type
325 ;; that lots of places have been using to slap javascript shit onto
326 (let ((val (w3-form-element-value el)))
327 (if (or (not val) (string= val ""))
328 (setq val "Push Me"))
329 (widget-create 'push-button
335 (defun w3-form-create-image (el face)
336 (widget-create 'push-button
339 :notify 'w3-form-submit/reset-callback
341 (plist-get (w3-form-element-plist el) 'alt)
342 ;; Can it have a value other than "" anyway?
343 ;; w3-form-determine-size does not even bother
344 ;; to check the value.
345 (let ((val (w3-form-element-value el)))
348 (not (zerop (length val)))
352 (defun w3-form-create-submit-button (el face)
353 (let ((val (w3-form-element-value el)))
354 (if (or (not val) (string= val ""))
355 (setq val (if (eq (w3-form-element-type el) 'submit)
358 (widget-create 'push-button
359 :notify 'w3-form-submit/reset-callback
360 :button-face face val)))
362 (defun w3-form-create-file-browser (el face)
366 :size (w3-form-element-size el)
368 :value (w3-form-element-value el)))
370 (defun w3-form-create-keygen-list (el face)
371 (let* ((size (apply 'max (mapcar (lambda (pair) (length (car pair)))
372 w3-form-valid-key-sizes)))
373 (options (mapcar (lambda (pair)
379 :menu-tag-get `(lambda (zed) ,(car pair))
380 :tag (truncate-string-to-width (car pair)
383 w3-form-valid-key-sizes)))
384 (apply 'widget-create 'menu-choice
385 :emacspeak-help 'w3-form-summarize-field
394 (defun w3-form-create-option-list (el face)
395 (let* ((size (w3-form-determine-size el nil))
396 (widget (apply 'widget-create 'menu-choice
397 :value (w3-form-element-value el)
409 :emacspeak-help 'w3-form-summarize-field
410 :menu-tag-get `(lambda (zed) ,(car x))
411 :tag (truncate-string-to-width (car x)
416 (w3-form-element-options el)))))
417 (widget-value-set widget (w3-form-element-value el))
420 ;(defun w3-form-create-multiline (el face)
421 ; (widget-create 'text :value-face face (w3-form-element-value el)))
423 (defun w3-form-create-multiline (el face)
424 (widget-create 'push-button
426 :notify 'w3-do-text-entry
427 "Multiline text area"))
429 (defun w3-form-create-integer (el face)
430 (if w3-form-use-old-style
431 (w3-form-default-widget-creator el face)
432 (widget-create 'integer
433 :size (w3-form-element-size el)
437 :keymap w3-form-keymap
439 (w3-form-element-value el))))
441 (defun w3-form-create-float (el face)
442 (if w3-form-use-old-style
443 (w3-form-default-widget-creator el face)
444 (widget-create 'number
445 :size (w3-form-element-size el)
449 :keymap w3-form-keymap
451 (w3-form-element-value el))))
453 (defun w3-form-create-text (el face)
454 (if w3-form-use-old-style
455 (w3-form-default-widget-creator el face)
456 (widget-create 'editable-field
457 :keymap w3-form-keymap
458 :size (w3-form-element-size el)
461 (w3-form-element-value el))))
463 (defun w3-form-create-password (el face)
464 ;; *sigh* This will fail under XEmacs, but I can yell at them about
465 ;; upgrading separately for the release of 19.15 and 20.0
466 (if w3-form-use-old-style
467 (w3-form-default-widget-creator el face)
468 (widget-create 'editable-field
470 :keymap w3-form-keymap
471 :size (w3-form-element-size el)
475 (w3-form-element-value el))))
477 (defun w3-form-default-widget-creator (el face)
479 :notify 'w3-form-default-button-callback
480 :value-to-internal 'w3-form-default-button-update
481 :size (w3-form-element-size el)
485 (w3-form-element-value el)))
487 (defun w3-form-default-button-update (w v)
488 (let ((info (widget-get w :w3-form-data)))
491 (truncate-string-to-width
492 (if (eq 'password (w3-form-element-type info))
493 (make-string (length v) ?*)
495 (w3-form-element-size info) nil ? )))
498 (defun w3-form-default-button-callback (widget &rest ignore)
499 (let* ((obj (widget-get widget :w3-form-data))
500 (typ (w3-form-element-type obj))
501 (def (widget-value widget))
506 (setq val (funcall url-passwd-entry-func "Password: " def)))
508 (setq val (read-string
509 (concat (capitalize (symbol-name typ)) ": ") def))))
510 (widget-value-set widget val))
511 (apply 'w3-form-possibly-submit widget ignore))
513 ;; These properties tell the help-echo function how to summarize each
515 (put 'checkbox 'w3-summarize-function 'w3-form-summarize-checkbox)
516 (put 'multiline 'w3-summarize-function 'w3-form-summarize-multiline)
517 (put 'radio 'w3-summarize-function 'w3-form-summarize-radio-button)
518 (put 'reset 'w3-summarize-function 'w3-form-summarize-submit-button)
519 (put 'submit 'w3-summarize-function 'w3-form-summarize-submit-button)
520 (put 'button 'w3-summarize-function 'w3-form-summarize-submit-button)
521 (put 'file 'w3-summarize-function 'w3-form-summarize-file-browser)
522 (put 'option 'w3-summarize-function 'w3-form-summarize-option-list)
523 (put 'keygen 'w3-summarize-function 'w3-form-summarize-keygen-list)
524 (put 'image 'w3-summarize-function 'w3-form-summarize-image)
525 (put 'password 'w3-summarize-function 'w3-form-summarize-password)
526 (put 'hidden 'w3-summarize-function 'ignore)
528 (defun w3-form-summarize-field (widget &rest ignore)
529 "Sumarize a widget that should be a W3 form entry area.
530 This can be used as the :help-echo property of all w3 form entry widgets."
535 (setq info (widget-get widget :w3-form-data))
538 (while (widget-get widget :parent)
539 (setq widget (widget-get widget :parent)))
540 (setq info (widget-get widget :w3-form-data)))
542 (signal 'wrong-type-argument (list 'w3-form-widget widget)))
543 (setq func (or (get (w3-form-element-type info) 'w3-summarize-function)
544 'w3-form-summarize-default)
545 msg (and (fboundp func) (funcall func info widget)))
546 ;; FIXME! This should be removed once emacspeak is updated to
547 ;; more closely follow the widget-y way of just returning the string
548 ;; instead of having the underlying :help-echo or :emacspeak-help
549 ;; implementation do it.
550 (and msg (message "%s" msg))))
552 (defsubst w3-form-field-label (data)
553 ;;; FIXXX!!! Need to reimplement using the new forms implementation!
554 (declare (special w3-form-labels))
556 (assoc (or (plist-get (w3-form-element-plist data) 'id)
557 (plist-get (w3-form-element-plist data) 'label))
560 (defun w3-form-summarize-default (data widget)
561 (let ((label (w3-form-field-label data))
562 (name (w3-form-element-name data))
563 (value (widget-value (w3-form-element-widget data))))
564 (format "Text field %s set to: %s" (or label (concat "called " name))
567 (defun w3-form-summarize-password (data widget)
568 (let ((label (w3-form-field-label data))
569 (name (w3-form-element-name data)))
570 (format "Password field %s is a secret. Shhh."
571 (or label (concat "called " name)))))
573 (defun w3-form-summarize-multiline (data widget)
574 (let ((name (w3-form-element-name data))
575 (label (w3-form-field-label data))
576 (value (w3-form-element-value data)))
577 (format "Multiline text input %s set to: %s"
578 (or label (concat "called " name))
581 (defun w3-form-summarize-checkbox (data widget)
582 (let ((name (w3-form-element-name data))
583 (label (w3-form-field-label data))
584 (checked (widget-value (w3-form-element-widget data))))
585 (format "Checkbox %s is %s" (or label name) (if checked "on" "off"))))
587 (defun w3-form-summarize-option-list (data widget)
588 (let ((name (w3-form-element-name data))
589 (label (w3-form-field-label data))
590 (default (w3-form-element-default-value data)))
591 (format "Option list (%s) set to: %s" (or label name)
592 (widget-value (w3-form-element-widget data)))))
594 (defun w3-form-summarize-image (data widget)
595 (let ((name (w3-form-element-name data))
596 (label (w3-form-field-label data)))
597 (concat "Image entry " (or label (concat "called " name)))))
599 (defun w3-form-summarize-submit-button (data widget)
600 (let* ((type (w3-form-element-type data))
601 (label (w3-form-field-label data))
602 (button-text (widget-value (w3-form-element-widget data)))
603 (type-desc (case type
604 (submit "Submit Form")
606 (button "A Button"))))
607 (format "%s: %s" type-desc (or label button-text ""))))
609 (defun w3-form-summarize-radio-button (data widget)
610 (let ((name (w3-form-element-name data))
611 (label (w3-form-field-label data))
612 (cur-value (widget-value (w3-form-element-widget data)))
613 (this-value (widget-value (widget-get-sibling widget))))
614 (if (equal this-value cur-value)
615 (format "Radio group %s has %s pressed"
616 (or label name) this-value)
617 (format "Press this to change radio group %s from %s to %s" (or label name) cur-value
620 (defun w3-form-summarize-file-browser (data widget)
621 (let ((name (w3-form-element-name data))
622 (label (w3-form-field-label data))
623 (file (widget-value (w3-form-element-widget data))))
624 (format "File entry %s pointing to: %s" (or label name) (or file
627 (defun w3-form-summarize-keygen-list (data widget)
628 (format "Submitting this form will generate a %d bit key (not)"
629 (widget-value (w3-form-element-widget data))))
631 (defun w3-form-maybe-submit-by-keypress ()
633 (let ((widget (widget-at (point))))
635 (w3-form-possibly-submit widget))))
637 (defsubst w3-all-widgets (actn)
638 ;; Return a list of data entry widgets in form number ACTN
639 (cdr-safe (assoc actn w3-form-elements)))
641 (defun w3-form-possibly-submit (widget &rest ignore)
642 (let* ((formobj (widget-get widget :w3-form-data))
643 (ident (w3-form-element-action formobj))
644 (widgets (w3-all-widgets ident))
648 ;; Gack. Netscape auto-submits forms of one text field
649 ;; here we go through the list of widgets in this form and
650 ;; determine which are not submit/reset/button inputs.
651 ;; If the # == 1, then submit the form.
656 (case (w3-form-element-type (car widgets))
657 ((submit reset image button)
664 widgets (cdr widgets)))
665 (if (and (= text-fields 1) text-p)
666 (w3-submit-form ident))))
668 (defun w3-form-submit/reset-callback (widget &rest ignore)
669 (let* ((formobj (widget-get widget :w3-form-data))
670 (w3-submit-button formobj))
671 (case (w3-form-element-type formobj)
672 (submit (w3-submit-form (w3-form-element-action formobj)))
673 (reset (w3-revert-form (w3-form-element-action formobj)))
674 (image (w3-submit-form (w3-form-element-action formobj)))
677 "Impossible widget type %s triggered w3-form-submit/reset-callback"
678 (w3-form-element-type formobj))))))
681 (defun w3-do-text-entry (widget &rest ignore)
682 (let* ((data (list widget (current-buffer)))
683 (formobj (widget-get widget :w3-form-data))
684 (buff (get-buffer-create (format "Form Entry: %s"
685 (w3-form-element-name formobj)))))
686 (switch-to-buffer-other-window buff)
689 (if (w3-form-element-value formobj)
690 (insert (w3-form-element-value formobj)))
691 (setq w3-current-last-buffer data)
692 (message "Press C-c C-c when finished with text entry.")
693 (local-set-key "\C-c\C-c" 'w3-finish-text-entry)))
695 (defun w3-finish-text-entry ()
697 (if w3-current-last-buffer
698 (let* ((widget (nth 0 w3-current-last-buffer))
699 (formobj (widget-get widget :w3-form-data))
700 (buff (nth 1 w3-current-last-buffer))
701 (valu (buffer-string))
702 (inhibit-read-only t)
704 (local-set-key "\C-c\C-c" 'undefined)
705 (kill-buffer (current-buffer))
709 (if (not (and buff (bufferp buff) (buffer-name buff)))
710 (message "Could not find the form buffer for this text!")
711 (switch-to-buffer buff)
712 (w3-form-element-set-value formobj valu)))))
714 (defun w3-revert-form (actn)
716 (let* ((formobjs (w3-all-widgets actn))
717 (inhibit-read-only t)
718 deft type widget formobj)
720 (setq formobj (car formobjs)
721 widget (w3-form-element-widget formobj)
722 formobjs (cdr formobjs)
723 deft (w3-form-element-default-value formobj)
724 type (w3-form-element-type formobj))
726 ((submit reset image hidden) nil)
728 (setq deft (widget-get widget 'w3-form-default-value))
729 (if (and widget deft)
730 (widget-value-set widget deft)))
733 (widget-value-set widget t)
734 (widget-value-set widget nil)))
736 (w3-form-element-set-value formobj (w3-form-element-default-value
739 (widget-value-set widget deft))
741 (widget-value-set widget deft))))
744 (defun w3-form-encode-helper (formobjs)
746 (submit-button-data w3-submit-button)
747 formobj result widget temp type)
749 (setq formobj (car formobjs)
750 type (w3-form-element-type formobj)
751 widget (w3-form-element-widget formobj)
752 formobjs (cdr formobjs)
757 (if (and (eq submit-button-data formobj)
758 (w3-form-element-name formobj))
762 (concat (w3-form-element-name formobj)
765 (concat (w3-form-element-name formobj)
770 (if (and (eq submit-button-data formobj)
771 (w3-form-element-name formobj))
772 (cons (w3-form-element-name formobj)
773 (w3-form-element-value formobj))))
775 (let* ((radio-name (w3-form-element-name formobj))
776 (radio-object (cdr-safe
780 (w3-form-element-action formobj))
781 w3-form-radio-elements)))
782 (chosen-widget (and radio-object
784 (w3-form-element-widget
786 (if (assoc radio-name result)
788 (cons radio-name (widget-value chosen-widget)))))
790 (cons (w3-form-element-name formobj)
791 (number-to-string (or (condition-case ()
792 (widget-value widget)
795 (if (widget-value widget)
796 (cons (w3-form-element-name formobj)
797 (w3-form-element-value formobj))))
800 (fname (widget-value widget)))
802 (set-buffer (get-buffer-create " *w3-temp*"))
806 (insert-file-contents-literally fname)
807 (error (concat "Error accessing " fname))))
808 (cons (w3-form-element-name formobj)
811 (file-name-nondirectory fname)))
814 (cons (w3-form-element-name formobj)
816 (assoc (widget-value widget)
817 (w3-form-element-options formobj)))))
821 (error (error "Not configured for SSL, please read the info pages")))
822 (if (fboundp 'ssl-req-user-cert) nil
823 (error "This version of SSL isn't capable of requesting certificates"))
824 (let ((challenge (plist-get (w3-form-element-plist formobj) 'challenge))
825 (size (widget-value widget)))
826 (cons (w3-form-element-name formobj)
827 (ssl-req-user-cert size challenge))))
829 (cons (w3-form-element-name formobj)
830 (w3-form-element-value formobj)))
832 (cons (w3-form-element-name formobj)
833 (widget-value widget)))))
835 (setq result (cons temp result))))
838 (defun w3-form-encode-make-mime-part (id data separator)
842 (setq addons (mapconcat (lambda (x)
843 (format "; %s=\"%s\"" (car x) (cdr x)))
845 (setq data (cdr data)))
847 (format "%s\r\nContent-Disposition: form-data; name=\"%s\"%s\r\n\r\n%s"
848 separator id addons data)))
850 (defun w3-form-encode-multipart/x-www-form-data (formobjs)
851 ;; Create a multipart form submission.
852 ;; Returns a cons of two strings. Car is the separator used.
853 ;; cdr is the body of the MIME message."
854 (let ((separator (format-time-string "---separator-%Y%j%H%M%S-for-www-form-data")))
860 (w3-form-encode-make-mime-part (car formobj) (cdr formobj)
862 (w3-form-encode-helper formobjs)
864 "\r\n" separator "--\r\n"))))
866 (fset 'w3-form-encode-multipart/form-data
867 'w3-form-encode-multipart/x-www-form-data)
868 (fset 'w3-form-encode- 'w3-form-encode-application/x-www-form-urlencoded)
870 (defun w3-form-encode (result &optional enctype)
871 "Create a string suitably encoded for a URL request."
872 (let ((func (intern (concat "w3-form-encode-" enctype))))
874 (funcall func result)
875 (w3-warn 'html (format "Bad encoding type for form data: %s" enctype))
876 (w3-form-encode-application/x-www-form-urlencoded result))))
878 (defun w3-form-encode-text/plain (result)
884 (let ((nam (car widget))
886 (if (string-match "\n" nam)
890 (if (= x ?\n) "," (char-to-string x))))
892 (concat nam " " val))))
893 (w3-form-encode-helper result) "\n"))
896 ;; Fixme: check the charset issues on form submission
897 ;; http://ppewww.ph.gla.ac.uk/%7Eflavell/charset/form-i18n.html
899 (defun w3-form-encode-xwfu (chunk)
900 "Escape characters in a string for application/x-www-form-urlencoded.
901 Blasphemous crap because someone didn't think %20 was good enough for encoding
902 spaces. Die Die Die."
903 ;; This will get rid of the 'attributes' specified by the file type,
904 ;; which are useless for an application/x-www-form-urlencoded form.
906 (setq chunk (cdr chunk)))
912 ((memq char url-unreserved-chars) (char-to-string char))
913 (t (upcase (format "%%%02x" char)))))
914 ;; Fixme: Should this actually be accepting multibyte? Is there a
915 ;; better way in XEmacs?
917 (encode-coding-string chunk
918 (if (fboundp 'find-coding-systems-string)
919 (car (find-coding-systems-string chunk))
920 buffer-file-coding-system))
924 (defun w3-form-encode-application/x-www-form-urlencoded (result)
928 (concat (w3-form-encode-xwfu (car data)) "="
929 (w3-form-encode-xwfu (cdr data)))))
930 (w3-form-encode-helper result) "&"))
932 (defun w3-form-encode-application/x-w3-isindex (result)
933 (let* ((info (w3-form-encode-helper result))
934 (query (cdr-safe (assoc "isindex" info))))
936 (url-hexify-string query)
939 (defun w3-submit-form (ident)
940 ;; Submit form entry fields matching ACTN as their action identifier.
941 (let* ((result (w3-all-widgets ident))
942 (enctype (or (cdr (assq 'enctype ident))
943 "application/x-www-form-urlencoded"))
944 (query (w3-form-encode result enctype))
945 (themeth (upcase (or (cdr (assq 'method ident)) "get")))
946 (theurl (cdr (assq 'action ident))))
947 (if (and (string= "GET" themeth)
948 (string-match "\\([^\\?]*\\)\\?" theurl))
949 (setq theurl (match-string 1 theurl)))
951 ((or (string= "POST" themeth)
952 (string= "PUT" themeth))
954 (setq enctype (concat enctype "; boundary="
955 (substring (car query) 2 nil)
958 (let ((url-request-method themeth)
959 (url-request-data query)
960 (url-request-extra-headers
961 (cons (cons "Content-type" enctype) url-request-extra-headers)))
963 ((string= "GET" themeth)
964 (let ((theurl (concat theurl "?" query)))
967 (w3-warn 'html (format "Unknown submit method: %s" themeth))
968 (let ((theurl (concat theurl "?" query)))
969 (w3-fetch theurl))))))