Просмотр исходного кода

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
Родитель
Сommit
0b6359071c
1 измененных файлов с 44 добавлено и 42 удалено
  1. 44 42
      clj/clarity/cljs/clarity.cljs

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

4
            [om.core :as om :include-macros true]
4
            [om.core :as om :include-macros true]
5
            [om.dom :as dom :include-macros true]))
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
; data for one node: type and optionally data
10
; data for one node: type and optionally data
22
;  if data is present, fill the node with the data
11
;  if data is present, fill the node with the data
75
      (map? type) (:type type)
64
      (map? type) (:type type)
76
      :else type)))
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
  (om/component
68
  (om/component
80
    (dom/input #js {:type "checkbox"
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
  (om/component
74
  (om/component
86
    (dom/input #js {:type "number"
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
(def keyword-pattern "^:(\\w+|\\w+(\\.\\w+)*\\/\\w+)$")
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
  (om/component
82
  (om/component
94
    (dom/input #js {:type "text"
83
    (dom/input #js {:type "text"
95
                    :value (om/value kw)
84
                    :value val
96
                    :pattern keyword-pattern
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
  (om/component
99
  (om/component
104
    (dom/input #js {:type "text"
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
(defmethod make-typed-input 'Value [value owner]
104
(defmethod make-typed-input 'Value [value owner]
109
  (om/component
105
  (om/component
116
                    (keyword? value) {:type "text", :pattern keyword-pattern}
112
                    (keyword? value) {:type "text", :pattern keyword-pattern}
117
                    :else {:type "text"}))))))
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
  (om/component
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
      (into-array
118
      (into-array
123
        (map (fn [[_ v]]
119
        (map (fn [[_ v]]
124
               (dom/option nil (str v)))
120
               (dom/option nil (str v)))
125
             (rest type))))))
121
             (rest type))))))
126
122
127
(defmethod make-typed-input 'HMap [m owner {type :type}]
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
(def app-state
139
(def app-state
140
  (let [type '(HMap :mandatory
140
  (let [type '[HMap :mandatory
141
                    {:name {:type String :default "Paul"},
141
                    {:name {:type String :default "Paul"},
142
                     :age {:type Number, :default 10},
142
                     :age {:type Number, :default 10},
143
                     :language (U (Value :en)
143
                     :language (U (Value :en)
145
                                  (Value :fr)
145
                                  (Value :fr)
146
                                  (Value :jp))
146
                                  (Value :jp))
147
                     :fun Boolean
147
                     :fun Boolean
148
                     :gender Keyword})]
148
                     :gender Keyword}
149
                    :optional
150
                    {:secret-skill String}]]
149
    (atom
151
    (atom
150
     {:type type
152
     {:type type
151
      :data (empty-value type)})))
153
      :data (empty-value type)})))