Haved Clojurescript version of basic functions working and experimental DOM module working.
This commit is contained in:
parent
34c898df37
commit
de3186e8c0
5 changed files with 151 additions and 38 deletions
|
@ -7,7 +7,9 @@
|
|||
[org.clojure/clojurescript "0.0-2371"]]
|
||||
:profiles
|
||||
{:dev
|
||||
{:plugins [[com.cemerick/austin "0.1.5"]]}}
|
||||
{:plugins [[com.cemerick/austin "0.1.5"]]
|
||||
:dependencies
|
||||
[[com.cemerick/clojurescript.test "0.3.1"]]}}
|
||||
:source-paths ["src/clojure"]
|
||||
:javac-options ["-Xlint:unchecked"]
|
||||
:java-source-paths ["src/java"])
|
||||
|
|
|
@ -1,9 +1,24 @@
|
|||
(ns freactive.core
|
||||
(:refer-clojure :exclude [atom]))
|
||||
|
||||
(def ^:dynamic *register-dep* (constantly nil))
|
||||
(def ^:dynamic *register-dep* nil)
|
||||
|
||||
(deftype ReactiveAtom [state meta validator watches]
|
||||
(defn register-dep [ref]
|
||||
(when *register-dep* (*register-dep* ref)))
|
||||
|
||||
(defprotocol IInvalidates
|
||||
(-notify-invalidation-watches [this])
|
||||
(-add-invalidation-watch [this key f])
|
||||
(-remove-invalidation-watch [this key]))
|
||||
|
||||
|
||||
(defn add-invalidation-watch [this key f]
|
||||
(-add-invalidation-watch this key f))
|
||||
|
||||
(defn remove-invalidation-watch [this key]
|
||||
(-remove-invalidation-watch this key))
|
||||
|
||||
(deftype ReactiveAtom [state meta validator watches invalidation-watches]
|
||||
Object
|
||||
(equiv [this other]
|
||||
(-equiv this other))
|
||||
|
@ -14,8 +29,8 @@
|
|||
(-equiv [o other] (identical? o other))
|
||||
|
||||
IDeref
|
||||
(-deref [_]
|
||||
(*register-dep* thi)
|
||||
(-deref [this]
|
||||
(register-dep this)
|
||||
state)
|
||||
|
||||
IMeta
|
||||
|
@ -23,7 +38,7 @@
|
|||
|
||||
IPrintWithWriter
|
||||
(-pr-writer [a writer opts]
|
||||
(-write writer "#<Atom: ")
|
||||
(-write writer "#<ReactiveAtom: ")
|
||||
(pr-writer state writer opts)
|
||||
(-write writer ">"))
|
||||
|
||||
|
@ -38,9 +53,70 @@
|
|||
(set! (.-watches this) (dissoc watches key)))
|
||||
|
||||
IHash
|
||||
(-hash [this] (goog/getUid this)))
|
||||
(-hash [this] (goog/getUid this))
|
||||
|
||||
(deftype Reactive [state dirty f deps meta]
|
||||
IInvalidates
|
||||
(-notify-invalidation-watches [this]
|
||||
(doseq [[key f] invalidation-watches]
|
||||
(f key this)))
|
||||
(-add-invalidation-watch [this key f]
|
||||
(set! (.-invalidation-watches this) (assoc invalidation-watches key f))
|
||||
this)
|
||||
(-remove-invalidation-watch [this key]
|
||||
(set! (.-invalidation-watches this) (dissoc invalidation-watches key)))
|
||||
|
||||
IReset
|
||||
(-reset! [a new-value]
|
||||
(let [validate (.-validator a)]
|
||||
(when-not (nil? validate)
|
||||
(assert (validate new-value) "Validator rejected reference state"))
|
||||
(let [old-value (.-state a)]
|
||||
(set! (.-state a) new-value)
|
||||
(when-not (nil? (.-watches a))
|
||||
(-notify-watches a old-value new-value))
|
||||
(when-not (nil? (.-invalidation-watches a))
|
||||
(-notify-invalidation-watches a))
|
||||
new-value)))
|
||||
|
||||
ISwap
|
||||
(-swap! [a f]
|
||||
(-reset! a (f (.-state a))))
|
||||
(-swap! [a f x]
|
||||
(-reset! a (f (.-state a) x)))
|
||||
(-swap! [a f x y]
|
||||
(-reset! a (f (.-state a) x y)))
|
||||
(-swap! [a f x y more]
|
||||
(-reset! a (apply f (.-state a) x y more))))
|
||||
|
||||
(defn atom
|
||||
"Creates and returns a ReactiveAtom with an initial value of x and zero or
|
||||
more options (in any order):
|
||||
:meta metadata-map
|
||||
:validator validate-fn
|
||||
If metadata-map is supplied, it will be come the metadata on the
|
||||
atom. validate-fn must be nil or a side-effect-free fn of one
|
||||
argument, which will be passed the intended new state on any state
|
||||
change. If the new state is unacceptable, the validate-fn should
|
||||
return false or throw an Error. If either of these error conditions
|
||||
occur, then the value of the atom will not change."
|
||||
([x] (ReactiveAtom. x nil nil nil nil))
|
||||
([x & {:keys [meta validator]}] (ReactiveAtom. x meta validator nil nil)))
|
||||
|
||||
(defn- make-sully-fn [reactive]
|
||||
(fn sully
|
||||
([]
|
||||
(when-not (.-dirty reactive)
|
||||
(set! (.-dirty reactive) true)
|
||||
(-notify-invalidation-watches reactive)))
|
||||
([key ref]
|
||||
(-remove-invalidation-watch ref key)
|
||||
(sully))
|
||||
([key ref _ _]
|
||||
(-remove-watch ref key)
|
||||
(sully))))
|
||||
|
||||
(deftype ReactiveComputation [^:mutable state ^:mutable dirty f ^:mutable deps meta
|
||||
^:mutable watches ^:mutable invalidation-watches sully]
|
||||
Object
|
||||
(equiv [this other]
|
||||
(-equiv this other))
|
||||
|
@ -49,18 +125,30 @@
|
|||
(-equiv [o other] (identical? o other))
|
||||
|
||||
IDeref
|
||||
(-deref [_]
|
||||
(*register-dep* thi)
|
||||
(-deref [this]
|
||||
(register-dep this)
|
||||
(if-not dirty
|
||||
state
|
||||
(binding [*register-deps* nil])))
|
||||
(binding [*register-dep*
|
||||
(fn [ref]
|
||||
(cond
|
||||
(satisfies? IInvalidates ref)
|
||||
(-add-invalidation-watch ref this sully)
|
||||
(satisfies? IWatchable ref)
|
||||
(-add-watch ref this sully)))]
|
||||
(set! dirty false)
|
||||
(let [old-val state
|
||||
new-val (f)]
|
||||
(set! state new-val)
|
||||
(-notify-watches this old-val new-val)
|
||||
new-val))))
|
||||
|
||||
IMeta
|
||||
(-meta [_] meta)
|
||||
|
||||
IPrintWithWriter
|
||||
(-pr-writer [a writer opts]
|
||||
(-write writer "#<Atom: ")
|
||||
(-write writer "#<ReactiveComputation: ")
|
||||
(pr-writer state writer opts)
|
||||
(-write writer ">"))
|
||||
|
||||
|
@ -74,5 +162,20 @@
|
|||
(-remove-watch [this key]
|
||||
(set! (.-watches this) (dissoc watches key)))
|
||||
|
||||
IInvalidates
|
||||
(-notify-invalidation-watches [this]
|
||||
(doseq [[key f] invalidation-watches]
|
||||
(f key this)))
|
||||
(-add-invalidation-watch [this key f]
|
||||
(set! (.-invalidation-watches this) (assoc invalidation-watches key f))
|
||||
this)
|
||||
(-remove-invalidation-watch [this key]
|
||||
(set! (.-invalidation-watches this) (dissoc invalidation-watches key)))
|
||||
|
||||
IHash
|
||||
(-hash [this] (goog/getUid this)))
|
||||
|
||||
(defn rx* [f]
|
||||
(let [reactive (ReactiveComputation. nil true f nil nil nil nil nil)]
|
||||
(set! (.-sully reactive) (make-sully-fn reactive))
|
||||
reactive))
|
||||
|
|
|
@ -1,32 +1,34 @@
|
|||
(ns freactive.experimental.dom)
|
||||
(ns freactive.experimental.dom
|
||||
(:require
|
||||
[freactive.core :as r]))
|
||||
|
||||
(defn request-animation-frame [f]
|
||||
(.requestAnimationFrame js/window f))
|
||||
|
||||
(defn- set-style-prop! [elem prop-name prop-value]
|
||||
(let [prop-name (name prop-name)]
|
||||
(aset (.-style prop) prop-name (str prop-value))))
|
||||
(aset (.-style elem) prop-name (str prop-value))))
|
||||
|
||||
(defn- set-attr! [elem attr-name attr-value]
|
||||
(let [attr-name (name attr-name)]
|
||||
(.setAttribute elem attr-name attr-value)))
|
||||
|
||||
(defn- on-value-ref-invalidated* [set-fn]
|
||||
(fn on-value-ref-invalidated [ref [element attr-name :as key]]
|
||||
(r/remove-invalidation-watch attr-value-ref key)
|
||||
(fn on-value-ref-invalidated [[element attr-name :as key] ref]
|
||||
(r/remove-invalidation-watch ref key)
|
||||
(request-animation-frame
|
||||
(fn [_]
|
||||
(when (.-parentNode element)
|
||||
(r/add-invalidation-watch attr-value-ref key on-value-ref-invalidated)
|
||||
(set-fn elem attr-name attr-value))))))
|
||||
(r/add-invalidation-watch ref key on-value-ref-invalidated)
|
||||
(set-fn element attr-name @ref))))))
|
||||
|
||||
(defn- bind-syle-prop! [element attr-name attr-value]
|
||||
(defn- bind-style-prop! [element attr-name attr-value]
|
||||
(if (satisfies? cljs.core/IDeref attr-value)
|
||||
((on-attr-value-ref-invalidated set-style-prop!) attr-value [element attr-name])
|
||||
((on-value-ref-invalidated* set-style-prop!) attr-value [element attr-name])
|
||||
(set-style-prop! element attr-name attr-value)))
|
||||
|
||||
(defn- listen! [element evt-name handler]
|
||||
)
|
||||
(.addEventListener element evt-name handler))
|
||||
|
||||
(defn- bind-attr! [element attr-name attr-value]
|
||||
(let [attr-name (name attr-name)]
|
||||
|
@ -42,14 +44,11 @@
|
|||
|
||||
:default
|
||||
(if (satisfies? cljs.core/IDeref attr-value)
|
||||
((on-attr-value-ref-invalidated set-attr!) attr-value [element attr-name])
|
||||
((on-value-ref-invalidated* set-attr!) attr-value [element attr-name])
|
||||
(set-attr! element attr-name attr-value)))))
|
||||
|
||||
(defn- parse-elem-kw [kw]
|
||||
[kw])
|
||||
|
||||
(defn- create-elem [tag]
|
||||
(.createElement js/document (name tag)))
|
||||
(defn- create-elem [kw]
|
||||
(.createElement js/document (name kw)))
|
||||
|
||||
(declare build)
|
||||
|
||||
|
@ -64,7 +63,7 @@
|
|||
(defn- append-child!* [parent child]
|
||||
(let [child (convert-child child)]
|
||||
(.appendChild parent child)
|
||||
chuld))
|
||||
child))
|
||||
|
||||
(defn- replace-child!* [parent new-child old-child]
|
||||
(let [new-child (convert-child new-child)]
|
||||
|
@ -73,12 +72,12 @@
|
|||
|
||||
(defn on-child-ref-invalidated* [parent]
|
||||
(fn on-child-ref-invalidated
|
||||
[attr-value-ref cur-elem]
|
||||
(r/remove-invalidation-watch attr-value-ref wrapper)
|
||||
[cur-elem child-ref]
|
||||
(r/remove-invalidation-watch child-ref cur-elem)
|
||||
(request-animation-frame
|
||||
(fn [_]
|
||||
(r/add-invalidation-watch attr-value-ref cur-elem on-child-ref-invalidated)
|
||||
(let [new-elem @child
|
||||
(r/add-invalidation-watch child-ref cur-elem on-child-ref-invalidated)
|
||||
(let [new-elem @child-ref
|
||||
cur @cur-elem]
|
||||
(reset! cur-elem
|
||||
(if cur
|
||||
|
@ -88,7 +87,7 @@
|
|||
(defn- append-child! [parent child]
|
||||
(if
|
||||
(satisfies? cljs.core/IDeref child)
|
||||
((on-child-ref-invalidated* parent) child (atom nil))
|
||||
((on-child-ref-invalidated* parent) (atom nil) child)
|
||||
|
||||
(append-child!* parent child)))
|
||||
|
||||
|
@ -101,13 +100,10 @@
|
|||
(append-child! elem ch))))
|
||||
|
||||
(defn build [elem-def]
|
||||
(let [[tag id class-name] (parse-elem-kw (first elem-def))
|
||||
elem (create-elem tag)
|
||||
(let [elem (create-elem (first elem-def))
|
||||
attrs? (second elem-def)
|
||||
attrs (when (map? attrs?) attrs?)
|
||||
children (if attrs (nnext elem-def) (next elem-def))]
|
||||
(when id (set-attr! tag "id" id))
|
||||
(when id (set-attr! tag "class" class-name))
|
||||
(doseq [[k v] attrs]
|
||||
(bind-attr! elem k v))
|
||||
(when children
|
||||
|
|
|
@ -137,7 +137,7 @@ public void notifyWatches(Object oldVal, Object newVal){
|
|||
}
|
||||
|
||||
@Override
|
||||
public synchronized IInvalidates addInvalidationWatch(Object key, IFn callback) {
|
||||
public synchronized IInvalidates addInvalidationWatch(final Object key, final IFn callback) {
|
||||
addWatch(key, new AFn() {
|
||||
@Override
|
||||
public Object invoke(Object key, Object ref, Object oldV, Object newV) {
|
||||
|
|
12
test/freactive/core_test.cljs
Normal file
12
test/freactive/core_test.cljs
Normal file
|
@ -0,0 +1,12 @@
|
|||
(ns freactive.core-test
|
||||
(:refer-clojure :exclude [atom])
|
||||
(:require
|
||||
[freactive.core :refer [atom rx*]]
|
||||
[cemerick.cljs.test :refer-macros [deftest is]]))
|
||||
|
||||
(deftest rx-test1
|
||||
(let [r0 (atom 0)
|
||||
r1 (rx* (fn [] (inc @r0)))]
|
||||
(is (= 1 @r1))
|
||||
(swap! r0 inc)
|
||||
(is (= 2 @r1))))
|
Loading…
Reference in a new issue