diff options
| author | Kenjiro NAKAYAMA | 2014-11-10 22:33:55 +0100 |
|---|---|---|
| committer | Lars Magne Ingebrigtsen | 2014-11-10 22:33:55 +0100 |
| commit | fca2f70380dcb054497470aaf8eda6173063928e (patch) | |
| tree | af195d71b9833dc0e47488aa7402bd541330cad0 | |
| parent | 14fe3679c9b26b29872525c85f3278ecb50c8eac (diff) | |
| download | emacs-fca2f70380dcb054497470aaf8eda6173063928e.tar.gz emacs-fca2f70380dcb054497470aaf8eda6173063928e.zip | |
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 @@ | |||
| 1 | 2014-11-10 Kenjiro NAKAYAMA <nakayamakenjiro@gmail.com> | ||
| 2 | |||
| 3 | * net/eww.el(eww-form-file(defface)): New defface of file upload form. | ||
| 4 | (eww-submit-file): New key map of file upload. | ||
| 5 | (eww-form-file): New file upload button and file name context. | ||
| 6 | (eww-select-file): Select file and display selected file name. | ||
| 7 | (eww-tag-input): Handle input tag of file type. | ||
| 8 | (eww-update-field): Add point offset. | ||
| 9 | (eww-submit): Add submit with multipart/form-data. | ||
| 10 | |||
| 1 | 2014-11-10 Lars Magne Ingebrigtsen <larsi@gnus.org> | 11 | 2014-11-10 Lars Magne Ingebrigtsen <larsi@gnus.org> |
| 2 | 12 | ||
| 3 | * net/eww.el (eww-render, eww-display-html, eww-setup-buffer): | 13 | * 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 @@ | |||
| 1 | 2014-11-10 Kenjiro NAKAYAMA <nakayamakenjiro@gmail.com> | ||
| 2 | |||
| 3 | * gnus/mm-url.el (mm-url-encode-multipart-form-data): | ||
| 4 | Restore to handle "multipart/form-data" by eww. | ||
| 5 | |||
| 1 | 2014-11-07 Tassilo Horn <tsdh@gnu.org> | 6 | 2014-11-07 Tassilo Horn <tsdh@gnu.org> |
| 2 | 7 | ||
| 3 | * gnus-start.el (gnus-activate-group): Fix typo reported by Tim | 8 | * 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." | |||
| 414 | 414 | ||
| 415 | (autoload 'mml-compute-boundary "mml") | 415 | (autoload 'mml-compute-boundary "mml") |
| 416 | 416 | ||
| 417 | (defun mm-url-encode-multipart-form-data (pairs &optional boundary) | ||
| 418 | "Return PAIRS encoded in multipart/form-data." | ||
| 419 | ;; RFC1867 | ||
| 420 | ;; Get a good boundary | ||
| 421 | (unless boundary | ||
| 422 | (setq boundary (mml-compute-boundary '()))) | ||
| 423 | (concat | ||
| 424 | ;; Start with the boundary | ||
| 425 | "--" boundary "\r\n" | ||
| 426 | ;; Create name value pairs | ||
| 427 | (mapconcat | ||
| 428 | 'identity | ||
| 429 | ;; Delete any returned items that are empty | ||
| 430 | (delq nil | ||
| 431 | (mapcar (lambda (data) | ||
| 432 | (cond ((equal (car data) "file") | ||
| 433 | ;; For each pair | ||
| 434 | (format | ||
| 435 | ;; Encode the name | ||
| 436 | "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" | ||
| 437 | (cdr (assoc "name" (cdr data))) (cdr (assoc "filename" (cdr data))) | ||
| 438 | (cond ((stringp (cdr (assoc "filedata" (cdr data)))) | ||
| 439 | (cdr (assoc "filedata" (cdr data)))) | ||
| 440 | ((integerp (cdr (assoc "filedata" (cdr data)))) | ||
| 441 | (number-to-string (cdr (assoc "filedata" (cdr data)))))))) | ||
| 442 | ((equal (car data) "submit") | ||
| 443 | "Content-Disposition: form-data; name=\"submit\"\r\n\r\nSubmit\r\n") | ||
| 444 | (t | ||
| 445 | (format | ||
| 446 | "Content-Disposition: form-data;name=%S\r\n\r\n%s\r\n" | ||
| 447 | (car data) (concat (mm-url-form-encode-xwfu (cdr data))) | ||
| 448 | )))) | ||
| 449 | pairs)) | ||
| 450 | ;; use the boundary as a separator | ||
| 451 | (concat "\r\n--" boundary "\r\n")) | ||
| 452 | ;; put a boundary at the end. | ||
| 453 | "--" boundary "--\r\n")) | ||
| 454 | |||
| 417 | (defun mm-url-remove-markup () | 455 | (defun mm-url-remove-markup () |
| 418 | "Remove all HTML markup, leaving just plain text." | 456 | "Remove all HTML markup, leaving just plain text." |
| 419 | (goto-char (point-min)) | 457 | (goto-char (point-min)) |
| 420 | (while (search-forward "<!--" nil t) | 458 | (while (search-forward "<!--" nil t) |
| 421 | (delete-region (match-beginning 0) | 459 | (delete-region (match-beginning 0) |
| 422 | (or (search-forward "-->" nil t) | 460 | (or (search-forward "-->" nil t) |
| 423 | (point-max)))) | 461 | (point-max)))) |
| 424 | (goto-char (point-min)) | 462 | (goto-char (point-min)) |
| 425 | (while (re-search-forward "<[^>]+>" nil t) | 463 | (while (re-search-forward "<[^>]+>" nil t) |
| 426 | (replace-match "" t t))) | 464 | (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'." | |||
| 100 | :version "24.4" | 100 | :version "24.4" |
| 101 | :group 'eww) | 101 | :group 'eww) |
| 102 | 102 | ||
| 103 | (defface eww-form-file | ||
| 104 | '((((type x w32 ns) (class color)) ; Like default mode line | ||
| 105 | :box (:line-width 2 :style released-button) | ||
| 106 | :background "#808080" :foreground "black")) | ||
| 107 | "Face for eww buffer buttons." | ||
| 108 | :version "24.4" | ||
| 109 | :group 'eww | ||
| 110 | :type "Browse") | ||
| 111 | |||
| 103 | (defface eww-form-checkbox | 112 | (defface eww-form-checkbox |
| 104 | '((((type x w32 ns) (class color)) ; Like default mode line | 113 | '((((type x w32 ns) (class color)) ; Like default mode line |
| 105 | :box (:line-width 2 :style released-button) | 114 | :box (:line-width 2 :style released-button) |
| @@ -653,6 +662,12 @@ appears in a <link> or <a> tag." | |||
| 653 | (define-key map [(control c) (control c)] 'eww-submit) | 662 | (define-key map [(control c) (control c)] 'eww-submit) |
| 654 | map)) | 663 | map)) |
| 655 | 664 | ||
| 665 | (defvar eww-submit-file | ||
| 666 | (let ((map (make-sparse-keymap))) | ||
| 667 | (define-key map "\r" 'eww-select-file) | ||
| 668 | (define-key map [(control c) (control c)] 'eww-submit) | ||
| 669 | map)) | ||
| 670 | |||
| 656 | (defvar eww-checkbox-map | 671 | (defvar eww-checkbox-map |
| 657 | (let ((map (make-sparse-keymap))) | 672 | (let ((map (make-sparse-keymap))) |
| 658 | (define-key map " " 'eww-toggle-checkbox) | 673 | (define-key map " " 'eww-toggle-checkbox) |
| @@ -763,6 +778,34 @@ appears in a <link> or <a> tag." | |||
| 763 | (put-text-property start (point) 'keymap eww-checkbox-map) | 778 | (put-text-property start (point) 'keymap eww-checkbox-map) |
| 764 | (insert " "))) | 779 | (insert " "))) |
| 765 | 780 | ||
| 781 | (defun eww-form-file (cont) | ||
| 782 | (let ((start (point)) | ||
| 783 | (value (cdr (assq :value cont)))) | ||
| 784 | (setq value | ||
| 785 | (if (zerop (length value)) | ||
| 786 | " No file selected" | ||
| 787 | value)) | ||
| 788 | (insert "Browse") | ||
| 789 | (add-face-text-property start (point) 'eww-form-file) | ||
| 790 | (insert value) | ||
| 791 | (put-text-property start (point) 'eww-form | ||
| 792 | (list :eww-form eww-form | ||
| 793 | :value (cdr (assq :value cont)) | ||
| 794 | :type (downcase (cdr (assq :type cont))) | ||
| 795 | :name (cdr (assq :name cont)))) | ||
| 796 | (put-text-property start (point) 'keymap eww-submit-file) | ||
| 797 | (insert " "))) | ||
| 798 | |||
| 799 | (defun eww-select-file () | ||
| 800 | "Change the value of the upload file menu under point." | ||
| 801 | (interactive) | ||
| 802 | (let* ((input (get-text-property (point) 'eww-form))) | ||
| 803 | (let ((filename | ||
| 804 | (let ((insert-default-directory t)) | ||
| 805 | (read-file-name "filename: ")))) | ||
| 806 | (eww-update-field filename (length "Browse")) | ||
| 807 | (plist-put input :filename filename)))) | ||
| 808 | |||
| 766 | (defun eww-form-text (cont) | 809 | (defun eww-form-text (cont) |
| 767 | (let ((start (point)) | 810 | (let ((start (point)) |
| 768 | (type (downcase (or (cdr (assq :type cont)) | 811 | (type (downcase (or (cdr (assq :type cont)) |
| @@ -879,6 +922,8 @@ See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.") | |||
| 879 | ((or (equal type "checkbox") | 922 | ((or (equal type "checkbox") |
| 880 | (equal type "radio")) | 923 | (equal type "radio")) |
| 881 | (eww-form-checkbox cont)) | 924 | (eww-form-checkbox cont)) |
| 925 | ((equal type "file") | ||
| 926 | (eww-form-file cont)) | ||
| 882 | ((equal type "submit") | 927 | ((equal type "submit") |
| 883 | (eww-form-submit cont)) | 928 | (eww-form-submit cont)) |
| 884 | ((equal type "hidden") | 929 | ((equal type "hidden") |
| @@ -971,14 +1016,17 @@ See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.") | |||
| 971 | (goto-char | 1016 | (goto-char |
| 972 | (eww-update-field display)))) | 1017 | (eww-update-field display)))) |
| 973 | 1018 | ||
| 974 | (defun eww-update-field (string) | 1019 | (defun eww-update-field (string &optional offset) |
| 1020 | (if (not offset) (setq offset 0)) | ||
| 975 | (let ((properties (text-properties-at (point))) | 1021 | (let ((properties (text-properties-at (point))) |
| 976 | (start (eww-beginning-of-field)) | 1022 | (start (+ (eww-beginning-of-field) offset)) |
| 977 | (end (1+ (eww-end-of-field)))) | 1023 | (current-end (1+ (eww-end-of-field))) |
| 978 | (delete-region start end) | 1024 | (new-end (1+ (+ (eww-beginning-of-field) (length string))))) |
| 1025 | (delete-region start current-end) | ||
| 1026 | (forward-char offset) | ||
| 979 | (insert string | 1027 | (insert string |
| 980 | (make-string (- (- end start) (length string)) ? )) | 1028 | (make-string (- (- (+ new-end offset) start) (length string)) ? )) |
| 981 | (set-text-properties start end properties) | 1029 | (if (= 0 offset) (set-text-properties start new-end properties)) |
| 982 | start)) | 1030 | start)) |
| 983 | 1031 | ||
| 984 | (defun eww-toggle-checkbox () | 1032 | (defun eww-toggle-checkbox () |
| @@ -1046,8 +1094,8 @@ See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.") | |||
| 1046 | (form (plist-get this-input :eww-form)) | 1094 | (form (plist-get this-input :eww-form)) |
| 1047 | values next-submit) | 1095 | values next-submit) |
| 1048 | (dolist (elem (sort (eww-inputs form) | 1096 | (dolist (elem (sort (eww-inputs form) |
| 1049 | (lambda (o1 o2) | 1097 | (lambda (o1 o2) |
| 1050 | (< (car o1) (car o2))))) | 1098 | (< (car o1) (car o2))))) |
| 1051 | (let* ((input (cdr elem)) | 1099 | (let* ((input (cdr elem)) |
| 1052 | (input-start (car elem)) | 1100 | (input-start (car elem)) |
| 1053 | (name (plist-get input :name))) | 1101 | (name (plist-get input :name))) |
| @@ -1057,6 +1105,16 @@ See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.") | |||
| 1057 | (when (plist-get input :checked) | 1105 | (when (plist-get input :checked) |
| 1058 | (push (cons name (plist-get input :value)) | 1106 | (push (cons name (plist-get input :value)) |
| 1059 | values))) | 1107 | values))) |
| 1108 | ((equal (plist-get input :type) "file") | ||
| 1109 | (push (cons "file" | ||
| 1110 | (list (cons "filedata" | ||
| 1111 | (with-temp-buffer | ||
| 1112 | (insert-file-contents | ||
| 1113 | (plist-get input :filename)) | ||
| 1114 | (buffer-string))) | ||
| 1115 | (cons "name" (plist-get input :name)) | ||
| 1116 | (cons "filename" (plist-get input :filename)))) | ||
| 1117 | values)) | ||
| 1060 | ((equal (plist-get input :type) "submit") | 1118 | ((equal (plist-get input :type) "submit") |
| 1061 | ;; We want the values from buttons if we hit a button if | 1119 | ;; We want the values from buttons if we hit a button if |
| 1062 | ;; we hit enter on it, or if it's the first button after | 1120 | ;; 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'.") | |||
| 1079 | values))) | 1137 | values))) |
| 1080 | (if (and (stringp (cdr (assq :method form))) | 1138 | (if (and (stringp (cdr (assq :method form))) |
| 1081 | (equal (downcase (cdr (assq :method form))) "post")) | 1139 | (equal (downcase (cdr (assq :method form))) "post")) |
| 1082 | (let ((url-request-method "POST") | 1140 | (let ((mtype)) |
| 1083 | (url-request-extra-headers | 1141 | (dolist (x values mtype) |
| 1084 | '(("Content-Type" . "application/x-www-form-urlencoded"))) | 1142 | (if (equal (car x) "file") |
| 1085 | (url-request-data (mm-url-encode-www-form-urlencoded values))) | 1143 | (progn |
| 1086 | (eww-browse-url (shr-expand-url (cdr (assq :action form)) | 1144 | (setq mtype "multipart/form-data")))) |
| 1087 | (plist-get eww-data :url)))) | 1145 | (cond ((equal mtype "multipart/form-data") |
| 1146 | (let ((boundary (mml-compute-boundary '()))) | ||
| 1147 | (let ((url-request-method "POST") | ||
| 1148 | (url-request-extra-headers | ||
| 1149 | (list (cons "Content-Type" | ||
| 1150 | (concat "multipart/form-data; boundary=" | ||
| 1151 | boundary)))) | ||
| 1152 | (url-request-data | ||
| 1153 | (mm-url-encode-multipart-form-data values boundary))) | ||
| 1154 | (eww-browse-url (shr-expand-url | ||
| 1155 | (cdr (assq :action form)) | ||
| 1156 | (plist-get eww-data :url)))))) | ||
| 1157 | (t | ||
| 1158 | (let ((url-request-method "POST") | ||
| 1159 | (url-request-extra-headers | ||
| 1160 | '(("Content-Type" . | ||
| 1161 | "application/x-www-form-urlencoded"))) | ||
| 1162 | (url-request-data | ||
| 1163 | (mm-url-encode-www-form-urlencoded values))) | ||
| 1164 | (eww-browse-url (shr-expand-url | ||
| 1165 | (cdr (assq :action form)) | ||
| 1166 | (plist-get eww-data :url))))))) | ||
| 1088 | (eww-browse-url | 1167 | (eww-browse-url |
| 1089 | (concat | 1168 | (concat |
| 1090 | (if (cdr (assq :action form)) | 1169 | (if (cdr (assq :action form)) |