|  |  |  | @ -1,16 +1,19 @@ | 
		
	
		
			
				|  |  |  |  | (ns wanijo.framework.form | 
		
	
		
			
				|  |  |  |  |   (:require [clojure.spec.alpha :as spec] | 
		
	
		
			
				|  |  |  |  |             [hiccup.form :as hform] | 
		
	
		
			
				|  |  |  |  |             [hiccup.core :as hcore] | 
		
	
		
			
				|  |  |  |  |             [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 ::required boolean?) | 
		
	
		
			
				|  |  |  |  | (spec/def ::spec keyword?) | 
		
	
		
			
				|  |  |  |  | (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 | 
		
	
		
			
				|  |  |  |  |   #(some (partial = %) [:input :select :checkbox :textarea])) | 
		
	
		
			
				|  |  |  |  |   #(in? [:input :select :checkbox :textarea :mselect] %)) | 
		
	
		
			
				|  |  |  |  | (spec/def ::field | 
		
	
		
			
				|  |  |  |  |   (spec/keys :req-un [::label | 
		
	
		
			
				|  |  |  |  |                       ::required | 
		
	
	
		
			
				
					|  |  |  | @ -18,11 +21,7 @@ | 
		
	
		
			
				|  |  |  |  |              :opt-un [::options | 
		
	
		
			
				|  |  |  |  |                       ::widget])) | 
		
	
		
			
				|  |  |  |  | (spec/def ::fields | 
		
	
		
			
				|  |  |  |  |   (spec/and map? | 
		
	
		
			
				|  |  |  |  |             (fn [map] | 
		
	
		
			
				|  |  |  |  |               (every? #(spec/valid? ::field (val %)) map)) | 
		
	
		
			
				|  |  |  |  |             (fn [map] | 
		
	
		
			
				|  |  |  |  |               (every? #(keyword? (key %)) map)))) | 
		
	
		
			
				|  |  |  |  |   (spec/map-of keyword? ::field)) | 
		
	
		
			
				|  |  |  |  | (spec/def ::form | 
		
	
		
			
				|  |  |  |  |   (spec/keys :req-un [::fields])) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -111,14 +110,31 @@ | 
		
	
		
			
				|  |  |  |  |                     options | 
		
	
		
			
				|  |  |  |  |                     (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 | 
		
	
		
			
				|  |  |  |  |   {:input render-input | 
		
	
		
			
				|  |  |  |  |    :checkbox render-checkbox | 
		
	
		
			
				|  |  |  |  |    :textarea render-textarea | 
		
	
		
			
				|  |  |  |  |    :select render-select}) | 
		
	
		
			
				|  |  |  |  |    :select render-select | 
		
	
		
			
				|  |  |  |  |    :mselect render-multiselect}) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | (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])) | 
		
	
		
			
				|  |  |  |  |         submitted-hash (get-in req [:params :__form-hash]) | 
		
	
		
			
				|  |  |  |  |         validate? (= form-hash submitted-hash)] | 
		
	
	
		
			
				
					|  |  |  | 
 |