Bladeren bron

support optional entries in maps.

this change is so big because now writes occur "from above", e.g. the
components write to the map. this requires passing the map and key
around, which is why so much changed.

i'm not yet sure whether i like this, but i don't see how i could do it
otherwise. maybe we could have walked "upwards" with the cursors?
Lucas Stadler 12 jaren geleden
bovenliggende
commit
0b6359071c
1 gewijzigde bestanden met toevoegingen van 44 en 42 verwijderingen
  1. 44 42
      clj/clarity/cljs/clarity.cljs

+ 44 - 42
clj/clarity/cljs/clarity.cljs

@ -4,19 +4,8 @@
4 4
            [om.core :as om :include-macros true]
5 5
            [om.dom :as dom :include-macros true]))
6 6
7
(enable-console-print!)
8
9
(extend-type js/Boolean
10
  ICloneable
11
  (-clone [b] b))
12 7
13
(extend-type number
14
  ICloneable
15
  (-clone [n] (js/Number. n)))
16
17
(extend-type string
18
  ICloneable
19
  (-clone [s] (js/String. s)))
8
(enable-console-print!)
20 9
21 10
; data for one node: type and optionally data
22 11
;  if data is present, fill the node with the data
@ -75,35 +64,42 @@
75 64
      (map? type) (:type type)
76 65
      :else type)))
77 66
78
(defmethod make-typed-input 'Boolean [bool owner]
67
(defmethod make-typed-input 'Boolean [m owner {:keys [type key val]}]
79 68
  (om/component
80 69
    (dom/input #js {:type "checkbox"
81
                    :checked (.valueOf bool)
82
                    :onChange #(om/update! bool (fn [_ n] n) (js/Boolean. (.. % -target -checked)))})))
70
                    :checked (.valueOf (or val (empty-value type)))
71
                    :onChange #(om/transact! m key (fn [_ n] n) (js/Boolean. (.. % -target -checked)))})))
83 72
84
(defmethod make-typed-input 'Number [number owner]
73
(defmethod make-typed-input 'Number [m owner {:keys [key val]}]
85 74
  (om/component
86 75
    (dom/input #js {:type "number"
87
                    :value (om/value number)
88
                    :onChange #(om/update! number (fn [_ n] n) (js/parseFloat (.. % -target -value)))})))
76
                    :value val
77
                    :onChange (update-on-change! m key js/parseFloat)})))
89 78
90 79
(def keyword-pattern "^:(\\w+|\\w+(\\.\\w+)*\\/\\w+)$")
91 80
92
(defmethod make-typed-input 'Keyword [kw owner]
81
(defmethod make-typed-input 'Keyword [m owner {:keys [key val]}]
93 82
  (om/component
94 83
    (dom/input #js {:type "text"
95
                    :value (om/value kw)
84
                    :value val
96 85
                    :pattern keyword-pattern
97
                    :onChange (fn [ev]
98
                                (when (valid? (.-target ev))
99
                                  (om/update! kw (fn [o n] n) (or (read-keyword (.. ev -target -value))
100
                                                                  (empty-value 'Keyword)))))})))
101
102
(defmethod make-typed-input 'String [string owner]
86
                    :onChange (update-on-change! m key #(or (read-keyword %) (empty-value type)))})))
87
88
(defn update-on-change!
89
  ([m k] (update-on-change! m k identity))
90
  ([m k transform-fn] (update-on-change! m k transform-fn false))
91
  ([m k transform-fn optional?]
92
   (fn [ev]
93
     (let [new-val (transform-fn (.. ev -target -value))]
94
       (if (and optional? (empty? new-val))
95
         (om/update! m dissoc k)
96
         (om/transact! m k (fn [_ n] n) new-val))))))
97
98
(defmethod make-typed-input 'String [m owner {:keys [type key val optional?]}]
103 99
  (om/component
104 100
    (dom/input #js {:type "text"
105
                    :value (om/value string)
106
                    :onChange #(om/update! string (fn [_ n] n) (.. % -target -value))})))
101
                    :value val
102
                    :onChange (update-on-change! m key identity optional?)})))
107 103
108 104
(defmethod make-typed-input 'Value [value owner]
109 105
  (om/component
@ -116,28 +112,32 @@
116 112
                    (keyword? value) {:type "text", :pattern keyword-pattern}
117 113
                    :else {:type "text"}))))))
118 114
119
(defmethod make-typed-input 'U [value owner {type :type}]
115
(defmethod make-typed-input 'U [m owner {:keys [type key val]}]
120 116
  (om/component
121
    (dom/select #js {:onChange #(om/update! value (fn [_ n] n) (r/read-string (.. % -target -value)))}
117
    (dom/select #js {:onChange (update-on-change! m key r/read-string)}
122 118
      (into-array
123 119
        (map (fn [[_ v]]
124 120
               (dom/option nil (str v)))
125 121
             (rest type))))))
126 122
127 123
(defmethod make-typed-input 'HMap [m owner {type :type}]
128
  (om/component
129
    (dom/div nil
130
      (dom/span nil "{")
131
      (into-array
132
        (map (fn [[k v]]
133
               (dom/div #js {:className "field"}
134
                 (dom/label nil (str k))
135
                 (om/build make-typed-input v {:opts {:type (k (nth type 2))}})))
136
             m))
137
      (dom/span nil "}"))))
124
  (let [hmap (apply hash-map (rest type))
125
        required (:mandatory hmap)
126
        optional (:optional hmap)]
127
    (om/component
128
      (dom/div nil
129
        (dom/span nil "{")
130
        (into-array
131
          (map (fn [[k t]]
132
                 (dom/div #js {:className "field"}
133
                   (dom/label nil (str k))
134
                   (om/build make-typed-input m {:opts {:type t, :key k, :val (k m)
135
                                                        :optional? (contains? optional k)}})))
136
               (merge required optional)))
137
        (dom/span nil "}")))))
138 138
139 139
(def app-state
140
  (let [type '(HMap :mandatory
140
  (let [type '[HMap :mandatory
141 141
                    {:name {:type String :default "Paul"},
142 142
                     :age {:type Number, :default 10},
143 143
                     :language (U (Value :en)
@ -145,7 +145,9 @@
145 145
                                  (Value :fr)
146 146
                                  (Value :jp))
147 147
                     :fun Boolean
148
                     :gender Keyword})]
148
                     :gender Keyword}
149
                    :optional
150
                    {:secret-skill String}]]
149 151
    (atom
150 152
     {:type type
151 153
      :data (empty-value type)})))