(autoload 'mml-compute-boundary "mml")
+(defun mm-url-encode-multipart-form-data (pairs &optional boundary)
+ "Return PAIRS encoded in multipart/form-data."
+ ;; RFC1867
+ ;; Get a good boundary
+ (unless boundary
+ (setq boundary (mml-compute-boundary '())))
+ (concat
+ ;; Start with the boundary
+ "--" boundary "\r\n"
+ ;; Create name value pairs
+ (mapconcat
+ 'identity
+ ;; Delete any returned items that are empty
+ (delq nil
+ (mapcar (lambda (data)
+ (cond ((equal (car data) "file")
+ ;; For each pair
+ (format
+ ;; Encode the name
+ "Content-Disposition: form-data; name=%S; filename=%S\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Transfer-Encoding: binary\r\n\r\n%s"
+ (cdr (assoc "name" (cdr data))) (cdr (assoc "filename" (cdr data)))
+ (cond ((stringp (cdr (assoc "filedata" (cdr data))))
+ (cdr (assoc "filedata" (cdr data))))
+ ((integerp (cdr (assoc "filedata" (cdr data))))
+ (number-to-string (cdr (assoc "filedata" (cdr data))))))))
+ ((equal (car data) "submit")
+ "Content-Disposition: form-data; name=\"submit\"\r\n\r\nSubmit\r\n")
+ (t
+ (format
+ "Content-Disposition: form-data;name=%S\r\n\r\n%s\r\n"
+ (car data) (concat (mm-url-form-encode-xwfu (cdr data)))
+ ))))
+ pairs))
+ ;; use the boundary as a separator
+ (concat "\r\n--" boundary "\r\n"))
+ ;; put a boundary at the end.
+ "--" boundary "--\r\n"))
+
(defun mm-url-remove-markup ()
"Remove all HTML markup, leaving just plain text."
(goto-char (point-min))
(while (search-forward "<!--" nil t)
(delete-region (match-beginning 0)
- (or (search-forward "-->" nil t)
- (point-max))))
+ (or (search-forward "-->" nil t)
+ (point-max))))
(goto-char (point-min))
(while (re-search-forward "<[^>]+>" nil t)
(replace-match "" t t)))
:version "24.4"
:group 'eww)
+(defface eww-form-file
+ '((((type x w32 ns) (class color)) ; Like default mode line
+ :box (:line-width 2 :style released-button)
+ :background "#808080" :foreground "black"))
+ "Face for eww buffer buttons."
+ :version "24.4"
+ :group 'eww
+ :type "Browse")
+
(defface eww-form-checkbox
'((((type x w32 ns) (class color)) ; Like default mode line
:box (:line-width 2 :style released-button)
(define-key map [(control c) (control c)] 'eww-submit)
map))
+(defvar eww-submit-file
+ (let ((map (make-sparse-keymap)))
+ (define-key map "\r" 'eww-select-file)
+ (define-key map [(control c) (control c)] 'eww-submit)
+ map))
+
(defvar eww-checkbox-map
(let ((map (make-sparse-keymap)))
(define-key map " " 'eww-toggle-checkbox)
(put-text-property start (point) 'keymap eww-checkbox-map)
(insert " ")))
+(defun eww-form-file (cont)
+ (let ((start (point))
+ (value (cdr (assq :value cont))))
+ (setq value
+ (if (zerop (length value))
+ " No file selected"
+ value))
+ (insert "Browse")
+ (add-face-text-property start (point) 'eww-form-file)
+ (insert value)
+ (put-text-property start (point) 'eww-form
+ (list :eww-form eww-form
+ :value (cdr (assq :value cont))
+ :type (downcase (cdr (assq :type cont)))
+ :name (cdr (assq :name cont))))
+ (put-text-property start (point) 'keymap eww-submit-file)
+ (insert " ")))
+
+(defun eww-select-file ()
+ "Change the value of the upload file menu under point."
+ (interactive)
+ (let* ((input (get-text-property (point) 'eww-form)))
+ (let ((filename
+ (let ((insert-default-directory t))
+ (read-file-name "filename: "))))
+ (eww-update-field filename (length "Browse"))
+ (plist-put input :filename filename))))
+
(defun eww-form-text (cont)
(let ((start (point))
(type (downcase (or (cdr (assq :type cont))
((or (equal type "checkbox")
(equal type "radio"))
(eww-form-checkbox cont))
+ ((equal type "file")
+ (eww-form-file cont))
((equal type "submit")
(eww-form-submit cont))
((equal type "hidden")
(goto-char
(eww-update-field display))))
-(defun eww-update-field (string)
+(defun eww-update-field (string &optional offset)
+ (if (not offset) (setq offset 0))
(let ((properties (text-properties-at (point)))
- (start (eww-beginning-of-field))
- (end (1+ (eww-end-of-field))))
- (delete-region start end)
+ (start (+ (eww-beginning-of-field) offset))
+ (current-end (1+ (eww-end-of-field)))
+ (new-end (1+ (+ (eww-beginning-of-field) (length string)))))
+ (delete-region start current-end)
+ (forward-char offset)
(insert string
- (make-string (- (- end start) (length string)) ? ))
- (set-text-properties start end properties)
+ (make-string (- (- (+ new-end offset) start) (length string)) ? ))
+ (if (= 0 offset) (set-text-properties start new-end properties))
start))
(defun eww-toggle-checkbox ()
(form (plist-get this-input :eww-form))
values next-submit)
(dolist (elem (sort (eww-inputs form)
- (lambda (o1 o2)
- (< (car o1) (car o2)))))
+ (lambda (o1 o2)
+ (< (car o1) (car o2)))))
(let* ((input (cdr elem))
(input-start (car elem))
(name (plist-get input :name)))
(when (plist-get input :checked)
(push (cons name (plist-get input :value))
values)))
+ ((equal (plist-get input :type) "file")
+ (push (cons "file"
+ (list (cons "filedata"
+ (with-temp-buffer
+ (insert-file-contents
+ (plist-get input :filename))
+ (buffer-string)))
+ (cons "name" (plist-get input :name))
+ (cons "filename" (plist-get input :filename))))
+ values))
((equal (plist-get input :type) "submit")
;; We want the values from buttons if we hit a button if
;; we hit enter on it, or if it's the first button after
values)))
(if (and (stringp (cdr (assq :method form)))
(equal (downcase (cdr (assq :method form))) "post"))
- (let ((url-request-method "POST")
- (url-request-extra-headers
- '(("Content-Type" . "application/x-www-form-urlencoded")))
- (url-request-data (mm-url-encode-www-form-urlencoded values)))
- (eww-browse-url (shr-expand-url (cdr (assq :action form))
- (plist-get eww-data :url))))
+ (let ((mtype))
+ (dolist (x values mtype)
+ (if (equal (car x) "file")
+ (progn
+ (setq mtype "multipart/form-data"))))
+ (cond ((equal mtype "multipart/form-data")
+ (let ((boundary (mml-compute-boundary '())))
+ (let ((url-request-method "POST")
+ (url-request-extra-headers
+ (list (cons "Content-Type"
+ (concat "multipart/form-data; boundary="
+ boundary))))
+ (url-request-data
+ (mm-url-encode-multipart-form-data values boundary)))
+ (eww-browse-url (shr-expand-url
+ (cdr (assq :action form))
+ (plist-get eww-data :url))))))
+ (t
+ (let ((url-request-method "POST")
+ (url-request-extra-headers
+ '(("Content-Type" .
+ "application/x-www-form-urlencoded")))
+ (url-request-data
+ (mm-url-encode-www-form-urlencoded values)))
+ (eww-browse-url (shr-expand-url
+ (cdr (assq :action form))
+ (plist-get eww-data :url)))))))
(eww-browse-url
(concat
(if (cdr (assq :action form))