Refactored a lot of dom.cljs to support inserts properly, made ref transitions based on alter-meta! and added :binding-initialized and :binding-disposed callbacks. Played with the items view a little.
This commit is contained in:
parent
cf678507b6
commit
0e7134a5d7
4 changed files with 207 additions and 110 deletions
|
@ -8,6 +8,7 @@
|
|||
<div id="root"></div>
|
||||
<script src="js/compiled/out/goog/base.js" type="text/javascript"></script>
|
||||
<script src="js/compiled/app.js" type="text/javascript"></script>
|
||||
<script type="text/javascript">goog.require("freactive.dom_perf");</script>
|
||||
<!--<script type="text/javascript">goog.require("freactive.dom_perf");</script>-->
|
||||
<script type="text/javascript">goog.require("freactive.items_view_test");</script>
|
||||
</body>
|
||||
</html>
|
|
@ -7,15 +7,14 @@
|
|||
|
||||
(defonce ^:private auto-node-id 0)
|
||||
|
||||
;(defonce ^:private element-state-lookup {})
|
||||
(defonce ^:private element-state-lookup #js {})
|
||||
|
||||
(defprotocol IElementSpec
|
||||
(-get-virtual-dom [x]))
|
||||
|
||||
(defrecord ElementSpec [spec]
|
||||
IElementSpec
|
||||
(-get-virtual-dom [x] spec))
|
||||
;(defrecord ElementSpec [spec]
|
||||
; IElementSpec
|
||||
; (-get-virtual-dom [x] spec))
|
||||
|
||||
(defn- dom-node? [x]
|
||||
(> (.-nodeType x) 0))
|
||||
|
@ -36,6 +35,12 @@
|
|||
boolean
|
||||
(-get-virtual-dom [x] (str x)))
|
||||
|
||||
(defn- get-element-spec [x]
|
||||
(if (dom-node? x)
|
||||
(when-let [state (get-element-state x)]
|
||||
(.-element-spec state))
|
||||
x))
|
||||
|
||||
(defn- get-virtual-dom [x]
|
||||
(if x
|
||||
(cond
|
||||
|
@ -54,9 +59,6 @@
|
|||
;; nil values treated as empty "placeholder" text nodes
|
||||
""))
|
||||
|
||||
(defn- reset-element-spec! [dom-node spec]
|
||||
(set! (.-element-spec (get-element-state dom-node)) spec))
|
||||
|
||||
(deftype ElementState [id disposed element-spec child-states])
|
||||
|
||||
(declare set-attr!)
|
||||
|
@ -84,14 +86,10 @@
|
|||
(defn- unregister-from-parent-state [parent-state child-key]
|
||||
;;(set! (.-child-states parent-state) (dissoc (.-child-states parent-state) child))
|
||||
(when-let [child-states (.-child-states parent-state)]
|
||||
(js-delete child-states child-key))
|
||||
)
|
||||
(js-delete child-states child-key)))
|
||||
|
||||
(defn- get-element-spec [x]
|
||||
(if (dom-node? x)
|
||||
(when-let [state (get-element-state x)]
|
||||
(.-element-spec state))
|
||||
x))
|
||||
(defn- reset-element-spec! [dom-node spec]
|
||||
(set! (.-element-spec (get-element-state dom-node)) spec))
|
||||
|
||||
(defprotocol IRemove
|
||||
(-remove! [x]))
|
||||
|
@ -130,46 +128,48 @@
|
|||
|
||||
(defn remove! [x]
|
||||
(if (dom-node? x)
|
||||
(remove-dom-node x)
|
||||
(if-let [node-detaching (get-transition x :node-detaching)]
|
||||
(node-detaching x (fn [] (remove-dom-node x)))
|
||||
(remove-dom-node x))
|
||||
(-remove! x)))
|
||||
|
||||
;; ## Defining Transitions
|
||||
|
||||
(defn- wrap-element-spec [elem-spec]
|
||||
(if (string? elem-spec)
|
||||
(ElementSpec. elem-spec)
|
||||
elem-spec))
|
||||
;(defn- wrap-element-spec [elem-spec]
|
||||
; (if (string? elem-spec)
|
||||
; (ElementSpec. elem-spec)
|
||||
; elem-spec))
|
||||
|
||||
(defn with-transitions [elem-spec transitions]
|
||||
(if (satisfies? IDeref elem-spec)
|
||||
(rx (with-transitions @elem-spec transitions))
|
||||
(vary-meta (wrap-element-spec elem-spec) merge transitions)))
|
||||
(alter-meta! elem-spec merge transitions)
|
||||
(vary-meta elem-spec merge transitions)))
|
||||
|
||||
(defn- exec-transition [node transition-name callback]
|
||||
(if-let [transition (get-transition node transition-name)]
|
||||
(transition node callback)
|
||||
(when callback (callback))))
|
||||
|
||||
(defn- chain-transition [elem-spec transition-name transition-fn chain-fn]
|
||||
(if (satisfies? IDeref elem-spec)
|
||||
(rx (chain-transition @elem-spec transition-name transition-fn chain-fn))
|
||||
(let [cur-transition-fn (get-transition elem-spec transition-name)
|
||||
transition-fn (if cur-transition-fn
|
||||
(chain-fn cur-transition-fn transition-fn)
|
||||
transition-fn)]
|
||||
(with-transitions elem-spec {transition-name transition-fn}))))
|
||||
|
||||
(defn prepend-transition [elem-spec transition-name transition-fn]
|
||||
(chain-transition elem-spec transition-name transition-fn
|
||||
(fn [cur-tx new-tx]
|
||||
(fn [elem on-complete]
|
||||
(new-tx elem (fn [elem _] (cur-tx elem on-complete)))))) )
|
||||
|
||||
(defn append-transition [elem-spec transition-name transition-fn]
|
||||
(chain-transition elem-spec transition-name transition-fn
|
||||
(fn [cur-tx new-tx]
|
||||
(fn [elem on-complete]
|
||||
(cur-tx elem (fn [elem _] (new-tx elem on-complete)))))) )
|
||||
;
|
||||
;(defn- chain-transition [elem-spec transition-name transition-fn chain-fn]
|
||||
; (if (satisfies? IDeref elem-spec)
|
||||
; (rx (chain-transition @elem-spec transition-name transition-fn chain-fn))
|
||||
; (let [cur-transition-fn (get-transition elem-spec transition-name)
|
||||
; transition-fn (if cur-transition-fn
|
||||
; (chain-fn cur-transition-fn transition-fn)
|
||||
; transition-fn)]
|
||||
; (with-transitions elem-spec {transition-name transition-fn}))))
|
||||
;
|
||||
;(defn prepend-transition [elem-spec transition-name transition-fn]
|
||||
; (chain-transition elem-spec transition-name transition-fn
|
||||
; (fn [cur-tx new-tx]
|
||||
; (fn [elem on-complete]
|
||||
; (new-tx elem (fn [elem _] (cur-tx elem on-complete)))))) )
|
||||
;
|
||||
;(defn append-transition [elem-spec transition-name transition-fn]
|
||||
; (chain-transition elem-spec transition-name transition-fn
|
||||
; (fn [cur-tx new-tx]
|
||||
; (fn [elem on-complete]
|
||||
; (cur-tx elem (fn [elem _] (new-tx elem on-complete)))))) )
|
||||
|
||||
;; ## Polyfills
|
||||
|
||||
|
@ -229,12 +229,16 @@
|
|||
(.removeAttribute elem attr-name))
|
||||
|
||||
(defn- set-style-prop! [elem prop-name prop-value]
|
||||
(aset (.-style elem) prop-name (str prop-value)))
|
||||
(aset (.-style elem)
|
||||
prop-name
|
||||
(if (.-substring prop-value)
|
||||
prop-value
|
||||
(.toString prop-value))))
|
||||
|
||||
(defn- remove-style-prop! [elem prop-name]
|
||||
(js-delete (.-style elem) prop-name))
|
||||
|
||||
(defn- on-value-ref-invalidated* [set-fn element state-prefix attr-name ref node-state]
|
||||
(defn- bind-attr* [set-fn element state-prefix attr-name ref node-state]
|
||||
(when-let [[add-watch* remove-watch*] (r/get-add-remove-watch* ref)]
|
||||
(let [attr-state #js {:disposed false}
|
||||
key [element attr-name]
|
||||
|
@ -253,13 +257,14 @@
|
|||
(register-with-parent-state node-state
|
||||
(str "-" state-prefix "." attr-name) attr-state)
|
||||
(add-watch* ref key f)))
|
||||
|
||||
(set-fn @ref))
|
||||
|
||||
(defn- bind-style-prop! [element attr-name attr-value node-state]
|
||||
(let [setter (fn [v] (set-style-prop! element attr-name attr-value))]
|
||||
(let [setter (fn [v]
|
||||
(println "setting style" element attr-name v)
|
||||
(set-style-prop! element attr-name v))]
|
||||
(if (satisfies? cljs.core/IDeref attr-value)
|
||||
(on-value-ref-invalidated* setter element "style" attr-name attr-value node-state)
|
||||
(bind-attr* setter element "style" attr-name attr-value node-state)
|
||||
(setter attr-value))))
|
||||
|
||||
(defn listen! [element evt-name handler]
|
||||
|
@ -291,7 +296,7 @@
|
|||
|
||||
(defn- bind-prop-attr! [set-fn element attr-name attr-value node-state]
|
||||
(if (satisfies? cljs.core/IDeref attr-value)
|
||||
(on-value-ref-invalidated* set-fn element "attr" attr-name
|
||||
(bind-attr* set-fn element "attr" attr-name
|
||||
attr-value node-state)
|
||||
(set-fn attr-value)))
|
||||
|
||||
|
@ -323,7 +328,12 @@
|
|||
(fn [cls] (set! (.-className element) cls))
|
||||
|
||||
:default
|
||||
(fn [attr-value] (.setAttribute element attr-name attr-value))))
|
||||
(fn [attr-value]
|
||||
(.setAttribute
|
||||
element attr-name
|
||||
(if (.-substring attr-value)
|
||||
attr-value
|
||||
(.toString attr-value))))))
|
||||
|
||||
(defn- bind-attr! [element attr-name attr-value node-state]
|
||||
(let [attr-name (name attr-name)]
|
||||
|
@ -494,16 +504,22 @@
|
|||
children)
|
||||
dom-vec)))
|
||||
|
||||
(defn- register-element-with-parent [parent new-elem]
|
||||
(when-not (text-node? new-elem)
|
||||
(when-let [parent-state (get-element-state parent)]
|
||||
(let [state (get-element-state new-elem)]
|
||||
(set! (.-parent-state state) parent-state)
|
||||
(register-with-parent-state parent-state (get-node-id new-elem) state)))))
|
||||
|
||||
(defn- replace-node-completly [parent new-elem-spec cur-dom-node]
|
||||
(let [new-elem (build-element new-elem-spec)]
|
||||
(.replaceChild parent new-elem cur-dom-node)
|
||||
(dispose-node cur-dom-node)
|
||||
new-elem))
|
||||
(register-element-with-parent parent new-elem)
|
||||
(.replaceChild parent new-elem cur-dom-node)
|
||||
(dispose-node cur-dom-node)
|
||||
new-elem))
|
||||
|
||||
(declare replace-child)
|
||||
|
||||
(declare replace-or-append-child)
|
||||
|
||||
(declare append-children!)
|
||||
|
||||
(defn- try-diff-subseq [parent cur-child new-children]
|
||||
|
@ -570,47 +586,40 @@
|
|||
(replace-node-completly parent new-elem-spec cur-dom-node))))
|
||||
(replace-node-completly parent new-elem-spec cur-dom-node)))))
|
||||
|
||||
(defn- insert-child [parent vdom before]
|
||||
(let [new-elem (build-element vdom)]
|
||||
(register-element-with-parent parent new-elem)
|
||||
(.insertBefore parent new-elem before)
|
||||
new-elem))
|
||||
|
||||
(defn- append-child [parent new-elem]
|
||||
(let [new-elem (build-element new-elem)]
|
||||
(.appendChild
|
||||
;(get-dom-node parent)
|
||||
parent
|
||||
new-elem)
|
||||
(register-element-with-parent parent new-elem)
|
||||
(.appendChild parent new-elem)
|
||||
new-elem))
|
||||
|
||||
(defn- register-element-with-parent [parent new-elem]
|
||||
(when-not (text-node? new-elem)
|
||||
(when-let [parent-state (get-element-state parent)]
|
||||
(let [state (get-element-state new-elem)]
|
||||
(set! (.-parent-state state) parent-state)
|
||||
(register-with-parent-state parent-state (get-node-id new-elem) state))))
|
||||
)
|
||||
(defn- append-or-insert-child [parent new-elem before]
|
||||
(if before
|
||||
(insert-child parent new-elem before)
|
||||
(append-child parent new-elem)))
|
||||
|
||||
(defn- replace-or-append-child [parent new-elem cur-elem top-level]
|
||||
(let [new-elem
|
||||
(if cur-elem
|
||||
(replace-child parent new-elem cur-elem top-level)
|
||||
(append-child parent new-elem))]
|
||||
(register-element-with-parent parent new-elem)
|
||||
new-elem))
|
||||
;(defn- do-show-element [parent new-elem nil]
|
||||
; (when new-elem
|
||||
; (let [show (get-transition new-elem :node-attached)
|
||||
; new-elem (replace-or-append-child parent new-elem cur-elem true)]
|
||||
; (when show
|
||||
; (show new-elem)
|
||||
; new-elem)
|
||||
; new-elem)))
|
||||
|
||||
(defn- do-show-element [parent new-elem cur-elem]
|
||||
(when new-elem
|
||||
(let [show (get-transition new-elem :node-attached)
|
||||
new-elem (replace-or-append-child parent new-elem cur-elem true)]
|
||||
(when show
|
||||
(show new-elem)
|
||||
new-elem)
|
||||
new-elem)))
|
||||
|
||||
(defn- transition-element
|
||||
([parent new-elem cur-elem]
|
||||
(if cur-elem
|
||||
(if-let [hide (get-transition cur-elem :node-detaching)]
|
||||
(hide cur-elem
|
||||
(do-show-element parent new-elem cur-elem))
|
||||
(do-show-element parent new-elem cur-elem))
|
||||
(do-show-element parent new-elem cur-elem))))
|
||||
(defn- mount-element
|
||||
([parent new-elem before]
|
||||
(let [show (get-transition new-elem :node-mounted)
|
||||
new-elem (append-or-insert-child parent new-elem before)]
|
||||
(when show
|
||||
(show new-elem)
|
||||
new-elem)
|
||||
new-elem)))
|
||||
|
||||
(defn- clear-children! [parent]
|
||||
(let [dom-node parent
|
||||
|
@ -650,7 +659,7 @@
|
|||
(when-let [parent-state (get-element-state parent)]
|
||||
(unregister-from-parent-state parent-state id))))
|
||||
|
||||
(defn- append-deref-child [parent child-ref]
|
||||
(defn- bind-child [parent child-ref before]
|
||||
(if-let [[add-watch* remove-watch*] (r/get-add-remove-watch* child-ref)]
|
||||
(let [state (ReactiveElement. nil parent nil false false false nil nil)
|
||||
|
||||
|
@ -660,7 +669,10 @@
|
|||
(or (non-reactively @child-ref) ""))
|
||||
|
||||
show-new-elem (fn [new-elem cur]
|
||||
(let [new-node (replace-or-append-child parent new-elem cur true)]
|
||||
(let [new-node
|
||||
(if cur
|
||||
(replace-child parent new-elem cur true)
|
||||
(append-or-insert-child parent new-elem before))]
|
||||
(set! (.-cur-element state) new-node)
|
||||
(set! (.-updating state) false)
|
||||
(when (.-dirty state)
|
||||
|
@ -688,9 +700,7 @@
|
|||
(get-new-elem)
|
||||
new-elem)]
|
||||
(show-new-elem new-elem cur))))))
|
||||
(show-new-elem new-elem cur)))
|
||||
|
||||
)))))
|
||||
(show-new-elem new-elem cur))))))))
|
||||
|
||||
invalidate
|
||||
(fn on-child-ref-invalidated
|
||||
|
@ -703,26 +713,38 @@
|
|||
(when-not (.-updating state)
|
||||
(set! (.-updating state) true)
|
||||
(queue-animation animate)))))]
|
||||
|
||||
(set! (.-animate state) animate)
|
||||
(set! (.-invalidate state) invalidate)
|
||||
(show-new-elem (get-new-elem) nil)
|
||||
;(set! (.-cur-element state)
|
||||
; (transition-element parent (or (non-reactively @child-ref) [:span]) nil))
|
||||
(when-let [binding-disposed (get (meta child-ref) :binding-disposed)]
|
||||
(set! (.-disposed-callback state) binding-disposed))
|
||||
(when-let [parent-state (get-element-state parent)]
|
||||
(register-with-parent-state parent-state "-reactive" state))
|
||||
(when-let [binding-initialized (get (meta child-ref)
|
||||
:binding-initialized)]
|
||||
(binding-initialized))
|
||||
(set! (.-updating state) false)
|
||||
;(let [new-node (append-or-insert-child parent (get-new-elem) before)]
|
||||
; (set! (.-cur-element state) new-node)
|
||||
; (when-let [node-mounted (get-transition new-node :node-attached)]
|
||||
; (node-mounted new-node))
|
||||
; (when (.-dirty state)
|
||||
; (queue-animation (.-animate state))))
|
||||
(show-new-elem (get-new-elem) nil)
|
||||
state)
|
||||
(transition-element parent @child-ref nil)))
|
||||
(mount-element parent @child-ref before)))
|
||||
|
||||
;; Building Elements
|
||||
|
||||
(defn append-child! [parent child]
|
||||
(defn insert-child! [parent child before]
|
||||
(cond
|
||||
(satisfies? IDeref child)
|
||||
(append-deref-child parent child)
|
||||
(bind-child parent child before)
|
||||
|
||||
:default
|
||||
(transition-element parent child nil)))
|
||||
(mount-element parent child before)))
|
||||
|
||||
(defn append-child! [parent child]
|
||||
(insert-child! parent child nil))
|
||||
|
||||
(defn- append-children! [elem children]
|
||||
(doseq [ch children]
|
||||
|
@ -734,6 +756,7 @@
|
|||
|
||||
(defn build-element [elem-spec]
|
||||
(let [virtual-dom (get-virtual-dom elem-spec)]
|
||||
(println virtual-dom)
|
||||
(cond
|
||||
(string? virtual-dom)
|
||||
(.createTextNode js/document virtual-dom)
|
||||
|
@ -752,6 +775,9 @@
|
|||
(bind-attr! node k v state))
|
||||
(when children
|
||||
(append-children! node children))
|
||||
(when-let [m (-meta virtual-dom)]
|
||||
(when-let [node-created (get m :node-created)]
|
||||
(node-created node)))
|
||||
node))))
|
||||
|
||||
(defn mount! [element child]
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
(-reset-view [view])
|
||||
(-set-view-range [view start end]))
|
||||
|
||||
(defrecord ItemsView [element coll]
|
||||
dom/IHasElement
|
||||
(-get-element [_] element)
|
||||
(deftype ItemsView [element collection]
|
||||
dom/IElementSpec
|
||||
(-get-virtual-dom [_] element)
|
||||
|
||||
dom/IRemove
|
||||
(-remove [_] (dom/-remove element)))
|
||||
(-remove! [_] (dom/remove! element)))
|
||||
|
||||
(deftype ItemContainer [elem state])
|
||||
|
||||
|
@ -48,21 +48,21 @@
|
|||
view (ItemsView. element coll)
|
||||
|
||||
update-fn
|
||||
(fn [view coll changes]
|
||||
(fn [view changes]
|
||||
(doseq [[k v] changes]
|
||||
(let [elem-container (get @elem-mappings k)]
|
||||
(if elem-container
|
||||
(if v
|
||||
(reset! (.-state elem-container) v)
|
||||
(do
|
||||
(dom/-remove (.-elem elem-container))
|
||||
(dom/remove! (.-elem elem-container))
|
||||
(swap! elem-mappings dissoc k)))
|
||||
(when v
|
||||
(let [state (atom v)
|
||||
elem (dom/append-child! (.-element view) (template-fn state))]
|
||||
(swap! elem-mappings assoc k (ItemContainer. elem state))))))))]
|
||||
|
||||
(update-fn view coll @(.-state coll))
|
||||
(update-fn view @(.-state coll))
|
||||
(observe-changes coll view update-fn)
|
||||
|
||||
#_(dom/with-transitions
|
||||
|
|
70
test/freactive/items_view_test.cljs
Normal file
70
test/freactive/items_view_test.cljs
Normal file
|
@ -0,0 +1,70 @@
|
|||
(ns freactive.items-view-test
|
||||
(:refer-clojure :exclude [atom])
|
||||
(:require [freactive.dom :as dom]
|
||||
[freactive.core :refer [atom rx]]
|
||||
[freactive.experimental.observable-collection :refer
|
||||
[observable-collection transact!]]
|
||||
[freactive.experimental.items-view :as items-view]
|
||||
[figwheel.client :as fw]
|
||||
[cljs.core.async :refer [chan put! <!]])
|
||||
(:require-macros
|
||||
[cljs.core.async.macros :refer [go go-loop]]
|
||||
[freactive.macros :refer [rx]]))
|
||||
|
||||
(enable-console-print!)
|
||||
|
||||
(dom/enable-fps-instrumentation!)
|
||||
|
||||
(defn item-view [item]
|
||||
(let [state (atom :viewing)
|
||||
action-ch (chan)]
|
||||
(go-loop []
|
||||
(let [action (<! action-ch)]
|
||||
(case @state
|
||||
:viewing
|
||||
(when (= action :edit)
|
||||
(reset! state :editing))
|
||||
:editing
|
||||
(when (= action :commit)
|
||||
(reset! state :viewing)))
|
||||
(recur)))
|
||||
[:li
|
||||
(dom/with-transitions
|
||||
[:input {:value @item :data-state @state
|
||||
:on-keypress
|
||||
(fn [e]
|
||||
(when (= (.-keyCode e) 13)
|
||||
(put! action-ch :commit)
|
||||
(.preventDefault e)))
|
||||
:on-changed
|
||||
(fn [e] (reset! item (.. e -target -value)))
|
||||
:style {:display
|
||||
(rx
|
||||
(if (= @state :editing)
|
||||
""
|
||||
"none"))}}]
|
||||
{})
|
||||
[:span
|
||||
{:on-mousedown (fn [e] (put! action-ch :edit))
|
||||
:style {:display
|
||||
(rx
|
||||
(if (= @state :viewing)
|
||||
""
|
||||
"none"))}}
|
||||
@item]]))
|
||||
|
||||
(defn view []
|
||||
(let [items (observable-collection {:a 1 :b 2})
|
||||
items-view (items-view/items-view :ul item-view
|
||||
items)]
|
||||
[:div
|
||||
items-view
|
||||
[:div
|
||||
[:span "New Item:"]
|
||||
[:button {:on-click (fn [e] (transact! items [:assoc! 0 57]))} "Add"]
|
||||
]
|
||||
]))
|
||||
|
||||
(dom/mount! (.getElementById js/document "root") (view))
|
||||
|
||||
(fw/watch-and-reload)
|
Loading…
Reference in a new issue