Add directions to recipes
This commit is contained in:
parent
f8af086c19
commit
0e2f13d63d
3 changed files with 141 additions and 100 deletions
|
@ -9,10 +9,11 @@
|
|||
(:require-macros [grub.macros :refer [log logs]]
|
||||
[cljs.core.async.macros :refer [go go-loop]]))
|
||||
|
||||
(defn new-recipe [name grubs]
|
||||
(defn new-recipe [name grubs directions]
|
||||
{:id (str "recipe-" (uuid/make-random))
|
||||
:name name
|
||||
:grubs grubs})
|
||||
:grubs grubs
|
||||
:directions directions})
|
||||
|
||||
(defn parse-grubs-from-str [grubs-str]
|
||||
(->> grubs-str
|
||||
|
@ -36,18 +37,23 @@
|
|||
(condp = [current next]
|
||||
[:editing :waiting] (let [recipe (om/get-props owner)
|
||||
name (om/get-state owner :name)
|
||||
grubs (om/get-state owner :grubs)]
|
||||
(when-not (and (= name (:name @recipe))
|
||||
(= grubs (:grubs @recipe)))
|
||||
(om/transact! recipe
|
||||
nil
|
||||
#(assoc % :name name :grubs grubs)
|
||||
grubs (om/get-state owner :grubs)
|
||||
directions (om/get-state owner :directions)]
|
||||
(when (or (not= name (:name @recipe))
|
||||
(not= grubs (:grubs @recipe))
|
||||
(not= directions (:directions @recipe)))
|
||||
(om/transact! recipe nil #(assoc %
|
||||
:name name
|
||||
:grubs grubs
|
||||
:directions directions)
|
||||
:local)))
|
||||
nil)
|
||||
(when-not (= current next) (om/set-state! owner :edit-state next))))
|
||||
|
||||
(defn num-newlines [str]
|
||||
(count (re-seq #"\n" str)))
|
||||
(if (or (nil? str) (empty? str))
|
||||
1
|
||||
(count (re-seq #"\n" str))))
|
||||
|
||||
(defn view [{:keys [id] :as recipe} owner {:keys [remove-recipe-ch]}]
|
||||
(reify
|
||||
|
@ -57,6 +63,7 @@
|
|||
{:edit-state :waiting
|
||||
:name (:name recipe)
|
||||
:grubs (:grubs recipe)
|
||||
:directions (:directions recipe)
|
||||
:unmounted false}))
|
||||
|
||||
om/IWillReceiveProps
|
||||
|
@ -67,7 +74,7 @@
|
|||
(om/set-state! owner :grubs grubs)))
|
||||
|
||||
om/IRenderState
|
||||
(render-state [this {:keys [edit-state name grubs]}]
|
||||
(render-state [this {:keys [edit-state name grubs directions]}]
|
||||
(let [update (om/get-shared owner :recipe-update)]
|
||||
(html
|
||||
[:div.panel.panel-default.recipe-panel
|
||||
|
@ -97,6 +104,12 @@
|
|||
:rows (inc (num-newlines grubs))
|
||||
:value grubs
|
||||
:on-change #(om/set-state! owner :grubs (dom/event-val %))}]
|
||||
[:textarea.form-control.recipe-grubs-input
|
||||
{:ref :textarea
|
||||
:rows (inc (num-newlines directions))
|
||||
:value directions
|
||||
:placeholder "Directions"
|
||||
:on-change #(om/set-state! owner :directions (dom/event-val %))}]
|
||||
[:button.btn.btn-danger.pull-left.recipe-remove-btn
|
||||
{:type "button"
|
||||
:on-click #(put! remove-recipe-ch id)}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
(:require [grub.view.dom :as dom]
|
||||
[grub.view.grub :as grub-view]
|
||||
[grub.view.recipe :as recipe]
|
||||
[grub.view.recipe-new :as recipe-new]
|
||||
[om.core :as om :include-macros true]
|
||||
[sablono.core :as html :refer-macros [html]]
|
||||
[cljs.core.async :as a :refer [<! chan]]
|
||||
|
@ -9,99 +10,18 @@
|
|||
(:require-macros [grub.macros :refer [log logs]]
|
||||
[cljs.core.async.macros :refer [go go-loop]]))
|
||||
|
||||
(defn add-recipe [owner name grubs]
|
||||
(when (and (not (empty? name))
|
||||
(not (empty? grubs)))
|
||||
(let [recipes (om/get-props owner)
|
||||
new-recipe (recipe/new-recipe name grubs)]
|
||||
(om/set-state! owner :new-recipe-name "")
|
||||
(om/set-state! owner :new-recipe-grubs "")
|
||||
(om/transact! recipes nil #(assoc % (:id new-recipe) new-recipe) :local))))
|
||||
|
||||
(def transitions
|
||||
{:waiting {:click :editing}
|
||||
:editing {:body-mousedown :waiting
|
||||
:save :waiting}})
|
||||
|
||||
(defn transition-state [owner event]
|
||||
(let [current (om/get-state owner :edit-state)
|
||||
next (or (get-in transitions [current event]) current)]
|
||||
(condp = [current event next]
|
||||
[:editing :save :waiting] (let [add-ch (om/get-shared owner :recipe-add)
|
||||
name (om/get-state owner :new-recipe-name)
|
||||
grubs (om/get-state owner :new-recipe-grubs)]
|
||||
(add-recipe owner name grubs))
|
||||
nil)
|
||||
(om/set-state! owner :edit-state next)))
|
||||
|
||||
(defn new-recipe-view [_ owner]
|
||||
(reify
|
||||
om/IInitState
|
||||
(init-state [_]
|
||||
{:edit-state :waiting
|
||||
:new-recipe-name ""
|
||||
:new-recipe-grubs ""
|
||||
:unmounted false})
|
||||
|
||||
om/IRenderState
|
||||
(render-state [this {:keys [edit-state new-recipe-name new-recipe-grubs]}]
|
||||
(html
|
||||
[:div.panel.panel-default.recipe-panel
|
||||
{:on-click #(when (not (dom/click-on-elem? % (om/get-node owner :save-btn)))
|
||||
(transition-state owner :click))}
|
||||
[:div.panel-heading.recipe-header.new
|
||||
[:input.form-control.recipe-header-input
|
||||
{:id "new-recipe-name"
|
||||
:type "text"
|
||||
:placeholder "New recipe"
|
||||
:value new-recipe-name
|
||||
:on-change #(om/set-state! owner :new-recipe-name (dom/event-val %))}]]
|
||||
[:div.panel-body.recipe-grubs
|
||||
{:class (when (= edit-state :waiting) "hidden")}
|
||||
[:textarea.form-control.recipe-grubs-input
|
||||
{:id "new-recipe-grubs"
|
||||
:rows (inc (recipe/num-newlines new-recipe-grubs))
|
||||
:placeholder "Recipe ingredients"
|
||||
:value new-recipe-grubs
|
||||
:on-change #(om/set-state! owner :new-recipe-grubs (dom/event-val %))}]
|
||||
[:button.btn.btn-primary.pull-right.recipe-done-btn
|
||||
{:type "button"
|
||||
:ref :save-btn
|
||||
:on-click #(transition-state owner :save)}
|
||||
[:span.glyphicon.glyphicon-ok#save-recipe-btn]]]]))
|
||||
|
||||
om/IWillMount
|
||||
(will-mount [_]
|
||||
(let [<events (om/get-shared owner :<events)
|
||||
subscriber (chan)]
|
||||
(a/sub <events :body-mousedown subscriber)
|
||||
(om/set-state! owner :subscriber subscriber)
|
||||
(go-loop [] (let [event (<! subscriber)]
|
||||
(when-not (or (nil? event)
|
||||
(om/get-state owner :unmounted))
|
||||
(when-not (dom/click-on-self? (:event event) (om/get-node owner))
|
||||
(transition-state owner :body-mousedown))
|
||||
(recur))))))
|
||||
|
||||
om/IWillUnmount
|
||||
(will-unmount [_]
|
||||
(let [<events (om/get-shared owner :<events)
|
||||
subscriber (om/get-state owner :subscriber)]
|
||||
(om/set-state! owner :unmounted true)
|
||||
(a/unsub <events :body-mousedown subscriber)
|
||||
(a/close! (om/get-state owner :subscriber))))))
|
||||
|
||||
(defn view [recipes owner]
|
||||
(reify
|
||||
om/IInitState
|
||||
(init-state [_]
|
||||
{:remove-recipe-ch (chan)})
|
||||
{:add-recipe-ch (chan)
|
||||
:remove-recipe-ch (chan)})
|
||||
om/IRenderState
|
||||
(render-state [_ {:keys [remove-recipe-ch]}]
|
||||
(render-state [_ {:keys [remove-recipe-ch add-recipe-ch]}]
|
||||
(html
|
||||
[:div
|
||||
[:h3.recipes-title "Recipes"]
|
||||
(om/build new-recipe-view recipes)
|
||||
(om/build recipe-new/view {} {:opts {:add-recipe-ch add-recipe-ch}})
|
||||
[:ul#recipe-list.list-group.recipe-list
|
||||
(for [recipe (vals recipes)]
|
||||
(om/build recipe/view
|
||||
|
@ -109,8 +29,14 @@
|
|||
{:key :id :opts {:remove-recipe-ch remove-recipe-ch}}))]]))
|
||||
om/IWillMount
|
||||
(will-mount [_]
|
||||
(let [remove-recipe-ch (om/get-state owner :remove-recipe-ch)]
|
||||
(go-loop []
|
||||
(let [removed-id (<! remove-recipe-ch)]
|
||||
(when-not (nil? removed-id)
|
||||
(om/transact! recipes nil #(dissoc % removed-id) :local))))))))
|
||||
(let [add-recipe-ch (om/get-state owner :add-recipe-ch)
|
||||
remove-recipe-ch (om/get-state owner :remove-recipe-ch)]
|
||||
(go (loop []
|
||||
(let [removed-id (<! remove-recipe-ch)]
|
||||
(when-not (nil? removed-id)
|
||||
(om/transact! recipes nil #(dissoc % removed-id) :local))
|
||||
(recur))))
|
||||
(go (loop []
|
||||
(let [added (<! add-recipe-ch)]
|
||||
(om/transact! recipes nil #(assoc % (:id added) added) :local)
|
||||
(recur))))))))
|
||||
|
|
102
src/cljs/grub/view/recipe_new.cljs
Normal file
102
src/cljs/grub/view/recipe_new.cljs
Normal file
|
@ -0,0 +1,102 @@
|
|||
(ns grub.view.recipe-new
|
||||
(:require [grub.view.dom :as dom]
|
||||
[grub.view.recipe :as recipe]
|
||||
[om.core :as om :include-macros true]
|
||||
[sablono.core :as html :refer-macros [html]]
|
||||
[cljs.core.async :as a :refer [<! chan]]
|
||||
[cljs-uuid.core :as uuid])
|
||||
(:require-macros [grub.macros :refer [log logs]]
|
||||
[cljs.core.async.macros :refer [go go-loop]]))
|
||||
|
||||
(defn add-recipe [owner name grubs directions]
|
||||
(when (and (not (empty? name))
|
||||
(not (empty? grubs)))
|
||||
(let [recipes (om/get-props owner)
|
||||
new-recipe (recipe/new-recipe name grubs directions)
|
||||
add-recipe-ch (om/get-state owner :add-recipe-ch)]
|
||||
(om/set-state! owner :new-recipe-name "")
|
||||
(om/set-state! owner :new-recipe-grubs "")
|
||||
(om/set-state! owner :new-recipe-directions "")
|
||||
(a/put! add-recipe-ch new-recipe))))
|
||||
|
||||
(def transitions
|
||||
{:waiting {:click :editing}
|
||||
:editing {:body-mousedown :waiting
|
||||
:save :waiting}})
|
||||
|
||||
(defn transition-state [owner event]
|
||||
(let [current (om/get-state owner :edit-state)
|
||||
next (or (get-in transitions [current event]) current)]
|
||||
(condp = [current event next]
|
||||
[:editing :save :waiting] (let [add-ch (om/get-shared owner :recipe-add)
|
||||
name (om/get-state owner :new-recipe-name)
|
||||
grubs (om/get-state owner :new-recipe-grubs)
|
||||
directions (om/get-state owner :new-recipe-directions)]
|
||||
(add-recipe owner name grubs directions))
|
||||
nil)
|
||||
(om/set-state! owner :edit-state next)))
|
||||
|
||||
(defn view [_ owner {:keys [add-recipe-ch]}]
|
||||
(reify
|
||||
om/IInitState
|
||||
(init-state [_]
|
||||
{:add-recipe-ch add-recipe-ch
|
||||
:edit-state :waiting
|
||||
:new-recipe-name ""
|
||||
:new-recipe-grubs ""
|
||||
:new-recipe-directions ""
|
||||
:unmounted false})
|
||||
|
||||
om/IRenderState
|
||||
(render-state [this {:keys [edit-state new-recipe-name new-recipe-grubs new-recipe-directions]}]
|
||||
(html
|
||||
[:div.panel.panel-default.recipe-panel
|
||||
{:on-click #(when (not (dom/click-on-elem? % (om/get-node owner :save-btn)))
|
||||
(transition-state owner :click))}
|
||||
[:div.panel-heading.recipe-header.new
|
||||
[:input.form-control.recipe-header-input
|
||||
{:id "new-recipe-name"
|
||||
:type "text"
|
||||
:placeholder "New recipe"
|
||||
:value new-recipe-name
|
||||
:on-change #(om/set-state! owner :new-recipe-name (dom/event-val %))}]]
|
||||
[:div.panel-body.recipe-grubs
|
||||
{:class (when (= edit-state :waiting) "hidden")}
|
||||
[:textarea.form-control.recipe-grubs-input
|
||||
{:id "new-recipe-grubs"
|
||||
:rows (inc (recipe/num-newlines new-recipe-grubs))
|
||||
:placeholder "Ingredients"
|
||||
:value new-recipe-grubs
|
||||
:on-change #(om/set-state! owner :new-recipe-grubs (dom/event-val %))}]
|
||||
[:textarea.form-control.recipe-grubs-input
|
||||
{:ref :textarea
|
||||
:rows (inc (recipe/num-newlines new-recipe-directions))
|
||||
:value new-recipe-directions
|
||||
:placeholder "Directions"
|
||||
:on-change #(om/set-state! owner :new-recipe-directions (dom/event-val %))}]
|
||||
[:button.btn.btn-primary.pull-right.recipe-done-btn
|
||||
{:type "button"
|
||||
:ref :save-btn
|
||||
:on-click #(transition-state owner :save)}
|
||||
[:span.glyphicon.glyphicon-ok#save-recipe-btn]]]]))
|
||||
|
||||
om/IWillMount
|
||||
(will-mount [_]
|
||||
(let [<events (om/get-shared owner :<events)
|
||||
subscriber (chan)]
|
||||
(a/sub <events :body-mousedown subscriber)
|
||||
(om/set-state! owner :subscriber subscriber)
|
||||
(go-loop [] (let [event (<! subscriber)]
|
||||
(when-not (or (nil? event)
|
||||
(om/get-state owner :unmounted))
|
||||
(when-not (dom/click-on-self? (:event event) (om/get-node owner))
|
||||
(transition-state owner :body-mousedown))
|
||||
(recur))))))
|
||||
|
||||
om/IWillUnmount
|
||||
(will-unmount [_]
|
||||
(let [<events (om/get-shared owner :<events)
|
||||
subscriber (om/get-state owner :subscriber)]
|
||||
(om/set-state! owner :unmounted true)
|
||||
(a/unsub <events :body-mousedown subscriber)
|
||||
(a/close! (om/get-state owner :subscriber))))))
|
Loading…
Add table
Reference in a new issue