|
6 | 6 | [cljs-time.format :as time-format]
|
7 | 7 | [cljs-time.coerce :as timec]
|
8 | 8 | [pallet.thread-expr :as th]))
|
| 9 | + |
| 10 | + |
9 | 11 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
10 | 12 | (def date-local-format "dd/MM/yyyy")
|
11 | 13 | (def date-local-mask "00/00/0000")
|
12 | 14 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
| 15 | + |
13 | 16 | (defn- date-from-localstring
|
14 | 17 | [value fmt]
|
15 | 18 | (let [d (time-format/parse (time-format/formatter fmt) value)]
|
16 | 19 | (js/Date. d)))
|
| 20 | + |
17 | 21 | (defn- string-from-date
|
18 | 22 | [dt fmt]
|
19 | 23 | (let [dt (timec/from-date dt)]
|
20 | 24 | (time-format/unparse (time-format/formatter fmt) dt)))
|
| 25 | + |
21 | 26 | (defn- convert-input
|
22 | 27 | [input-type value]
|
23 | 28 | (condp = input-type
|
|
27 | 32 | ;; assume empty string for unhandled values
|
28 | 33 | (str value)))
|
29 | 34 | value))
|
| 35 | + |
30 | 36 | (defn- convert-output
|
31 | 37 | [output-type value]
|
32 | 38 | (condp = output-type
|
|
37 | 43 | "numeric" (let [f (js/parseFloat value)]
|
38 | 44 | (if (js/isNaN f) value f))
|
39 | 45 | value))
|
| 46 | + |
40 | 47 | (defn replace-item-at-pos
|
41 | 48 | "Given a vector and position number, will return a new
|
42 | 49 | vector with the element replaced."
|
|
47 | 54 | (if (and has-items? in-bounds?)
|
48 | 55 | (vec (concat (subvec v 0 p) [n] (subvec v (inc p))))
|
49 | 56 | v)))
|
| 57 | + |
50 | 58 | (defn- erase-selection
|
51 | 59 | [mask-vector entered-values sel-start sel-end]
|
52 | 60 | (if (= sel-start sel-end)
|
|
57 | 65 | entered-values)
|
58 | 66 | (inc sel-start)
|
59 | 67 | sel-end)))
|
| 68 | + |
60 | 69 | (defn- next-available-position
|
61 | 70 | [mask-vector pos]
|
62 | 71 | (if (and (> (count mask-vector) pos) (string? (nth mask-vector pos)))
|
63 | 72 | (recur mask-vector (inc pos))
|
64 | 73 | pos))
|
| 74 | + |
65 | 75 | (defn- special-key?
|
66 | 76 | [char-code]
|
67 | 77 | (contains? #{9 ;; tab
|
|
82 | 92 | 45 ;; insert
|
83 | 93 | 144} ;; num lock;
|
84 | 94 | char-code))
|
| 95 | + |
85 | 96 | (defn- get-selection-start ;; assume modern browser IE9 and up
|
86 | 97 | [control]
|
87 | 98 | (.-selectionStart control))
|
| 99 | + |
88 | 100 | (defn- get-selection-end ;; assume modern browser IE9 and up
|
89 | 101 | [control]
|
90 | 102 | (.-selectionEnd control))
|
| 103 | + |
91 | 104 | (defn- set-caret-pos
|
92 | 105 | [control pos]
|
93 | 106 | (.setSelectionRange control pos pos))
|
| 107 | + |
94 | 108 | (defn- mask-handler-selector
|
95 | 109 | [target owner state]
|
96 | 110 | (condp = (:input-format state)
|
|
99 | 113 | "password" :unmasked
|
100 | 114 | nil :unmasked
|
101 | 115 | :mask))
|
| 116 | + |
102 | 117 | (defn- update-target
|
103 | 118 | [target owner {:keys [input-format path onChange private-state] :as state} bInternal]
|
104 | 119 | (when (and target
|
|
113 | 128 | (not bInternal)
|
114 | 129 | (not= value (path target)))
|
115 | 130 | (onChange value))))))
|
| 131 | + |
116 | 132 | (defn- fire-on-change
|
117 | 133 | [target owner {:keys [typing-timeout private-state] :as state}]
|
118 | 134 | (let [cbtimeout (:cbtimeout @private-state)]
|
119 | 135 | (when-not (= 0 cbtimeout)
|
120 | 136 | (.clearTimeout js/window cbtimeout))
|
121 | 137 | (swap! private-state assoc :cbtimeout (.setTimeout js/window #(update-target target owner state false)
|
122 | 138 | (or typing-timeout 500)))))
|
| 139 | + |
123 | 140 | (defn- cancel-pending-timers
|
124 | 141 | [target owner {:keys [typing-timeout private-state] :as state}]
|
125 | 142 | (let [cbtimeout (:cbtimeout @private-state)]
|
126 | 143 | (when-not (= 0 cbtimeout)
|
127 | 144 | (.clearTimeout js/window cbtimeout)
|
128 | 145 | (swap! private-state assoc :cbtimeout 0))))
|
| 146 | + |
129 | 147 | ;; ---------------------------------------------------------------------
|
130 | 148 | ;; handle-custom-keys
|
131 | 149 | (defmulti handle-custom-keys! mask-handler-selector)
|
| 150 | + |
132 | 151 | (defmethod handle-custom-keys! :mask
|
133 | 152 | [target owner state k]
|
134 | 153 | (let [private-state (:private-state state)
|
|
165 | 184 | (set-caret-pos dom-node sel-start)))
|
166 | 185 | false)
|
167 | 186 | true)))
|
| 187 | + |
168 | 188 | (defmethod handle-custom-keys! :default
|
169 | 189 | [target owner state k]
|
170 | 190 | true)
|
171 | 191 |
|
172 | 192 | ;; ---------------------------------------------------------------------
|
173 | 193 | ;; handlekeydown
|
174 | 194 | (defmulti handlekeydown mask-handler-selector)
|
| 195 | + |
175 | 196 | (defmethod handlekeydown :mask
|
176 | 197 | [target owner state e]
|
177 | 198 | (let [k (.-which e)]
|
|
224 | 245 | ;; ---------------------------------------------------------------------
|
225 | 246 | ;; handlekeyup
|
226 | 247 | (defmulti handlekeyup mask-handler-selector)
|
| 248 | + |
227 | 249 | (defmethod handlekeyup :mask
|
228 | 250 | [target owner state e]
|
229 | 251 | (let [k (.-which e)]
|
230 | 252 | (if (special-key? k)
|
231 | 253 | true)
|
232 | 254 | false))
|
| 255 | + |
233 | 256 | (defmethod handlekeyup :default
|
234 | 257 | [target owner state e]
|
235 | 258 | true)
|
| 259 | + |
236 | 260 | ;; ---------------------------------------------------------------------
|
237 | 261 | ;; handlekeypress
|
238 | 262 | (defmulti handlekeypress mask-handler-selector)
|
|
258 | 282 | (set-caret-pos dom-node pos)
|
259 | 283 | (set-caret-pos dom-node (inc pos))))))
|
260 | 284 | false))
|
| 285 | + |
261 | 286 | (defmethod handlekeypress :numeric
|
262 | 287 | [target owner state e]
|
263 | 288 | (let [char-code (.-which e)
|
264 | 289 | new-char (.fromCharCode js/String char-code)]
|
265 | 290 | (pos? (count (re-seq #"\d" new-char)))))
|
| 291 | + |
266 | 292 | (defmethod handlekeypress :default
|
267 | 293 | [target owner state e]
|
268 | 294 | true)
|
| 295 | + |
269 | 296 | ;; ---------------------------------------------------------------------
|
270 | 297 | ;; Apply Mask
|
271 | 298 | (defmulti applymask! mask-handler-selector)
|
| 299 | + |
272 | 300 | (defmethod applymask! :mask
|
273 | 301 | [target owner state value]
|
274 | 302 | (let [private-state (:private-state state)
|
|
293 | 321 | (swap! private-state assoc :entered-values entered-values
|
294 | 322 | :prev-value new-value)
|
295 | 323 | (set! (.-value dom-node) new-value)))))
|
| 324 | + |
296 | 325 | (defmethod applymask! :default
|
297 | 326 | [target owner state value]
|
298 | 327 | (when-let [dom-node (:dom-node @(:private-state state))]
|
299 | 328 | (when-not (= value (:prev-value @(:private-state state)))
|
300 | 329 | (set! (.-value dom-node) value))))
|
| 330 | + |
301 | 331 | ;; ---------------------------------------------------------------------
|
302 | 332 | ;; handlepaste
|
303 | 333 | (defmulti handlepaste mask-handler-selector)
|
| 334 | + |
304 | 335 | (defmethod handlepaste :mask
|
305 | 336 | [target owner state k]
|
306 | 337 | (.setTimeout js/window (fn []
|
|
309 | 340 | (applymask! target owner state (.-value dom-node))))
|
310 | 341 | 1)
|
311 | 342 | true)
|
| 343 | + |
312 | 344 | (defmethod handlepaste :default
|
313 | 345 | [target owner state e]
|
314 | 346 | true)
|
| 347 | + |
315 | 348 | ;; ---------------------------------------------------------------------
|
316 | 349 | ;; Init Mask
|
317 | 350 | (defmulti initmask! mask-handler-selector)
|
| 351 | + |
318 | 352 | (defmethod initmask! :mask
|
319 | 353 | [target owner state]
|
320 | 354 | (let [private-state (:private-state state)
|
|
329 | 363 | %) input-mask))]
|
330 | 364 | (swap! private-state assoc :entered-values (map #(when (string? %) %) mask)
|
331 | 365 | :mask-vector (remove nil? mask))))
|
| 366 | + |
332 | 367 | (defmethod initmask! :default
|
333 | 368 | [target owner state])
|
| 369 | + |
334 | 370 | ;; ---------------------------------------------------------------------
|
335 | 371 | ;; Components
|
336 | 372 | (defn- create-textinput
|
|
413 | 449 | (merge {:max (:max state)}))
|
414 | 450 | (th/when-> (:resize state)
|
415 | 451 | (merge {:resize (name (:resize state))}))))))))
|
| 452 | + |
416 | 453 | (defn textinput
|
417 | 454 | [target path {:keys [input-class input-format align] :as opts
|
418 | 455 | :or {input-class ""}}]
|
|
0 commit comments