aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenjiro NAKAYAMA2014-11-10 22:33:55 +0100
committerLars Magne Ingebrigtsen2014-11-10 22:33:55 +0100
commitfca2f70380dcb054497470aaf8eda6173063928e (patch)
treeaf195d71b9833dc0e47488aa7402bd541330cad0
parent14fe3679c9b26b29872525c85f3278ecb50c8eac (diff)
downloademacs-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/ChangeLog10
-rw-r--r--lisp/gnus/ChangeLog5
-rw-r--r--lisp/gnus/mm-url.el42
-rw-r--r--lisp/net/eww.el107
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 @@
12014-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
12014-11-10 Lars Magne Ingebrigtsen <larsi@gnus.org> 112014-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 @@
12014-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
12014-11-07 Tassilo Horn <tsdh@gnu.org> 62014-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))