Refactor: separate state and DOM

This commit is contained in:
Nicholas Kariniemi 2013-08-06 23:38:53 +03:00
parent 0cc5cc5dc8
commit 991807700b
5 changed files with 84 additions and 55 deletions

View file

@ -49,7 +49,7 @@
(go (doseq [grub sorted-grubs]
(let [grub-event (-> grub
(select-keys [:_id :grub :completed])
(assoc :event :create))]
(assoc :event :add))]
(>! out grub-event))))
out))

View file

@ -3,40 +3,19 @@
:refer [fan-in fan-out event-chan filter-chan do-chan do-chan! map-chan]]
[grub-client.view :as view]
[grub-client.websocket :as ws]
[grub-client.state :as state]
[cljs.core.async :refer [<! >! >!! chan close! timeout]]
[cljs.reader])
(:require-macros [grub-client.macros :refer [log logs go-loop]]
[cljs.core.async.macros :refer [go]]))
(defn get-local-events []
(fan-in [(view/get-added-events)
(view/get-completed-events)
(view/get-deleted-events)]))
(defmulti handle-event :event :default :unknown-event)
(defmethod handle-event :create [event]
(view/add-grub event))
(defmethod handle-event :complete [event]
(view/complete-grub event))
(defmethod handle-event :uncomplete [event]
(view/uncomplete-grub event))
(defmethod handle-event :delete [event]
(view/delete-grub event))
(defmethod handle-event :unknown-event [event]
(logs "Cannot handle unknown event:" event))
(defn handle-grub-events []
(let [local-events (get-local-events)
(let [local-events (view/get-local-events)
[local-events' local-events''] (fan-out local-events 2)
remote-events (ws/get-remote-events)
events (fan-in [local-events' remote-events])]
(do-chan! ws/send-to-server local-events'')
(go-loop (handle-event (<! events)))))
(go-loop (state/handle-event (<! events)))))
(defn init []
(view/render-body)

View file

@ -4,7 +4,7 @@
`(.log js/console ~@args))
(defmacro logs [& args]
(let [strings (map (fn [a] `(str ~a)) args)]
(let [strings (map (fn [a] `(pr-str ~a)) args)]
`(.log js/console ~@strings)))
(defmacro go-loop [& body]

View file

@ -0,0 +1,49 @@
(ns grub-client.state
(:require-macros [grub-client.macros :refer [log logs]]))
(def grubs (atom []))
(defn get-grub-with-index [grubs id]
(let [grub-index (->> grubs
(map-indexed vector)
(filter #(= (:_id (second %)) id))
(first)
(first))
grub (nth grubs grub-index)]
[grub-index grub]))
(defmulti handle-event :event :default :unknown-event)
(defmethod handle-event :add [event]
(let [grub (select-keys event [:_id :grub :completed])]
(swap! grubs (fn [current] (conj current grub)))))
(defmethod handle-event :create [event]
(let [grub (-> event
(select-keys [:_id :grub])
(assoc :completed false))]
(swap! grubs (fn [current] (conj current grub)))))
(defmethod handle-event :complete [event]
(swap! grubs
(fn [current]
(let [[grub-index grub] (get-grub-with-index current (:_id event))
completed-grub (assoc grub :completed true)]
(assoc current grub-index completed-grub)))))
(defmethod handle-event :uncomplete [event]
(swap! grubs
(fn [current]
(let [[grub-index grub] (get-grub-with-index current (:_id event))
incomplete-grub (assoc grub :completed false)]
(assoc current grub-index incomplete-grub)))))
(defmethod handle-event :delete [event]
(swap! grubs
(fn [current]
(vec (remove #(= (:_id %) (:_id event)) current)))))
(defmethod handle-event :unknown-event [event]
(logs "Cannot handle unknown event:" event))

View file

@ -1,21 +1,13 @@
(ns grub-client.view
(:require [grub-client.async-utils
:refer [do-chan! do-chan event-chan map-chan fan-in filter-chan]]
[grub-client.state :as state]
[dommy.core :as dommy]
[cljs.core.async :refer [<! >! chan]])
(:require-macros [grub-client.macros :refer [log logs go-loop]]
[dommy.macros :refer [deftemplate sel1 node]]
[cljs.core.async.macros :refer [go]]))
(deftemplate grub-template [grub]
[:tr {:id (:_id grub)}
[:td
[:div.checkbox.grubCheckbox [:label
[:input {:type "checkbox"}]
(:grub grub)]]]
[:td
[:button.grub-close.close {:type "button"} "×"]]])
(def add-grub-text
(node [:input.form-control {:type "text" :placeholder "2 grubs"}]))
@ -36,28 +28,19 @@
[:tbody#grubList]]]
[:div.col-lg-4]]])
(deftemplate grub-template [grub]
[:tr {:id (:_id grub)}
[:td
[:div.checkbox.grubCheckbox [:label
[:input {:type "checkbox"
:checked (:completed grub)}]
(:grub grub)]]]
[:td
[:button.grub-close.close {:type "button"} "×"]]])
(defn render-body []
(dommy/prepend! (sel1 :body) (main-template)))
(defn add-grub-to-dom [grub-obj]
(logs "Add" grub-obj)
(dommy/append! (sel1 :#grubList) (grub-template grub-obj)))
(defn add-grub [grub]
(add-grub-to-dom grub))
(defn complete-grub [grub]
(logs "Complete" grub)
(aset (sel1 [(str "#" (:_id grub)) "input"]) "checked" true))
(defn uncomplete-grub [grub]
(logs "Uncomplete" grub)
(aset (sel1 [(str "#" (:_id grub)) "input"]) "checked" false))
(defn delete-grub [grub]
(let [elem (sel1 (str "#" (:_id grub)))]
(.removeChild (.-parentNode elem) elem)))
(defn get-add-grub-text []
(let [text (dommy/value add-grub-text)]
(dommy/set-value! add-grub-text "")
@ -108,4 +91,22 @@
(let [ids (map-chan #(.-id (.-parentNode (.-parentNode (.-target %)))) click-events)
grub-events (map-chan (fn [id] {:event :delete :_id id}) ids)]
grub-events)))
(defn get-local-events []
(fan-in [(get-added-events)
(get-completed-events)
(get-deleted-events)]))
(defn render-grub-list [grubs]
(let [grub-list (sel1 :#grubList)
sorted-grubs (sort-by :_id grubs)]
(aset grub-list "innerHTML" "")
(doseq [grub sorted-grubs]
(logs "render-grub-list:" grub)
(dommy/append! grub-list (grub-template grub)))))
(add-watch state/grubs
:grub-add-watch
(fn [key ref old new]
(logs "state:" new)
(render-grub-list new)))