Skip to content

Instantly share code, notes, and snippets.

@minikomi
Created December 26, 2013 13:47
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save minikomi/8134035 to your computer and use it in GitHub Desktop.
Save minikomi/8134035 to your computer and use it in GitHub Desktop.
(ns chanplay.core
(:require
[goog.dom :as dom]
[goog.events :as events]
[cljs.core.async :as async
:refer [<! >! chan close! sliding-buffer put! alts!]]
[jayq.core
:refer [$ append ajax inner html $deferred when done resolve pipe on] :as jq]
[crate.core :as crate]
)
(:require-macros
[cljs.core.async.macros :as m :refer [go alt!]]
))
(enable-console-print!)
;; Channel helpers
(defn data-from-event [event]
(-> event .-currentTarget $ .data (js->clj :keywordize-keys true)))
(defn fields-value-map [form-selector fields]
(into {} (map
(fn [fld]
[fld (jq/val ($ (str form-selector " input[name=" (name fld) "]")))] )
fields)))
(defn form-submit-chan [form-selector msg-name fields]
(let [rc (chan)]
(on ($ "body") :submit form-selector {}
(fn [e]
(jq/prevent e)
(put! rc [msg-name (fields-value-map form-selector fields)])))
rc))
(defn click-chan [selector msg-name]
(let [rc (chan)]
(on ($ "body") :click selector {}
(fn [e]
(jq/prevent e)
(put! rc [msg-name (data-from-event e)])))
rc))
;; ----------- Templates
(defn modal-form [{:keys [mode] :as state}]
(when (= mode :modal)
[:div.modal
[:h4 "Add Task"]
[:form.new-task-form
[:input.new-task-name {:type "text"
:name "content"
:placeholder "New Task"}]
[:p
[:input {:type "submit" :value "Save" :class "btn btn-primary"}]
[:a {:href "#" :class " cancel btn"} "cancel"]]]]))
(defn todo-task [idx {:keys [completed] :as task}]
(let [control (if completed
[:i {:class "icon-ok-sign icon-white"} "●"]
[:a {:href "#" :class "check" :data-task-index idx}
[:i {:class "icon-ok-circle icon-white"} "○"]])]
[:li
control
[:span {:class (if completed "completed")}
(:content task)]]
))
(defn todo-list [{:keys [todos] :as state}]
[:div
[:p
[:a {:href "#" :class "new-todo btn btn-primary"} "Add task"]]
[:ul {:class "todo-list unstyled"}
(map-indexed todo-task todos)]
(modal-form state)])
;; ----------- Handlers
(defn handle [state event]
(let [mode (:mode state)
event-type (first event)
event-data (second event)]
(mode
{:list
(case event-type
; change mode to :modal
:add-todo (assoc state :mode :modal)
; change completed status
:complete-todo (assoc-in state [:todos (:taskIndex event-data) :completed] true)
; default
state)
:modal
(case event-type
; change mode to :list
:cancel-modal (assoc state :mode :list)
; create new task
:create-todo (-> state
(assoc :mode :list)
(assoc :todos
(conj (:todos state)
{:content (:content event-data) :completed false})))
; default
state)
})))
;; ---------- App loop
(def initial-state {:mode :list
:todos [{:content "Buy a new car"
:completed false}]})
(let [add-todo (click-chan "a.new-todo" :add-todo)
complete-todo (click-chan ".todo-list a.check" :complete-todo)
cancel-modal (click-chan ".modal a.cancel" :cancel-modal)
create-todo (form-submit-chan ".modal form" :create-todo [:content])]
(go
(loop [state initial-state]
(println state)
; display
(jq/html ($ "#content") (crate/html (todo-list state)))
; handle & recur
(let [event (first (alts! [add-todo complete-todo cancel-modal create-todo]))]
(println event)
(recur (handle state event))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment