1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
(* Js_of_ocaml library
* http://www.ocsigen.org/js_of_ocaml/
* Copyright (C) 2011 Pierre Chambart
* Laboratoire PPS - CNRS Université Paris Diderot
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, with linking exception;
* either version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*)
open Js
open Dom_html
open! Import
class type formData = object
method append : js_string t -> js_string t -> unit meth
method append_blob : js_string t -> File.blob t -> unit meth
end
let formData : formData t constr = Js.Unsafe.global##._FormData
let formData_form : (formElement t -> formData t) constr = Js.Unsafe.global##._FormData
type form_elt =
[ `String of js_string t
| `File of File.file t
]
type form_contents =
[ `Fields of (string * form_elt) list ref
| `FormData of formData t
]
let rec filter_map f = function
| [] -> []
| v :: q -> (
match f v with
| None -> filter_map f q
| Some v' -> v' :: filter_map f q)
class type submittableElement = object
method disabled : bool t prop
method name : js_string t readonly_prop
method value : js_string t prop
end
let have_content (elt : submittableElement t) =
elt##.name##.length > 0 && not (Js.to_bool elt##.disabled)
let get_textarea_val (elt : textAreaElement t) =
if have_content (elt :> submittableElement t)
then
let name = to_string elt##.name in
[ name, `String elt##.value ]
else []
let get_select_val (elt : selectElement t) =
if have_content (elt :> submittableElement t)
then
let name = to_string elt##.name in
if to_bool elt##.multiple
then
let options =
Array.init elt##.options##.length (fun i -> Opt.to_option (elt##.options##item i))
in
filter_map
(function
| None -> None
| Some e ->
if Js.to_bool e##.selected then Some (name, `String e##.value) else None)
(Array.to_list options)
else [ name, `String elt##.value ]
else []
class type file_input = object
inherit inputElement
method files : File.fileList t readonly_prop
method multiple : bool optdef readonly_prop
end
let get_input_val ?(get = false) (elt : inputElement t) =
if have_content (elt :> submittableElement t)
then
let name = to_string elt##.name in
let value = elt##.value in
match to_bytestring elt##._type##toLowerCase with
| "checkbox" | "radio" ->
if to_bool elt##.checked then [ name, `String value ] else []
| "submit" | "reset" -> []
| "text" | "password" -> [ name, `String value ]
| "file" -> (
if get
then [ name, `String value ]
else
let elt : file_input t = Unsafe.coerce elt in
let list = elt##.files in
if list##.length = 0
then [ name, `String (Js.string "") ]
else
match Optdef.to_option elt##.multiple with
| None | Some false -> (
match Opt.to_option (list##item 0) with
| None -> []
| Some file -> [ name, `File file ])
| Some true ->
filter_map
(fun f ->
match Opt.to_option f with
| None -> None
| Some file -> Some (name, `File file))
(Array.to_list (Array.init list##.length (fun i -> list##item i))))
| _ -> [ name, `String value ]
else []
let get_form_elements (form : formElement t) =
let rec loop acc i =
if i < 0
then acc
else
match Opt.to_option (form##.elements##item i) with
| None -> loop acc (i - i)
| Some x -> loop (x :: acc) (i - 1)
in
loop [] (form##.elements##.length - 1)
let get_element_content ?get v =
match tagged v with
| Select v -> get_select_val v
| Input v -> get_input_val ?get v
| Textarea v -> get_textarea_val v
| _ -> []
let form_elements ?get (form : formElement t) =
List.flatten (List.map (fun v -> get_element_content ?get v) (get_form_elements form))
let append (form_contents : form_contents) (form_elt : string * form_elt) =
match form_contents with
| `Fields list -> list := form_elt :: !list
| `FormData f -> (
match form_elt with
| name, `String s -> f##append (string name) s
| name, `File file -> f##append_blob (string name) (file :> File.blob t))
let empty_form_contents () =
match Optdef.to_option (Js.def formData) with
| None -> `Fields (ref [])
| Some constr -> `FormData (new%js constr)
let post_form_contents form =
let contents = empty_form_contents () in
List.iter (append contents) (form_elements form);
contents
let get_form_contents form =
List.map
(function
| name, `String s -> name, to_string s
| _ -> assert false)
(form_elements ~get:true form)
|