|
|
@ -1,16 +1,19 @@
|
|
|
|
(ns wanijo.framework.form
|
|
|
|
(ns wanijo.framework.form
|
|
|
|
(:require [clojure.spec.alpha :as spec]
|
|
|
|
(:require [clojure.spec.alpha :as spec]
|
|
|
|
[hiccup.form :as hform]
|
|
|
|
[hiccup.form :as hform]
|
|
|
|
|
|
|
|
[hiccup.core :as hcore]
|
|
|
|
[wanijo.framework.view :as view]
|
|
|
|
[wanijo.framework.view :as view]
|
|
|
|
[ring.util.anti-forgery :refer [anti-forgery-field]]))
|
|
|
|
[ring.util.anti-forgery :refer [anti-forgery-field]]
|
|
|
|
|
|
|
|
[wanijo.framework.common :refer [in?]]))
|
|
|
|
|
|
|
|
|
|
|
|
(spec/def ::label string?)
|
|
|
|
(spec/def ::label string?)
|
|
|
|
(spec/def ::required boolean?)
|
|
|
|
(spec/def ::required boolean?)
|
|
|
|
(spec/def ::spec keyword?)
|
|
|
|
(spec/def ::spec keyword?)
|
|
|
|
(spec/def ::options
|
|
|
|
(spec/def ::options
|
|
|
|
(spec/coll-of (spec/tuple string? string?)))
|
|
|
|
(spec/or :empty empty?
|
|
|
|
|
|
|
|
:options (spec/coll-of (spec/tuple string? string?))))
|
|
|
|
(spec/def ::widget
|
|
|
|
(spec/def ::widget
|
|
|
|
#(some (partial = %) [:input :select :checkbox :textarea]))
|
|
|
|
#(in? [:input :select :checkbox :textarea :mselect] %))
|
|
|
|
(spec/def ::field
|
|
|
|
(spec/def ::field
|
|
|
|
(spec/keys :req-un [::label
|
|
|
|
(spec/keys :req-un [::label
|
|
|
|
::required
|
|
|
|
::required
|
|
|
@ -18,11 +21,7 @@
|
|
|
|
:opt-un [::options
|
|
|
|
:opt-un [::options
|
|
|
|
::widget]))
|
|
|
|
::widget]))
|
|
|
|
(spec/def ::fields
|
|
|
|
(spec/def ::fields
|
|
|
|
(spec/and map?
|
|
|
|
(spec/map-of keyword? ::field))
|
|
|
|
(fn [map]
|
|
|
|
|
|
|
|
(every? #(spec/valid? ::field (val %)) map))
|
|
|
|
|
|
|
|
(fn [map]
|
|
|
|
|
|
|
|
(every? #(keyword? (key %)) map))))
|
|
|
|
|
|
|
|
(spec/def ::form
|
|
|
|
(spec/def ::form
|
|
|
|
(spec/keys :req-un [::fields]))
|
|
|
|
(spec/keys :req-un [::fields]))
|
|
|
|
|
|
|
|
|
|
|
@ -111,14 +110,31 @@
|
|
|
|
options
|
|
|
|
options
|
|
|
|
(if validate? req-value value))))
|
|
|
|
(if validate? req-value value))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(defn render-multiselect [id {:keys [label spec options]} value req-value validate?]
|
|
|
|
|
|
|
|
(list
|
|
|
|
|
|
|
|
(when (and validate? (not (spec/valid? spec req-value)))
|
|
|
|
|
|
|
|
(spec-to-errmsg label spec value))
|
|
|
|
|
|
|
|
(hform/label id label)
|
|
|
|
|
|
|
|
(hcore/html
|
|
|
|
|
|
|
|
[:select {:multiple "multiple"
|
|
|
|
|
|
|
|
:size 5
|
|
|
|
|
|
|
|
:name (name id)
|
|
|
|
|
|
|
|
:id (name id)}
|
|
|
|
|
|
|
|
(for [option options]
|
|
|
|
|
|
|
|
[:option {:value (second option)
|
|
|
|
|
|
|
|
:selected (in? (if validate? req-value value)
|
|
|
|
|
|
|
|
(second option))}
|
|
|
|
|
|
|
|
(first option)])])))
|
|
|
|
|
|
|
|
|
|
|
|
(def render-mapping
|
|
|
|
(def render-mapping
|
|
|
|
{:input render-input
|
|
|
|
{:input render-input
|
|
|
|
:checkbox render-checkbox
|
|
|
|
:checkbox render-checkbox
|
|
|
|
:textarea render-textarea
|
|
|
|
:textarea render-textarea
|
|
|
|
:select render-select})
|
|
|
|
:select render-select
|
|
|
|
|
|
|
|
:mselect render-multiselect})
|
|
|
|
|
|
|
|
|
|
|
|
(defn render-widgets [form-def values req]
|
|
|
|
(defn render-widgets [form-def values req]
|
|
|
|
{:pre [(spec/valid? ::form form-def)]}
|
|
|
|
{:pre [(spec/assert ::form form-def)]}
|
|
|
|
(let [form-hash (str (hash [form-def values]))
|
|
|
|
(let [form-hash (str (hash [form-def values]))
|
|
|
|
submitted-hash (get-in req [:params :__form-hash])
|
|
|
|
submitted-hash (get-in req [:params :__form-hash])
|
|
|
|
validate? (= form-hash submitted-hash)]
|
|
|
|
validate? (= form-hash submitted-hash)]
|
|
|
|