Skip to content

Instantly share code, notes, and snippets.

@andreloureiro
Created February 23, 2016 19:58
Show Gist options
  • Select an option

  • Save andreloureiro/dc73873f7eb753cd5d39 to your computer and use it in GitHub Desktop.

Select an option

Save andreloureiro/dc73873f7eb753cd5d39 to your computer and use it in GitHub Desktop.
(ns mimas.core
(:require [om.next :as om :refer-macros [defui]]
[om.dom :as dom]
[goog.dom :as gdom]))
(enable-console-print!)
(println "mimas")
;; --- Utils ---
(defn str->edn [s]
(cljs.reader/read-string s))
;; --- Parser ---
(defmulti readf om/dispatch)
(defmethod readf :task/list
[{:keys [state query]} k _]
{:value (om/db->tree query (get @state k) @state)})
(defmethod readf :project/list
[{:keys [state query parser]} k _]
(let [projects (om/db->tree query (get @state k) @state)
tasks (om/db->tree [:id :title :project] (get @state :task/list) @state)
projects-with-tasks (mapv (fn [project] (assoc project :tasks (filterv #(= (:project %) [:project/by-id (:id project)]) tasks))) projects)]
{:value projects-with-tasks}))
(defmulti mutatef om/dispatch)
(defmethod mutatef 'task/create
[{:keys [state ref]} _ {:keys [task]}]
(let [ref [:task/by-id (:id task)]]
{:action #(swap! state (fn [st]
(-> st
(update :task/list conj ref)
(assoc-in ref task))))}))
(def parser (om/parser {:read readf :mutate mutatef}))
;; --- Reconciler ---
(def state {:project/list [{:id 0 :title "Project#1"}
{:id 1 :title "Project#2"}]
:task/list [{:id 0 :title "Task#1" :project [:project/by-id 1]}
{:id 1 :title "Task#2" :project [:project/by-id 0]}]})
(def reconciler (om/reconciler {:state state
:parser parser}))
;; --- Components ---
(defui TaskInput
Object
(initLocalState [_]
{:title nil
:project nil})
(render [this]
(let [{:keys [create-task projects] :as computed} (om/get-computed this)
{:keys [title project]} (om/get-state this)]
(dom/div nil
(dom/input #js {:type "text"
:value title
:onChange #(om/update-state! this assoc :title (.. % -target -value))
:placeholder "task..."})
(dom/select #js {:value project
:onChange #(om/update-state! this assoc :project (str->edn (.. % -target -value)))}
(map #(dom/option #js {:value `[:project/by-id ~(:id %)]} (:title %)) projects))
(dom/button #js {:onClick #(create-task title project)} "create")))))
(def task-input (om/factory TaskInput))
(defui Project
static om/Ident
(ident [_ {:keys [id]}]
`[:project/by-id ~id])
static om/IQuery
(query [_]
[:id :title]))
(defn render-project [{:keys [title tasks]}]
(dom/li nil title
(dom/ul nil
(map (fn [task] (dom/li nil (:title task))) tasks))))
(defui ProjectList
Object
(render [this]
(let [projects (om/props this)]
(dom/ul nil
(map render-project projects)))))
(def project-list (om/factory ProjectList))
(defui Task
static om/Ident
(ident [_ {:keys [id]}]
`[:task/by-id ~id])
static om/IQuery
(query [_]
[:id :title {:project [:id :title]}])
Object
(render [this]
(let [{:keys [id title project] :as task} (om/props this)]
(dom/li nil (str title " - " (:title project))))))
(def task (om/factory Task {:key-fn :id}))
(defn task-list [list]
(dom/ul nil (map task list)))
(defui ^:once Mimas
static om/IQuery
(query [this]
`[{:task/list ~(om/get-query Task)}
{:project/list ~(om/get-query Project)}])
Object
(create-task [this title project]
(let [task {:id (rand-int 100) :title title :project project}]
(om/transact! this `[(task/create {:task ~task}) :task/list])))
(render [this]
(let [{:keys [task/list] :as props} (om/props this)]
(dom/div nil
(task-input (om/computed props {:projects (:project/list props) :create-task #(.create-task this %1 %2)}))
(dom/p nil "tasks")
(task-list list)
(dom/p nil "projects")
(project-list (:project/list props))))))
(om/add-root!
reconciler
Mimas
(gdom/getElement "app"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment