diff options
author | Kenjiro NAKAYAMA <nakayamakenjiro@gmail.com> | 2014-11-10 22:33:55 +0100 |
---|---|---|
committer | Lars Magne Ingebrigtsen <larsi@gnus.org> | 2014-11-10 22:33:55 +0100 |
commit | fca2f70380dcb054497470aaf8eda6173063928e (patch) | |
tree | af195d71b9833dc0e47488aa7402bd541330cad0 | |
parent | 14fe3679c9b26b29872525c85f3278ecb50c8eac (diff) | |
download | emacs-fca2f70380dcb054497470aaf8eda6173063928e.tar.gz |
Allow uploading files from eww
2014-11-10 Kenjiro NAKAYAMA <nakayamakenjiro@gmail.com>
* net/eww.el(eww-form-file(defface)): New defface of file upload form.
(eww-submit-file): New key map of file upload.
(eww-form-file): New file upload button and file name context.
(eww-select-file): Select file and display selected file name.
(eww-tag-input): Handle input tag of file type.
(eww-update-field): Add point offset.
(eww-submit): Add submit with multipart/form-data.
* gnus/mm-url.el (mm-url-encode-multipart-form-data):
Restore to handle "multipart/form-data" by eww.
-rw-r--r-- | lisp/ChangeLog | 10 | ||||
-rw-r--r-- | lisp/gnus/ChangeLog | 5 | ||||
-rw-r--r-- | lisp/gnus/mm-url.el | 42 | ||||
-rw-r--r-- | lisp/net/eww.el | 107 |
4 files changed, 148 insertions, 16 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index efa44b009cb..c70f56f2f99 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,13 @@ +2014-11-10 Kenjiro NAKAYAMA <nakayamakenjiro@gmail.com> + + * net/eww.el(eww-form-file(defface)): New defface of file upload form. + (eww-submit-file): New key map of file upload. + (eww-form-file): New file upload button and file name context. + (eww-select-file): Select file and display selected file name. + (eww-tag-input): Handle input tag of file type. + (eww-update-field): Add point offset. + (eww-submit): Add submit with multipart/form-data. + 2014-11-10 Lars Magne Ingebrigtsen <larsi@gnus.org> * net/eww.el (eww-render, eww-display-html, eww-setup-buffer): diff --git a/lisp/gnus/ChangeLog b/lisp/gnus/ChangeLog index f0126a26c91..18588ebc35c 100644 --- a/lisp/gnus/ChangeLog +++ b/lisp/gnus/ChangeLog @@ -1,3 +1,8 @@ +2014-11-10 Kenjiro NAKAYAMA <nakayamakenjiro@gmail.com> + + * gnus/mm-url.el (mm-url-encode-multipart-form-data): + Restore to handle "multipart/form-data" by eww. + 2014-11-07 Tassilo Horn <tsdh@gnu.org> * gnus-start.el (gnus-activate-group): Fix typo reported by Tim diff --git a/lisp/gnus/mm-url.el b/lisp/gnus/mm-url.el index bb342d6b8b1..bbeb1d85374 100644 --- a/lisp/gnus/mm-url.el +++ b/lisp/gnus/mm-url.el @@ -414,13 +414,51 @@ spaces. Die Die Die." (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))) diff --git a/lisp/net/eww.el b/lisp/net/eww.el index b867134db00..306d5dca507 100644 --- a/lisp/net/eww.el +++ b/lisp/net/eww.el @@ -100,6 +100,15 @@ See also `eww-form-checkbox-selected-symbol'." :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) @@ -653,6 +662,12 @@ appears in a <link> or <a> tag." (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) @@ -763,6 +778,34 @@ appears in a <link> or <a> tag." (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)) @@ -879,6 +922,8 @@ See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.") ((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") @@ -971,14 +1016,17 @@ See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.") (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 () @@ -1046,8 +1094,8 @@ See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.") (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))) @@ -1057,6 +1105,16 @@ See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.") (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 @@ -1079,12 +1137,33 @@ See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.") 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)) |