Haved Clojurescript version of basic functions working and experimental DOM module working.

This commit is contained in:
Aaron Craelius 2014-11-11 18:20:02 -05:00
parent 34c898df37
commit de3186e8c0
5 changed files with 151 additions and 38 deletions

View file

@ -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"])

View file

@ -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))

View file

@ -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

View file

@ -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) {

View 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))))