- add re-frame as a project dependency

- move model/db , handlers & history from dj-scratchpad to re-frame
- introduce priviliged protocol history/reset-history! and call from bootstrap
- convert all requires to use new re-frame/handlers
- introduce demo.bootstrap to init system and trigger handler registrations (removed redundant requires elsewhere).
- call bootsrap from main.cljs
- update unit tests
This commit is contained in:
hipitihop 2014-12-11 18:24:19 +10:00
parent a89f8cfa16
commit d37f86989a
5 changed files with 99 additions and 29 deletions

View File

@ -4,7 +4,8 @@
:dependencies [[org.clojure/clojure "1.6.0"]
[org.clojure/clojurescript "0.0-2322"]
[reagent "0.4.3"]]
[reagent "0.4.3"]
[historian "1.0.7"]]
:profiles {:debug {:debug true}
:dev {:dependencies [[spellhouse/clairvoyant "0.0-48-gf5e59d3"]]
@ -24,7 +25,7 @@
:jar-exclusions [#"(?:^|\/)re-frame-demo\/"]
:cljsbuild {:builds [{:id "demo"
:source-paths ["src/demo" "src/re_frame"]
:source-paths ["src" "src/re_frame"]
:compiler {:output-to "run/compiled/demo.js"
:source-map "run/compiled/demo.js.map"
:output-dir "run/compiled/demo"

View File

@ -1,4 +0,0 @@
(ns re-frame.core
(:require [reagent.core :as reagent]
))

11
src/re_frame/db.cljs Normal file
View File

@ -0,0 +1,11 @@
(ns re-frame.db
(:require [reagent.core :as r]))
;; -- application data ---------------------------------------------------------------------------
;;
;; The entire state of the application is stored in this one atom.
;; It is useful to think of this atom as a database, hence its name.
;; For example, when it is mutated, we want it done in "a transaction", so it never appears in
;; an inconsistent state. Atomic operations, etc.
(def ^:private db (r/atom {}))

View File

@ -1,4 +1,5 @@
(ns model.handlers)
(ns re-frame.handlers
(:require [re-frame.db :refer [db]]))
;; -- helpers ------------------------------------------------------------------------------------
@ -25,14 +26,12 @@
validation-fn))))
;; -- application data ---------------------------------------------------------------------------
;;
;; The entire state of the application is stored in this one atom.
;; It is useful to think of this atom as a database, hence its name.
;; For example, when it is mutated, we want it done in "a transaction", so it never appears in
;; an inconsistent state. Atomic operations, etc.
;;
(def ^:private db (atom nil))
(defn get-in-db
"Direct lookup of arbitrary path in state/db without subscription/reaction.
NOTE: While it is convenient to not have to pass values through function chains,
by definition this also incourages non pure functional style, so resist."
[path-v]
(get-in @db path-v))
;; -- Event Handlers ------------------------------------------------------------------------------
@ -84,12 +83,12 @@
;; reagent components call this function when they want to "send" an event.
(defn dispatch ;; TODO: call it (dispatch-event [])
(defn dispatch
[event-v] ;; something like [:delete-item 42]
(let [event-id (first-in-vector event-v)
handler-fn (get @event-id->handler-fn event-id)]
(assert (not (nil? handler-fn)) (str "No event handler registered for event: " event-id ))
(handler-fn @db event-v)))
(handler-fn db event-v)))
@ -119,19 +118,20 @@
(def ^:private subscription-key->handler-fn (atom {}))
(defn register-subscription
[key-v handler-fn]
(if (contains? @subscription-key->handler-fn key-v)
(println "Warning: overwritting a subscription-handler: " key-v)) ;; TODO: more generic logging
(swap! subscription-key->handler-fn assoc key-v handler-fn))
(defn register-subscription
[key-v handler-fn]
(if (contains? @subscription-key->handler-fn key-v)
(println "Warning: overwritting a subscription-handler: " key-v)) ;; TODO: more generic logging
(swap! subscription-key->handler-fn assoc key-v handler-fn))
(defn subscribe
"returns a reagent/reaction which observes a part of the "
[v]
(let [key-v (first-in-vector v)
handler-fn (get @subscription-key->handler-fn key-v)]
(assert (not (nil? handler-fn)) (str "No subscription handler registered for key: " key-v))
(handler-fn @db v)))
(defn subscribe
"returns a reagent/reaction which observes a part of the "
[v]
(let [key-v (first-in-vector v)
handler-fn (get @subscription-key->handler-fn key-v)]
(assert (not (nil? handler-fn)) (str "No subscription handler registered for key: " key-v))
(handler-fn db v)))

62
src/re_frame/history.cljs Normal file
View File

@ -0,0 +1,62 @@
(ns re-frame.history
(:require-macros [reagent.ratom :refer [reaction]]
[historian.core :refer [off-the-record]])
(:require
[reagent.core :as r]
[re-frame.db :refer [db]]
[re-frame.handlers :refer [register-subscription register-handler]]
[historian.core :as historian]
))
;; -- History -----------------------------------------------------------
;; https://day8.slack.com/files/mikhug/F03238WLX/historian.md
(historian/record! db :db)
(def undo-list (r/atom []))
(def redo-list (r/atom []))
(historian/replace-library! undo-list)
(historian/replace-prophecy! redo-list)
(defn reset-history!
"privileged protocol: should not be used by client code"
[]
(historian/clear-history!)
(historian/trigger-record!))
(register-subscription
:undos?
(fn
[_ _]
"answer true is anything is stored in the undo list"
(reaction (> (count @undo-list) 1))))
(register-subscription
:redos?
(fn
[_ _]
"answer true is anything is stored in the redo list"
(reaction (> (count @redo-list) 0))))
;; -------------------------- HANDLERS ----------------------------------------
(register-handler
:undo
(fn
[_ _]
(historian/undo!))) ;; (dispatch [:undo])
(register-handler
:redo
(fn
[_ _]
(historian/redo!))) ;; (dispatch [:undo])
(register-handler
:no-history-while
(fn
[db [_ mutation-fn]]
(off-the-record
(reset! db (mutation-fn @db)))))