Render grub list with om

This commit is contained in:
Nicholas Kariniemi 2014-06-29 12:35:35 +03:00
parent 594408ede2
commit 24632d99ce
9 changed files with 17237 additions and 226 deletions

View file

@ -1,161 +1,165 @@
html, body {
height: 100%;
min-height: 100%;
width: 100%;
min-width: 100%;
margin: 0px;
height: 100%;
min-height: 100%;
width: 100%;
min-width: 100%;
margin: 0px;
}
h3 {
margin-top: 10px;
margin-top: 10px;
}
.recipes-title {
clear: right;
clear: right;
}
.recipe-list {
margin-top: 10px;
margin-top: 10px;
}
#recipe-grubs {
width: 100%;
width: 100%;
}
.recipe-add-grubs-btn {
float: right;
clear: both;
margin: 2px;
float: right;
clear: both;
margin: 2px;
}
.hidden {
display: none;
display: none;
}
.leftmost-column {
margin-bottom: 45px;
margin-bottom: 45px;
}
.grub-close {
display: none;
display: none;
}
tr:hover .grub-close {
display: block;
display: block;
}
#grub-list {
margin-top: 10px;
margin-bottom: 10px;
margin-top: 10px;
margin-bottom: 10px;
}
.add-grub-input-form .input-group-btn {
width: 100%;
}
.grub-item {
cursor: default;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: default;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.grub-item.grub-active {
color: #ffffff;
background-color: rgb(71, 73, 73);
color: #ffffff;
background-color: rgb(71, 73, 73);
}
.grub-item .input-span {
display: block;
overflow: hidden;
display: block;
overflow: hidden;
}
.grub-item .grub-static {
display: inline;
display: inline;
}
.grub-item .grub-input {
display: none;
display: none;
}
.grub-item.edit .grub-static {
display: none;
display: none;
}
.grub-item.edit .grub-input {
display: inline;
width: 100%;
display: inline;
width: 100%;
}
.grub-item .glyphicon {
margin-right: 5px;
margin-right: 5px;
}
.completed {
text-decoration: line-through;
color: #a9a9a9;
text-decoration: line-through;
color: #a9a9a9;
}
.completed.edit {
text-decoration: none;
color: default;
text-decoration: none;
color: default;
}
.panel-body {
padding: 10px;
padding-top: 0px;
padding: 10px;
padding-top: 0px;
}
.panel-heading {
background-color: #ffffff;
background-color: #ffffff;
}
.recipe-panel {
padding: 0px;
margin-bottom: -1px;
padding: 0px;
margin-bottom: -1px;
}
.recipe-panel > .recipe-header {
background-color: #ffffff;
background-color: #ffffff;
}
.recipe-header {
margin: 0px;
padding: 0px;
border-bottom: none;
margin: 0px;
padding: 0px;
border-bottom: none;
}
.recipe-header-input {
border: none;
box-shadow: none;
transition: none;
border-bottom: none;
width: inherit;
display: inline;
border: none;
box-shadow: none;
transition: none;
border-bottom: none;
width: inherit;
display: inline;
}
.recipe-header-input:focus {
border: none;
box-shadow: none;
transition: none;
outline: none;
border: none;
box-shadow: none;
transition: none;
outline: none;
}
.recipe-btn {
margin-top: 10px;
margin-top: 10px;
}
.recipe-grubs {
}
.recipe-grubs-input {
border: none;
box-shadow: none;
transition: none;
border-bottom: none;
resize: none;
border: none;
box-shadow: none;
transition: none;
border-bottom: none;
resize: none;
}
.recipe-grubs-input:focus {
border: none;
box-shadow: none;
transition: none;
border-bottom: none;
border: none;
box-shadow: none;
transition: none;
border-bottom: none;
}

16644
public/js/react-0.9.0.js Normal file

File diff suppressed because it is too large Load diff

21
public/js/react-0.9.0.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -25,7 +25,8 @@
(html5
index-page-header
[:body
(include-js "http://fb.me/react-0.9.0.js")
[:div#container]
(include-js "/js/react-0.9.0.min.js")
(include-js "/js/jquery.js")
(include-js "/js/bootstrap.js")
(include-js "/js/grub.js")]))
@ -34,7 +35,8 @@
(html5
index-page-header
[:body
(include-js "http://fb.me/react-0.9.0.js")
[:div#container]
(include-js "/js/react-0.9.0.js")
(include-js "/js/out/goog/base.js")
(include-js "/js/jquery.js")
(include-js "/js/bootstrap.js")

View file

@ -1,5 +1,5 @@
(ns grub.core
(:require [grub.view :as view]
(:require [grub.state :as state]
[grub.websocket :as ws]
[cljs.core.async :as a :refer [<! >! chan]])
(:require-macros [grub.macros :refer [log logs go-loop]]
@ -7,10 +7,10 @@
(defn wire-channels-together []
(let [to-remote (chan)
to-view (chan)
to-state (chan)
from-remote (ws/get-remote-chan to-remote)
from-view (view/setup-and-get-view-events to-view)]
(a/pipe from-remote to-view)
(a/pipe from-view to-remote)))
from-state (state/update-state-and-render to-state)]
(a/pipe from-remote to-state)
(a/pipe from-state to-remote)))
(wire-channels-together)

59
src/cljs/grub/state.cljs Normal file
View file

@ -0,0 +1,59 @@
(ns grub.state
(:require [grub.view :as view]
[cljs.core.async :as a :refer [<! >! chan]])
(:require-macros [grub.macros :refer [log logs]]
[cljs.core.async.macros :refer [go go-loop]]))
(def default-app-state {:grubs {}
:recipes {}})
(defmulti handle-event (fn [event state] (:event event))
:default :unknown-event)
(defmethod handle-event :unknown-event [event grubs]
(logs "Cannot handle unknown event:" event)
grubs)
(defn new-grub [id grub completed]
{:id id :grub grub :completed completed})
(defmethod handle-event :add-grub [event grubs]
(let [grub (new-grub (:id event) (:grub event) (:completed event))]
(assoc grubs (:id grub) grub)))
(defn assoc-new-grub [current new]
(assoc current (:id new)
(new-grub (:id new) (:grub new) (:completed new))))
(defn make-add-grubs-map [grub-events]
(reduce assoc-new-grub {} grub-events))
(defmethod handle-event :add-grub-list [event grubs]
(let [add-grub-events (:grubs event)
add-grubs (make-add-grubs-map add-grub-events)]
(merge grubs add-grubs)))
(defmethod handle-event :complete-grub [event grubs]
(assoc-in grubs [(:id event) :completed] true))
(defmethod handle-event :uncomplete-grub [event grubs]
(assoc-in grubs [(:id event) :completed] false))
(defmethod handle-event :update-grub [event grubs]
(assoc-in grubs [(:id event) :grub] (:grub event)))
(defmethod handle-event :clear-all-grubs [event grubs]
{})
(defn update-state-and-render [remote-chan]
(let [out (chan)]
(go-loop [state default-app-state]
(let [event (<! remote-chan)
new-grubs (handle-event event (:grubs state))
new-state (assoc state :grubs new-grubs)]
(logs "event:" event)
(logs "new-state")
(logs new-state)
(view/render-body new-state)
(recur new-state)))
out))

View file

@ -1,24 +1,364 @@
(ns grub.view
(:require [grub.view.dom :as dom]
[grub.view.grub :as grub-view]
[grub.view.recipe :as recipe-view]
[dommy.core :as dommy]
[cljs.core.async :as a :refer [<! >! chan]])
(:require-macros [grub.macros :refer [log logs and-let]]
[dommy.macros :refer [deftemplate sel1 node]]
[cljs.core.async.macros :refer [go go-loop]]))
(:require [dommy.core :as dommy]
[cljs.core.async :as a :refer [<! >! chan]]
[om.core :as om :include-macros true]
[om.dom :as dom :include-macros true]
[sablono.core :as html :refer-macros [html]])
(:require-macros [grub.macros :refer [log logs]]
[dommy.macros :refer [sel1]]
[cljs.core.async.macros :refer [go]]))
(defn setup-and-get-view-events [remote-channel]
(dom/render-body)
(let [out (chan)
remote (a/mult remote-channel)
to-grubs (chan)
to-recipes (chan)
from-grubs (grub-view/handle-grubs to-grubs)
from-recipes (a/mult (recipe-view/handle-recipes to-recipes))]
(a/tap remote to-grubs)
(a/tap remote to-recipes)
(a/tap from-recipes to-grubs)
(a/tap from-recipes out)
(a/pipe from-grubs out)
out))
(defn listen
([el type] (listen el type nil))
([el type f] (listen el type f (chan)))
([el type f out]
(let [push-fn (fn [e] (when f (f e)) (go (>! out e)))
unlisten #(do (dommy/unlisten! el type push-fn)
(a/close! out))]
(dommy/listen! el type push-fn)
{:chan out :unlisten unlisten})))
(def ENTER-KEYCODE 13)
(defn listen-once
([el type] (listen el type nil))
([el type f] (listen el type f (chan)))
([el type f out]
(let [push-fn (fn [e] (when f (f e)) (go (>! out e)))
unlisten #(do (dommy/unlisten! el type push-fn)
(a/close! out))]
(dommy/listen-once! el type push-fn)
{:chan out :unlisten unlisten})))
(defn get-away-clicks [elem]
(let [{c :chan unlisten :unlisten} (listen (sel1 :body) :click)
filtered-chan (a/filter< #(not (dommy/descendant? (.-target %) elem)) c)]
{:unlisten unlisten :chan filtered-chan}))
(defn get-clicks [elem]
(listen elem :click))
(defn get-enters [elem]
(let [{c :chan unlisten :unlisten} (listen elem :keyup)
filtered-chan (a/filter< #(= (.-which %) ENTER-KEYCODE) c)]
{:unlisten unlisten
:chan filtered-chan}))
(defn get-ctrl-enters []
(let [{c :chan unlisten :unlisten} (listen (sel1 :body) :keyup)
filtered-chan (a/filter< #(and (= (.-which %) ENTER-KEYCODE)
(.-ctrlKey %))
c)]
{:chan filtered-chan :unlisten unlisten}))
(defn get-body-enters []
(get-enters (sel1 :body)))
(def add-grub-btn
[:button.btn.btn-primary {:id "add-grub-btn" :type "button"} "Add"])
(def clear-all-btn
[:button.btn.hidden.pull-right
{:id "clear-all-btn" :type "button"}
"Clear all"])
(defn clear-grubs! []
(dommy/set-html! (sel1 :#grub-list) ""))
(defn get-grub-completed-glyph [completed]
(if completed
[:span.glyphicon.glyphicon-check]
[:span.glyphicon.glyphicon-unchecked]))
(defn make-grub-node [id grub completed]
[:li.list-group-item.grub-item
{:id id
:class (when completed "completed")}
[:span.grub-static
(get-grub-completed-glyph completed)
[:span.grub-text grub]]
[:input.grub-input {:type "text" :value grub}]])
(defn grubs-selector []
[(sel1 :#grub-list) :.grub-item])
(defn make-recipe-node
([id name grubs] (make-recipe-node id name grubs false))
([id name grubs new-recipe]
[:div.panel.panel-default.recipe-panel
{:id id}
[:div.panel-heading.recipe-header
[:input.form-control.recipe-header-input
{:id "recipe-name"
:type "text"
:placeholder "Grub pie"
:value name}]
(when-not new-recipe
[:button.btn.btn-primary.btn-sm.recipe-add-grubs-btn {:type "button"} "Add Grubs"])]
[:div.panel-body.recipe-grubs.hidden
[:textarea.form-control.recipe-grubs-input
{:id "recipe-grubs"
:rows 3
:placeholder "2 grubs"}
grubs]
[:button.btn.btn-primary.hidden.pull-right.recipe-btn.recipe-done-btn
{:type "button"} "Done"]]]))
(def new-recipe (make-recipe-node "new-recipe" "" "" true))
(def new-recipe-done-btn
(sel1 new-recipe ".recipe-done-btn"))
(defn recipes-selector []
[(sel1 :#recipe-list) :.recipe-panel])
(defn recipe-done-btns-selector []
[(sel1 :body) :.recipe-done-btn])
(defn recipe-done-btn-selector [recipe-elem]
(sel1 recipe-elem :.recipe-done-btn))
(defn recipe-add-grubs-btns-selector []
[(sel1 :body) :.recipe-add-grubs-btn])
(defn grub-list-template [grubs]
(for [grub grubs]
(make-grub-node (:id grub) (:grub grub) (:completed grub))))
(defn render-grub-list [grubs]
(let [grub-list (sel1 :#grub-list)]
(aset grub-list "innerHTML" "")
(dommy/replace-contents! grub-list (grub-list-template grubs))))
(defn get-add-grub-text []
(dommy/value (sel1 :#add-grub-input)))
(defn clear-add-grub-text []
(dommy/set-value! (sel1 :#add-grub-input) ""))
(defn get-recipe-add-grubs-clicks []
(->> (:chan (listen (recipe-add-grubs-btns-selector) :click))
(a/map< #(dommy/closest (.-selectedTarget %) :.recipe-panel))))
(defn get-edit-recipe-input-click []
(->> (:chan (listen-once (recipes-selector) :click))
(a/filter< #(not (dommy/has-class? (.-selectedTarget %) :btn)))
(a/map< #(.-selectedTarget %))))
(defprotocol IHideable
(-hide! [this])
(-show! [this]))
(defprotocol IGrub
(-activate! [this])
(-deactivate! [this])
(-id [this])
(-grub-text [this])
(-complete! [this])
(-uncomplete! [this])
(-completed? [this])
(-set-editing! [this])
(-unset-editing! [this])
(-editing? [this])
(-update-grub! [this grub]))
(defprotocol IRecipe
(-expand! [this])
(-unexpand! [this])
(-update-recipe! [this])
(-get-name [this])
(-get-grubs-str [this])
(-get-grubs [this]))
(defprotocol IClearable
(-clear! [this]))
(extend-type js/HTMLElement
IHideable
(-hide! [this]
(dommy/add-class! this :hidden))
(-show! [this]
(dommy/remove-class! this :hidden)))
(extend-type js/HTMLElement
IGrub
(-activate! [this]
(dommy/add-class! this :grub-active))
(-deactivate! [this]
(dommy/remove-class! this :grub-active))
(-id [this]
(.-id this))
(-grub-text [this]
(.-value (sel1 this :.grub-input)))
(-complete! [this]
(dommy/add-class! this :completed)
(dommy/replace! (sel1 this ".glyphicon")
(get-grub-completed-glyph true)))
(-uncomplete! [this]
(dommy/remove-class! this :completed)
(dommy/replace! (sel1 this ".glyphicon")
(get-grub-completed-glyph false)))
(-completed? [this]
(dommy/has-class? this :completed))
(-set-editing! [this]
(-deactivate! this)
(dommy/add-class! this :edit)
(.focus (sel1 this :input)))
(-unset-editing! [this]
(dommy/remove-class! this :edit))
(-editing? [this]
(dommy/has-class? this :edit)))
(defrecord Grub [elem id grub completed]
dommy.template/PElement
(-elem [this] elem)
IGrub
(-set-editing! [this] (-set-editing! elem))
(-unset-editing! [this] (-unset-editing! elem))
(-editing? [this] (-editing? elem))
(-complete! [this] (-complete! elem))
(-uncomplete! [this] (-uncomplete! elem))
(-completed? [this] (-completed? elem))
(-set-editing! [this] (-set-editing! elem))
(-unset-editing! [this] (-unset-editing! elem))
(-editing? [this] (-editing? elem))
(-update-grub! [this grub]
(dommy/set-text! (sel1 elem ".grub-text") grub)
(dommy/set-value! (sel1 elem ".grub-input") grub)))
(defn make-new-grub [id grub completed]
(let [node (make-grub-node id grub completed)
grub (Grub. node id grub completed)
grub-list (sel1 :#grub-list)]
grub))
(defn clear-new-grub-input! []
(dommy/set-value! (sel1 :#add-grub-input) ""))
(defn focus-new-grub-input! []
(.focus (sel1 :#add-grub-input)))
(extend-type js/HTMLDivElement
IRecipe
(-expand! [this]
(dommy/remove-class! (sel1 this ".recipe-grubs") :hidden)
(dommy/remove-class! (sel1 this ".recipe-done-btn") :hidden))
(-unexpand! [this]
(dommy/add-class! (sel1 this ".recipe-grubs") :hidden)
(dommy/add-class! (sel1 this ".recipe-done-btn") :hidden))
(-get-name [this]
(dommy/value (sel1 this :#recipe-name)))
(-get-grubs-str [this]
(dommy/value (sel1 this :#recipe-grubs)))
(-get-grubs [this]
(let [split-grubs (clojure.string/split-lines (-get-grubs-str this))]
(when split-grubs (into [] split-grubs)))))
(extend-type js/HTMLDivElement
IClearable
(-clear! [this]
(dommy/set-value! (sel1 this "#recipe-name") "")
(dommy/set-value! (sel1 this "#recipe-grubs") "")))
(defrecord Recipe [elem id name grubs]
dommy.template/PElement
(-elem [this] elem)
IRecipe
(-expand! [this] (-expand! elem))
(-unexpand! [this] (-unexpand! elem))
(-clear! [this] (-clear! elem))
(-update-recipe! [this]
(dommy/set-value! (sel1 this :#recipe-name) name)
(dommy/set-text! (sel1 this :#recipe-grubs) grubs)))
(defn add-new-recipe! [id name grubs]
(let [node (make-recipe-node id name grubs)
recipe (Recipe. node id name grubs)
recipe-list (sel1 :#recipe-list)]
(dommy/append! recipe-list recipe)
recipe))
(defn grub-view [grub-state owner]
(reify
om/IRender
(render [this]
(let [{:keys [id grub completed]} grub-state]
(html
[:li.list-group-item.grub-item
{:id id
:class (when completed "completed")}
[:span.grub-static
(get-grub-completed-glyph completed)
[:span.grub-text grub]]
[:input.grub-input {:type "text" :value grub}]])))))
(defn get-grub-ingredient [grub]
(let [text (clojure.string/lower-case (:grub grub))
match (re-find #"[a-z]{3}.*$" text)]
match))
(defn sort-grubs [grubs]
(sort-by (juxt :completed get-grub-ingredient) (vals grubs)))
(defn app-view [state owner]
(reify
om/IRender
(render [this]
(let [sorted-grubs (sort-grubs (:grubs state))]
(logs "render app-view state:" state)
(logs "render app-view owner:" owner)
(logs "render grubs:" sorted-grubs)
(html
[:div.container
[:div.row
[:div.col-sm-6.leftmost-column
[:h3 "Grub List"]
[:div.input-group.add-grub-input-form
[:span.input-group-btn
[:input.form-control#add-grub-input {:type "text" :placeholder "2 grubs"}]]
[:button.btn.btn-primary {:id "add-grub-btn" :type "button"} "Add"]]
[:ul#grub-list.list-group
(for [grub (vals (:grubs state))]
(om/build grub-view grub))]
[:button.btn.hidden.pull-right
{:id "clear-all-btn" :type "button"}
"Clear all"]]
[:div.col-sm-6
[:h3.recipes-title "Recipes"]
[:div.panel.panel-default.recipe-panel
[:div.panel-heading.recipe-header
[:input.form-control.recipe-header-input
{:id "recipe-name"
:type "text"
:placeholder "Grub pie"}]
[:button.btn.btn-primary.btn-sm.recipe-add-grubs-btn {:type "button"} "Add Grubs"]]
[:div.panel-body.recipe-grubs.hidden
[:textarea.form-control.recipe-grubs-input
{:id "recipe-grubs"
:rows 3
:placeholder "2 grubs"}]
[:button.btn.btn-primary.hidden.pull-right.recipe-btn.recipe-done-btn
{:type "button"} "Done"]]]
[:ul#recipe-list.list-group.recipe-list]]]])))))
(defn render-body [state]
(logs state)
(om/root app-view state {:target (.getElementById js/document "container")}))

View file

@ -4,8 +4,8 @@
[om.core :as om :include-macros true]
[om.dom :as dom :include-macros true]
[sablono.core :as html :refer-macros [html]])
(:require-macros [grub.macros :refer [log logs go-loop]]
[dommy.macros :refer [deftemplate sel1 node]]
(:require-macros [grub.macros :refer [log logs]]
[dommy.macros :refer [sel1]]
[cljs.core.async.macros :refer [go]]))
(defn listen
@ -54,33 +54,30 @@
(defn get-body-enters []
(get-enters (sel1 :body)))
(def add-grub-text
[:input.form-control {:id "add-grub-input" :type "text" :placeholder "2 grubs"}])
(def add-grub-btn
[:button.btn.btn-primary {:id "add-grub-btn" :type "button"} "Add"])
(def clear-all-btn
(node [:button.btn.hidden.pull-right
{:id "clear-all-btn" :type "button"}
"Clear all"]))
[:button.btn.hidden.pull-right
{:id "clear-all-btn" :type "button"}
"Clear all"])
(defn clear-grubs! []
(dommy/set-html! (sel1 :#grub-list) ""))
(defn get-grub-completed-glyph [completed]
(node (if completed
(if completed
[:span.glyphicon.glyphicon-check]
[:span.glyphicon.glyphicon-unchecked])))
[:span.glyphicon.glyphicon-unchecked]))
(defn make-grub-node [id grub completed]
(node [:li.list-group-item.grub-item
{:id id
:class (when completed "completed")}
[:span.grub-static
(get-grub-completed-glyph completed)
[:span.grub-text grub]]
[:input.grub-input {:type "text" :value grub}]]))
[:li.list-group-item.grub-item
{:id id
:class (when completed "completed")}
[:span.grub-static
(get-grub-completed-glyph completed)
[:span.grub-text grub]]
[:input.grub-input {:type "text" :value grub}]])
(defn grubs-selector []
[(sel1 :#grub-list) :.grub-item])
@ -88,24 +85,24 @@
(defn make-recipe-node
([id name grubs] (make-recipe-node id name grubs false))
([id name grubs new-recipe]
(node [:div.panel.panel-default.recipe-panel
{:id id}
[:div.panel-heading.recipe-header
[:input.form-control.recipe-header-input
{:id "recipe-name"
:type "text"
:placeholder "Grub pie"
:value name}]
(when-not new-recipe
[:button.btn.btn-primary.btn-sm.recipe-add-grubs-btn {:type "button"} "Add Grubs"])]
[:div.panel-body.recipe-grubs.hidden
[:textarea.form-control.recipe-grubs-input
{:id "recipe-grubs"
:rows 3
:placeholder "2 grubs"}
grubs]
[:button.btn.btn-primary.hidden.pull-right.recipe-btn.recipe-done-btn
{:type "button"} "Done"]]])))
[:div.panel.panel-default.recipe-panel
{:id id}
[:div.panel-heading.recipe-header
[:input.form-control.recipe-header-input
{:id "recipe-name"
:type "text"
:placeholder "Grub pie"
:value name}]
(when-not new-recipe
[:button.btn.btn-primary.btn-sm.recipe-add-grubs-btn {:type "button"} "Add Grubs"])]
[:div.panel-body.recipe-grubs.hidden
[:textarea.form-control.recipe-grubs-input
{:id "recipe-grubs"
:rows 3
:placeholder "2 grubs"}
grubs]
[:button.btn.btn-primary.hidden.pull-right.recipe-btn.recipe-done-btn
{:type "button"} "Done"]]]))
(def new-recipe (make-recipe-node "new-recipe" "" "" true))
@ -124,36 +121,9 @@
(defn recipe-add-grubs-btns-selector []
[(sel1 :body) :.recipe-add-grubs-btn])
(deftemplate main-template []
[:div.container
[:div.row
[:div.col-sm-6.leftmost-column
[:h3 "Grub List"]
[:div#addGrubInput]
[:ul#grub-list.list-group]
clear-all-btn]
[:div.col-sm-6
[:h3.recipes-title "Recipes"]
new-recipe
[:ul#recipe-list.list-group.recipe-list]]]])
(deftemplate grub-list-template [grubs]
(node (for [grub grubs]
(make-grub-node (:id grub) (:grub grub) (:completed grub)))))
(defn add-grub-input [data]
(om/component
(html [:div.input-group
add-grub-text
[:span.input-group-btn
add-grub-btn]])))
(defn render-om []
(om/root add-grub-input {} {:target (.getElementById js/document "addGrubInput")}))
(defn render-body []
(dommy/prepend! (sel1 :body) (main-template))
(render-om))
(defn grub-list-template [grubs]
(for [grub grubs]
(make-grub-node (:id grub) (:grub grub) (:completed grub))))
(defn render-grub-list [grubs]
(let [grub-list (sel1 :#grub-list)]
@ -325,4 +295,40 @@
recipe-list (sel1 :#recipe-list)]
(dommy/append! recipe-list recipe)
recipe))
(defn grub-view []
(om/component
(html
[:div.container
[:div.row
[:div.col-sm-6.leftmost-column
[:h3 "Grub List"]
[:div.input-group.add-grub-input-form
[:span.input-group-btn
[:input.form-control#add-grub-input {:type "text" :placeholder "2 grubs"}]]
[:button.btn.btn-primary {:id "add-grub-btn" :type "button"} "Add"]]
[:ul#grub-list.list-group]
[:button.btn.hidden.pull-right
{:id "clear-all-btn" :type "button"}
"Clear all"]]
[:div.col-sm-6
[:h3.recipes-title "Recipes"]
[:div.panel.panel-default.recipe-panel
[:div.panel-heading.recipe-header
[:input.form-control.recipe-header-input
{:id "recipe-name"
:type "text"
:placeholder "Grub pie"}]
[:button.btn.btn-primary.btn-sm.recipe-add-grubs-btn {:type "button"} "Add Grubs"]]
[:div.panel-body.recipe-grubs.hidden
[:textarea.form-control.recipe-grubs-input
{:id "recipe-grubs"
:rows 3
:placeholder "2 grubs"}]
[:button.btn.btn-primary.hidden.pull-right.recipe-btn.recipe-done-btn
{:type "button"} "Done"]]]
[:ul#recipe-list.list-group.recipe-list]]]])))
(defn render-body [state]
(logs state)
(om/root grub-view state {:target (.getElementById js/document "container")}))

View file

@ -37,7 +37,7 @@
(a/map< parse-complete-event)))
(defn get-clear-all-events []
(->> (:chan (dom/listen dom/clear-all-btn :click))
(->> (:chan (dom/listen (sel1 :#clear-all-btn) :click))
(a/map< (fn [e] {:event :clear-all-grubs}))))
(defn get-grub-mousedown-events []
@ -127,68 +127,3 @@
(defn sort-and-render-grub-list! [grubs]
(let [sorted-grubs (sort-by (juxt :completed get-grub-ingredient) (vals grubs))]
(dom/render-grub-list sorted-grubs)))
(defmulti handle-event (fn [event grubs] (:event event))
:default :unknown-event)
(defmethod handle-event :unknown-event [event grubs]
;(logs "Cannot handle unknown event:" event)
grubs)
(defmethod handle-event :add-grub [event grubs]
(let [grub (dom/make-new-grub (:id event) (:grub event) (:completed event))
new-grubs (assoc grubs (:id grub) grub)]
(dom/-show! dom/clear-all-btn)
(sort-and-render-grub-list! new-grubs)
(dom/clear-new-grub-input!)
(dom/focus-new-grub-input!)
new-grubs))
(defn assoc-new-grub [current new]
(assoc current (:id new)
(dom/make-new-grub (:id new) (:grub new) (:completed new))))
(defn make-add-grubs-map [grub-events]
(reduce assoc-new-grub {} grub-events))
(defmethod handle-event :add-grub-list [event grubs]
(let [add-grub-events (:grubs event)
add-grubs (make-add-grubs-map add-grub-events)
new-grubs (merge grubs add-grubs)]
(dom/-show! dom/clear-all-btn)
(sort-and-render-grub-list! new-grubs)
new-grubs))
(defmethod handle-event :complete-grub [event grubs]
(let [grub (get grubs (:id event))
new-grubs (assoc-in grubs [(:id event) :completed] true)]
(sort-and-render-grub-list! new-grubs)
new-grubs))
(defmethod handle-event :uncomplete-grub [event grubs]
(let [new-grubs (assoc-in grubs [(:id event) :completed] false)]
(sort-and-render-grub-list! new-grubs)
new-grubs))
(defmethod handle-event :update-grub [event grubs]
(let [new-grubs (assoc-in grubs [(:id event) :grub] (:grub event))]
(sort-and-render-grub-list! new-grubs)
new-grubs))
(defmethod handle-event :clear-all-grubs [event grubs]
(dom/-hide! dom/clear-all-btn)
(dom/clear-grubs!)
{})
(defn handle-grubs [remote-events]
(let [out (chan)
local-events [(get-create-events)
(get-complete-events)
(get-clear-all-events)
(get-update-events)]]
(go-loop [grubs {}]
(let [[event c] (a/alts! (conj local-events remote-events))]
(when-not (= c remote-events)
(>! out event))
(recur (handle-event event grubs))))
out))