/
form.clj
137 lines (117 loc) · 3.96 KB
/
form.clj
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
(ns hiccup.form
"Functions for generating HTML forms and input fields."
(:require [hiccup.def :refer [defelem]]
[hiccup.util :as util]))
(def ^:dynamic ^:no-doc *group* [])
(defmacro with-group
"Group together a set of related form fields for use with the Ring
nested-params middleware."
[group & body]
`(binding [*group* (conj *group* (util/as-str ~group))]
(list ~@body)))
(defn- make-name
"Create a field name from the supplied argument the current field group."
[name]
(reduce #(str %1 "[" %2 "]")
(conj *group* (util/as-str name))))
(defn- make-id
"Create a field id from the supplied argument and current field group."
[name]
(reduce #(str %1 "-" %2)
(conj *group* (util/as-str name))))
(defn- input-field
"Creates a new <input> element."
[type name value]
[:input {:type type
:name (make-name name)
:id (make-id name)
:value value}])
(defelem hidden-field
"Creates a hidden input field."
([name] (hidden-field name nil))
([name value] (input-field "hidden" name value)))
(defelem text-field
"Creates a new text input field."
([name] (text-field name nil))
([name value] (input-field "text" name value)))
(defelem password-field
"Creates a new password field."
([name] (password-field name nil))
([name value] (input-field "password" name value)))
(defelem email-field
"Creates a new email input field."
([name] (email-field name nil))
([name value] (input-field "email" name value)))
(defelem check-box
"Creates a check box."
([name] (check-box name nil))
([name checked?] (check-box name checked? "true"))
([name checked? value]
[:input {:type "checkbox"
:name (make-name name)
:id (make-id name)
:value value
:checked checked?}]))
(defelem radio-button
"Creates a radio button."
([group] (radio-button group nil))
([group checked?] (radio-button group checked? "true"))
([group checked? value]
[:input {:type "radio"
:name (make-name group)
:id (make-id (str (util/as-str group) "-" (util/as-str value)))
:value value
:checked checked?}]))
(defelem select-options
"Creates a seq of option tags from a collection."
([coll] (select-options coll nil))
([coll selected]
(for [x coll]
(if (sequential? x)
(let [[text val] x]
(if (sequential? val)
[:optgroup {:label text} (select-options val selected)]
[:option {:value val :selected (= val selected)} text]))
[:option {:selected (= x selected)} x]))))
(defelem drop-down
"Creates a drop-down box using the `<select>` tag."
([name options] (drop-down name options nil))
([name options selected]
[:select {:name (make-name name), :id (make-id name)}
(select-options options selected)]))
(defelem text-area
"Creates a text area element."
([name] (text-area name nil))
([name value]
[:textarea {:name (make-name name), :id (make-id name)}
(-> value util/escape-html util/raw-string)]))
(defelem file-upload
"Creates a file upload input."
[name]
(input-field "file" name nil))
(defelem label
"Creates a label for an input field with the supplied name."
[name text]
[:label {:for (make-id name)} text])
(defelem submit-button
"Creates a submit button."
[text]
[:input {:type "submit" :value text}])
(defelem reset-button
"Creates a form reset button."
[text]
[:input {:type "reset" :value text}])
(defelem form-to
"Create a form that points to a particular method and route.
For example:
(form-to [:put \"/post\"]
...)"
[[method action] & body]
(let [method-str (.toUpperCase (name method))
action-uri (util/to-uri action)]
(-> (if (contains? #{:get :post} method)
[:form {:method method-str, :action action-uri}]
[:form {:method "POST", :action action-uri}
(hidden-field "_method" method-str)])
(concat body)
(vec))))