Large refactoring - use async macros, separate files
This commit is contained in:
parent
1b2f67a961
commit
7473ed4120
3 changed files with 152 additions and 92 deletions
66
src-cljs/grub_client/async-utils.cljs
Normal file
66
src-cljs/grub_client/async-utils.cljs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
(ns grub-client.async-utils
|
||||||
|
(:require [cljs.core.async :as async :refer [<! >! chan put! alts!]])
|
||||||
|
(:require-macros [cljs.core.async.macros :as m :refer [go]]
|
||||||
|
[grub-client.macros :refer [go-loop]]))
|
||||||
|
|
||||||
|
(defn put-all! [cs x]
|
||||||
|
(doseq [c cs]
|
||||||
|
(put! c x)))
|
||||||
|
|
||||||
|
(defn fan-out [in cs-or-n]
|
||||||
|
(let [cs (if (number? cs-or-n)
|
||||||
|
(repeatedly cs-or-n chan)
|
||||||
|
cs-or-n)]
|
||||||
|
(go (loop []
|
||||||
|
(let [x (<! in)]
|
||||||
|
(if-not (nil? x)
|
||||||
|
(do
|
||||||
|
(put-all! cs x)
|
||||||
|
(recur))
|
||||||
|
:done))))
|
||||||
|
cs))
|
||||||
|
|
||||||
|
(defn fan-in
|
||||||
|
([ins] (fan-in (chan) ins))
|
||||||
|
([c ins]
|
||||||
|
(go (while true
|
||||||
|
(let [[x] (alts! ins)]
|
||||||
|
(>! c x))))
|
||||||
|
c))
|
||||||
|
|
||||||
|
(defn copy-chan
|
||||||
|
([c]
|
||||||
|
(first (fan-out c 1)))
|
||||||
|
([out c]
|
||||||
|
(first (fan-out c [out]))))
|
||||||
|
|
||||||
|
(defn event-chan
|
||||||
|
([type] (event-chan js/window type))
|
||||||
|
([el type] (event-chan (chan) el type))
|
||||||
|
([c el type]
|
||||||
|
(let [writer #(put! c %)]
|
||||||
|
(.addEventListener el type writer)
|
||||||
|
{:chan c
|
||||||
|
:unsubscribe #(.removeEventListener el type writer)})))
|
||||||
|
|
||||||
|
(defn map-chan
|
||||||
|
([f source] (map-chan (chan) f source))
|
||||||
|
([c f source]
|
||||||
|
(go-loop
|
||||||
|
(>! c (f (<! source))))
|
||||||
|
c))
|
||||||
|
|
||||||
|
(defn filter-chan
|
||||||
|
([f source] (filter-chan (chan) f source))
|
||||||
|
([c f source]
|
||||||
|
(go-loop
|
||||||
|
(let [v (<! source)]
|
||||||
|
(when (f v)
|
||||||
|
(>! c v))))
|
||||||
|
c))
|
||||||
|
|
||||||
|
(defn do-chan! [f source]
|
||||||
|
(go-loop
|
||||||
|
(let [v (<! source)]
|
||||||
|
(f v))))
|
||||||
|
|
|
@ -1,105 +1,42 @@
|
||||||
(ns grub-client.core
|
(ns grub-client.core
|
||||||
(:require [dommy.core :as dommy]
|
(:require [cljs.core.async :refer [<! >! >!! chan close! timeout]]
|
||||||
[cljs.core.async :as async :refer [<! >! chan close! timeout]])
|
[grub-client.async-utils
|
||||||
(:require-macros [dommy.macros :refer [deftemplate sel1 node]]
|
:refer [fan-in fan-out event-chan filter-chan do-chan!]]
|
||||||
[cljs.core.async.macros :as m :refer [go alt! alts!]]
|
[grub-client.view :as view])
|
||||||
|
(:require-macros [cljs.core.async.macros :refer [go]]
|
||||||
[grub-client.macros :refer [log go-loop]]))
|
[grub-client.macros :refer [log go-loop]]))
|
||||||
|
|
||||||
(deftemplate grub-template [grub]
|
|
||||||
[:tr
|
|
||||||
[:td
|
|
||||||
[:div.checkbox [:label [:input {:type "checkbox"}] grub]]]])
|
|
||||||
|
|
||||||
(def add-grub-text
|
|
||||||
(node [:input.form-control {:type "text" :placeholder "2 grubs"}]))
|
|
||||||
|
|
||||||
(def add-grub-btn
|
|
||||||
(node [:button.btn.btn-default {:type "button"} "Add"]))
|
|
||||||
|
|
||||||
(deftemplate main-template [grubs]
|
|
||||||
[:div.container
|
|
||||||
[:div.row.show-grid
|
|
||||||
[:div.col-lg-4]
|
|
||||||
[:div.col-lg-4
|
|
||||||
[:h3 "Grub List"]
|
|
||||||
[:div.input-group
|
|
||||||
add-grub-text
|
|
||||||
[:span.input-group-btn
|
|
||||||
add-grub-btn]]
|
|
||||||
[:table.table.table-condensed
|
|
||||||
[:tbody#grubList]]]
|
|
||||||
[:div.col-lg-4]]])
|
|
||||||
|
|
||||||
(defn render-body []
|
|
||||||
(dommy/prepend! (sel1 :body) (main-template)))
|
|
||||||
|
|
||||||
(defn push-new-grub [channel]
|
|
||||||
(let [new-grub (dommy/value add-grub-text)]
|
|
||||||
(dommy/set-value! add-grub-text "")
|
|
||||||
(go (>! channel new-grub))))
|
|
||||||
|
|
||||||
(defn put-grubs-from-clicks [channel]
|
|
||||||
(dommy/listen! add-grub-btn :click #(push-new-grub channel)))
|
|
||||||
|
|
||||||
(defn put-grubs-if-enter-pressed [channel event]
|
|
||||||
(when (= (.-keyIdentifier event) "Enter")
|
|
||||||
(push-new-grub channel)))
|
|
||||||
|
|
||||||
(defn put-grubs-from-enter [channel]
|
|
||||||
(dommy/listen! add-grub-text
|
|
||||||
:keyup
|
|
||||||
(partial put-grubs-if-enter-pressed channel)))
|
|
||||||
|
|
||||||
(defn get-added-grubs []
|
|
||||||
(let [out (chan)]
|
|
||||||
(put-grubs-from-clicks out)
|
|
||||||
(put-grubs-from-enter out)
|
|
||||||
out))
|
|
||||||
|
|
||||||
(defn append-new-grub [grub]
|
|
||||||
(dommy/append! (sel1 :#grubList) (grub-template grub)))
|
|
||||||
|
|
||||||
(defn append-new-grubs [chan]
|
|
||||||
(go-loop (let [grub (<! chan)]
|
|
||||||
(append-new-grub grub))))
|
|
||||||
|
|
||||||
(defn add-grubs-to-list [in]
|
|
||||||
(go-loop (let [new-grub (<! in)]
|
|
||||||
(append-new-grub new-grub))))
|
|
||||||
|
|
||||||
(defn filter-empty-grubs [in]
|
|
||||||
(let [out (chan)]
|
|
||||||
(go-loop (let [grub (<! in)]
|
|
||||||
(when-not (empty? grub) (>! out grub))))
|
|
||||||
out))
|
|
||||||
|
|
||||||
(def websocket* (atom nil))
|
(def websocket* (atom nil))
|
||||||
|
|
||||||
(defn push-grubs-to-server [chan]
|
(defn connect-to-server []
|
||||||
(let [websocket (js/WebSocket. "ws://localhost:3000/ws")]
|
(reset! websocket* (js/WebSocket. "ws://localhost:3000/ws")))
|
||||||
(aset websocket "onmessage" (fn [event]
|
|
||||||
(let [grub (.-data event)]
|
|
||||||
(log "Received grub:" grub)
|
|
||||||
(append-new-grub grub))))
|
|
||||||
(go-loop (let [grub (<! chan)]
|
|
||||||
(.send websocket grub)))))
|
|
||||||
|
|
||||||
(defn fan-out [in num-chans]
|
(defn get-local-added-grubs []
|
||||||
(let [out-channels (repeatedly num-chans chan)]
|
(let [grubs (fan-in [(view/get-grubs-from-clicks) (view/get-grubs-from-enter)])]
|
||||||
(go-loop (let [x (<! in)]
|
(filter-chan #(not (empty? %)) grubs)))
|
||||||
(doseq [out out-channels]
|
|
||||||
(>! out x))))
|
(defn push-grubs-to-server [in]
|
||||||
out-channels))
|
(do-chan! #(.send @websocket* %) in))
|
||||||
|
|
||||||
|
(defn get-remote-added-grubs []
|
||||||
|
(let [out (chan)]
|
||||||
|
(aset @websocket* "onmessage" (fn [event]
|
||||||
|
(let [grub (.-data event)]
|
||||||
|
(log "Received grub:" grub)
|
||||||
|
(go (>! out grub)))))
|
||||||
|
out))
|
||||||
|
|
||||||
(defn add-new-grubs-as-they-come []
|
(defn add-new-grubs-as-they-come []
|
||||||
(let [added-grubs (get-added-grubs)
|
(let [added-local (get-local-added-grubs)
|
||||||
filtered-grubs (filter-empty-grubs added-grubs)
|
[added-local' added-local''] (fan-out added-local 2)
|
||||||
out-channels (fan-out filtered-grubs 2)]
|
added-remote (get-remote-added-grubs)
|
||||||
(append-new-grubs (first out-channels))
|
added (fan-in [added-local' added-remote])]
|
||||||
(push-grubs-to-server (second out-channels))))
|
(do-chan! view/append-new-grub added)
|
||||||
|
(push-grubs-to-server added-local'')))
|
||||||
|
|
||||||
(defn init []
|
(defn init []
|
||||||
(render-body)
|
(view/render-body)
|
||||||
|
(connect-to-server)
|
||||||
(add-new-grubs-as-they-come))
|
(add-new-grubs-as-they-come))
|
||||||
|
|
||||||
(init)
|
(init)
|
||||||
|
|
57
src-cljs/grub_client/view.cljs
Normal file
57
src-cljs/grub_client/view.cljs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
(ns grub-client.view
|
||||||
|
(:require [dommy.core :as dommy]
|
||||||
|
[cljs.core.async :refer [<! >! chan]])
|
||||||
|
(:require-macros [dommy.macros :refer [deftemplate sel1 node]]
|
||||||
|
[cljs.core.async.macros :refer [go]]))
|
||||||
|
|
||||||
|
(deftemplate grub-template [grub]
|
||||||
|
[:tr
|
||||||
|
[:td
|
||||||
|
[:div.checkbox [:label [:input {:type "checkbox"}] grub]]]])
|
||||||
|
|
||||||
|
(def add-grub-text
|
||||||
|
(node [:input.form-control {:type "text" :placeholder "2 grubs"}]))
|
||||||
|
|
||||||
|
(def add-grub-btn
|
||||||
|
(node [:button.btn.btn-default {:type "button"} "Add"]))
|
||||||
|
|
||||||
|
(deftemplate main-template [grubs]
|
||||||
|
[:div.container
|
||||||
|
[:div.row.show-grid
|
||||||
|
[:div.col-lg-4]
|
||||||
|
[:div.col-lg-4
|
||||||
|
[:h3 "Grub List"]
|
||||||
|
[:div.input-group
|
||||||
|
add-grub-text
|
||||||
|
[:span.input-group-btn
|
||||||
|
add-grub-btn]]
|
||||||
|
[:table.table.table-condensed
|
||||||
|
[:tbody#grubList]]]
|
||||||
|
[:div.col-lg-4]]])
|
||||||
|
|
||||||
|
(defn render-body []
|
||||||
|
(dommy/prepend! (sel1 :body) (main-template)))
|
||||||
|
|
||||||
|
(defn append-new-grub [grub]
|
||||||
|
(dommy/append! (sel1 :#grubList) (grub-template grub)))
|
||||||
|
|
||||||
|
(defn push-new-grub [out]
|
||||||
|
(let [new-grub (dommy/value add-grub-text)]
|
||||||
|
(dommy/set-value! add-grub-text "")
|
||||||
|
(go (>! out new-grub))))
|
||||||
|
|
||||||
|
(defn get-grubs-from-clicks []
|
||||||
|
(let [out (chan)]
|
||||||
|
(dommy/listen! add-grub-btn :click #(push-new-grub out))
|
||||||
|
out))
|
||||||
|
|
||||||
|
(defn put-grubs-if-enter-pressed [out event]
|
||||||
|
(when (= (.-keyIdentifier event) "Enter")
|
||||||
|
(push-new-grub out)))
|
||||||
|
|
||||||
|
(defn get-grubs-from-enter []
|
||||||
|
(let [out (chan)]
|
||||||
|
(dommy/listen! add-grub-text
|
||||||
|
:keyup
|
||||||
|
(partial put-grubs-if-enter-pressed out))
|
||||||
|
out))
|
Loading…
Add table
Reference in a new issue