Fix aget/aset use with objects

This removes the interop macros which used aget/aset and prevented
Closure naming mangling, now normal property and method access is used
where possible, and goog.object used when using variable keys. Further
testing is needed to ensure this works correctly with Closure, as there
are some properties that are used with goog.object in one place, and as
property in another.

Fixes #324
This commit is contained in:
Juho Teperi 2017-11-18 20:04:52 +02:00
parent 1c5d361070
commit b7304d0f3f
15 changed files with 147 additions and 262 deletions

View File

@ -2,8 +2,7 @@
(:require [clojure.string :as string]
[goog.events :as evt]
[reagent.core :as r]
[reagent.debug :refer-macros [dbg log dev?]]
[reagent.interop :as i :refer-macros [$ $!]])
[reagent.debug :refer-macros [dbg log dev?]])
(:import goog.History
[goog.history Html5History EventType]))

View File

@ -57,7 +57,8 @@
:output-dir "target/cljsbuild/client/public/js/out"
:output-to "target/cljsbuild/client/public/js/main.js"
:asset-path "js/out"
:npm-deps false}}
:npm-deps false
:checked-arrays :warn}}
:client-npm
{:source-paths ["demo"]
@ -68,7 +69,8 @@
:main "reagentdemo.dev"
:output-dir "target/cljsbuild/client-npm/public/js/out"
:output-to "target/cljsbuild/client-npm/public/js/main.js"
:asset-path "js/out"}}
:asset-path "js/out"
:checked-arrays :warn}}
:test
{:source-paths ["test"]

View File

@ -11,7 +11,6 @@
assert-some assert-component
assert-js-object assert-new-state
assert-callable]]
[reagent.interop :refer-macros [$ $!]]
[reagent.dom :as dom]))
(def is-client util/is-client)

View File

@ -4,8 +4,7 @@
[reagent.impl.template :as tmpl]
[reagent.impl.batching :as batch]
[reagent.ratom :as ratom]
[reagent.debug :refer-macros [dbg]]
[reagent.interop :refer-macros [$ $!]]))
[reagent.debug :refer-macros [dbg]]))
(defonce ^:private imported nil)

View File

@ -2,8 +2,7 @@
(:require ["react-dom/server" :as dom-server]
[reagent.impl.util :as util]
[reagent.impl.template :as tmpl]
[reagent.ratom :as ratom]
[reagent.interop :refer-macros [$ $!]]))
[reagent.ratom :as ratom]))
(defonce ^:private imported nil)

View File

@ -1,9 +1,9 @@
(ns reagent.impl.batching
(:refer-clojure :exclude [flush])
(:require [reagent.debug :refer-macros [dbg assert-some]]
[reagent.interop :refer-macros [$ $!]]
[reagent.impl.util :refer [is-client]]
[clojure.string :as string]))
[clojure.string :as string]
[goog.object :as gobj]))
;;; Update batching
@ -19,15 +19,15 @@
(if-not is-client
fake-raf
(let [w js/window]
(or ($ w :requestAnimationFrame)
($ w :webkitRequestAnimationFrame)
($ w :mozRequestAnimationFrame)
($ w :msRequestAnimationFrame)
(or (.-requestAnimationFrame w)
(.-webkitRequestAnimationFrame w)
(.-mozRequestAnimationFrame w)
(.-msRequestAnimationFrame w)
fake-raf))))
(defn compare-mount-order [c1 c2]
(- ($ c1 :cljsMountOrder)
($ c2 :cljsMountOrder)))
(- (.-cljsMountOrder c1)
(.-cljsMountOrder c2)))
(defn run-queue [a]
;; sort components by mount order, to make sure parents
@ -35,8 +35,8 @@
(.sort a compare-mount-order)
(dotimes [i (alength a)]
(let [c (aget a i)]
(when (true? ($ c :cljsIsDirty))
($ c forceUpdate)))))
(when (true? (.-cljsIsDirty c))
(.forceUpdate c)))))
;; Set from ratom.cljs
@ -46,16 +46,16 @@
Object
(enqueue [this k f]
(assert-some f "Enqueued function")
(when (nil? (aget this k))
(aset this k (array)))
(.push (aget this k) f)
(when (nil? (gobj/get this k))
(gobj/set this k (array)))
(.push (gobj/get this k) f)
(.schedule this))
(run-funs [this k]
(when-some [fs (aget this k)]
(aset this k nil)
(when-some [^array fs (gobj/get this k)]
(gobj/set this k nil)
(dotimes [i (alength fs)]
((aget fs i)))))
((gobj/get fs i)))))
(schedule [this]
(when-not scheduled?
@ -81,8 +81,8 @@
(flush-queues [this]
(.run-funs this "beforeFlush")
(ratom-flush)
(when-some [cs (aget this "componentQueue")]
(aset this "componentQueue" nil)
(when-some [cs (.-componentQueue this)]
(set! (.-componentQueue this) nil)
(run-queue cs))
(.flush-after-render this)))
@ -95,12 +95,12 @@
(.flush-after-render render-queue))
(defn queue-render [c]
(when-not ($ c :cljsIsDirty)
($! c :cljsIsDirty true)
(when-not (.-cljsIsDirty c)
(set! (.-cljsIsDirty c) true)
(.queue-render render-queue c)))
(defn mark-rendered [c]
($! c :cljsIsDirty false))
(set! (.-cljsIsDirty c) false))
(defn do-before-flush [f]
(.add-before-flush render-queue f))

View File

@ -4,9 +4,9 @@
[reagent.impl.util :as util]
[reagent.impl.batching :as batch]
[reagent.ratom :as ratom]
[reagent.interop :refer-macros [$ $!]]
[reagent.debug :refer-macros [dbg prn dev? warn error warn-unless
assert-callable]]))
assert-callable]]
[goog.object :as gobj]))
(declare ^:dynamic *current-component*)
@ -16,10 +16,12 @@
(defn shallow-obj-to-map [o]
(let [ks (js-keys o)
len (alength ks)]
(loop [m {} i 0]
(loop [m {}
i 0]
(if (< i len)
(let [k (aget ks i)]
(recur (assoc m (keyword k) (aget o k)) (inc i)))
(recur (assoc m (keyword k) (gobj/get o k))
(inc i)))
m))))
(defn extract-props [v]
@ -33,52 +35,52 @@
(subvec v first-child))))
(defn props-argv [c p]
(if-some [a ($ p :argv)]
(if-some [a (.-argv p)]
a
[(.-constructor c) (shallow-obj-to-map p)]))
(defn get-argv [c]
(props-argv c ($ c :props)))
(props-argv c (.-props c)))
(defn get-props [c]
(let [p ($ c :props)]
(if-some [v ($ p :argv)]
(let [p (.-props c)]
(if-some [v (.-argv p)]
(extract-props v)
(shallow-obj-to-map p))))
(defn get-children [c]
(let [p ($ c :props)]
(if-some [v ($ p :argv)]
(let [p (.-props c)]
(if-some [v (.-argv p)]
(extract-children v)
(->> ($ p :children)
(->> (.-children p)
(react/Children.toArray)
(into [])))))
(defn ^boolean reagent-class? [c]
(and (fn? c)
(some? (some-> c .-prototype ($ :reagentRender)))))
(some? (some-> c .-prototype (.-reagentRender)))))
(defn ^boolean react-class? [c]
(and (fn? c)
(some? (some-> c .-prototype ($ :render)))))
(some? (some-> c .-prototype (.-render)))))
(defn ^boolean reagent-component? [c]
(some? ($ c :reagentRender)))
(some? (.-reagentRender c)))
(defn cached-react-class [c]
($ c :cljsReactClass))
(.-cljsReactClass c))
(defn cache-react-class [c constructor]
($! c :cljsReactClass constructor))
(set! (.-cljsReactClass c) constructor))
;;; State
(defn state-atom [this]
(let [sa ($ this :cljsState)]
(let [sa (.-cljsState this)]
(if-not (nil? sa)
sa
($! this :cljsState (ratom/atom nil)))))
(set! (.-cljsState this) (ratom/atom nil)))))
;; avoid circular dependency: this gets set from template.cljs
(defonce as-element nil)
@ -87,9 +89,9 @@
;;; Rendering
(defn wrap-render [c]
(let [f ($ c :reagentRender)
(let [f (.-reagentRender c)
_ (assert-callable f)
res (if (true? ($ c :cljsLegacyRender))
res (if (true? (.-cljsLegacyRender c))
(.call f c c)
(let [v (get-argv c)
n (count v)]
@ -106,7 +108,7 @@
(fn [& args]
(as-element (apply vector res args)))
res)]
($! c :reagentRender f)
(set! (.-reagentRender c) f)
(recur c))
:else res)))
@ -137,7 +139,7 @@
(fn render []
(this-as c (if util/*non-reactive*
(do-render c)
(let [rat ($ c :cljsRatom)]
(let [rat (.-cljsRatom c)]
(batch/mark-rendered c)
(if (nil? rat)
(ratom/run-in-reaction #(do-render c) c "cljsRatom"
@ -163,8 +165,8 @@
(this-as c
;; Don't care about nextstate here, we use forceUpdate
;; when only when state has changed anyway.
(let [old-argv ($ c :props.argv)
new-argv ($ nextprops :argv)
(let [old-argv (.. c -props -argv)
new-argv (.-argv nextprops)
noargv (or (nil? old-argv) (nil? new-argv))]
(cond
(nil? f) (or noargv (not= old-argv new-argv))
@ -182,7 +184,7 @@
:componentWillMount
(fn componentWillMount []
(this-as c
($! c :cljsMountOrder (batch/next-mount-count))
(set! (.-cljsMountOrder c) (batch/next-mount-count))
(when-not (nil? f)
(.call f c c))))
@ -193,7 +195,7 @@
:componentWillUnmount
(fn componentWillUnmount []
(this-as c
(some-> ($ c :cljsRatom)
(some-> (.-cljsRatom c)
ratom/dispose!)
(batch/mark-rendered c)
(when-not (nil? f)
@ -255,7 +257,7 @@
(defn map-to-js [m]
(reduce-kv (fn [o k v]
(doto o
(aset (name k) v)))
(gobj/set (name k) v)))
#js{} m))
(defn cljsify [body]
@ -273,10 +275,10 @@
(defn fiber-component-path [fiber]
(let [name (some-> fiber
($ :type)
($ :displayName))
(.-type)
(.-displayName))
parent (some-> fiber
($ :return))
(.-:return))
path (some-> parent
fiber-component-path
(str " > "))
@ -286,18 +288,18 @@
(defn component-path [c]
;; Alternative branch for React 16
;; Try both original name (for UMD foreign-lib) and manged name (property access, for Closure optimized React)
(if-let [fiber (or (some-> c ($ :_reactInternalFiber))
(if-let [fiber (or (some-> c (gobj/get "_reactInternalFiber"))
(some-> c (.-_reactInternalFiber)))]
(fiber-component-path fiber)
(let [instance (or (some-> c ($ :_reactInternalInstance))
(let [instance (or (some-> c (gobj/get "_reactInternalInstance"))
(some-> c (.-_reactInternalInstance))
c)
elem (or (some-> instance ($ :_currentElement))
elem (or (some-> instance (gobj/get "_currentElement"))
(some-> instance (.-_currentElement)))
name (some-> elem
($ :type)
($ :displayName))
owner (or (some-> elem ($ :_owner))
(.-type)
(.-displayName))
owner (or (some-> elem (gobj/get "_owner"))
(some-> elem (.-_owner)))
path (some-> owner
component-path

View File

@ -6,9 +6,9 @@
[reagent.impl.component :as comp]
[reagent.impl.batching :as batch]
[reagent.ratom :as ratom]
[reagent.interop :refer-macros [$ $!]]
[reagent.debug :refer-macros [dbg prn println log dev?
warn warn-unless]]))
warn warn-unless]]
[goog.object :as gobj]))
(declare as-element)
@ -44,14 +44,15 @@
(defn cache-get [o k]
(when ^boolean (.hasOwnProperty o k)
(aget o k)))
(gobj/get o k)))
(defn cached-prop-name [k]
(if (named? k)
(if-some [k' (cache-get prop-name-cache (name k))]
k'
(aset prop-name-cache (name k)
(util/dash-to-camel k)))
(let [v (util/dash-to-camel k)]
(gobj/set prop-name-cache (name k))
v))
k))
(defn ^boolean js-val? [x]
@ -61,8 +62,7 @@
(defn kv-conv [o k v]
(doto o
(aset (cached-prop-name k)
(convert-prop-value v))))
(gobj/set (cached-prop-name k) (convert-prop-value v))))
(defn convert-prop-value [x]
(cond (js-val? x) x
@ -82,8 +82,7 @@
(if (named? k)
(if-some [k' (cache-get custom-prop-name-cache (name k))]
k'
(aset prop-name-cache (name k)
(util/dash-to-camel k)))
(gobj/set prop-name-cache (name k) (util/dash-to-camel k)))
k))
(defn custom-kv-conv [o k v]
@ -101,18 +100,18 @@
:else (clj->js x)))
(defn oset [o k v]
(doto (if (nil? o) #js{} o)
(aset k v)))
(doto (if (nil? o) #js {} o)
(gobj/set k v)))
(defn oget [o k]
(if (nil? o) nil (aget o k)))
(if (nil? o) nil (gobj/get o k)))
(defn set-id-class
"Takes the id and class from tag keyword, and adds them to the
other props. Parsed tag is JS object with :id and :class properties."
[props id-class]
(let [id ($ id-class :id)
class ($ id-class :class)]
(let [id (.-id id-class)
class (.-className id-class)]
(cond-> props
;; Only use ID from tag keyword if no :id in props already
(and (some? id)
@ -136,7 +135,7 @@
(let [props (-> props
stringify-class
(set-id-class id-class))]
(if ($ id-class :custom)
(if (.-custom id-class)
(convert-custom-prop-value props)
(convert-prop-value props))))
@ -159,14 +158,14 @@
(defn input-node-set-value
[node rendered-value dom-value component {:keys [on-write]}]
(if-not (and (identical? node ($ js/document :activeElement))
(has-selection-api? ($ node :type))
(if-not (and (identical? node (.-activeElement js/document))
(has-selection-api? (.-type node))
(string? rendered-value)
(string? dom-value))
;; just set the value, no need to worry about a cursor
(do
($! component :cljsDOMValue rendered-value)
($! node :value rendered-value)
(set! (.-cljsDOMValue component) rendered-value)
(set! (.-value node) rendered-value)
(when (fn? on-write)
(on-write rendered-value)))
@ -191,37 +190,37 @@
;; So this is just a warning. The code below is simple
;; enough, but if you are tempted to change it, be aware of
;; all the scenarios you have handle.
(let [node-value ($ node :value)]
(let [node-value (.-value node)]
(if (not= node-value dom-value)
;; IE has not notified us of the change yet, so check again later
(batch/do-after-render #(input-component-set-value component))
(let [existing-offset-from-end (- (count node-value)
($ node :selectionStart))
(.-selectionStart node))
new-cursor-offset (- (count rendered-value)
existing-offset-from-end)]
($! component :cljsDOMValue rendered-value)
($! node :value rendered-value)
(set! (.-cljsDOMValue component) rendered-value)
(set! (.-value node) rendered-value)
(when (fn? on-write)
(on-write rendered-value))
($! node :selectionStart new-cursor-offset)
($! node :selectionEnd new-cursor-offset))))))
(set! (.-selectionStart node) new-cursor-offset)
(set! (.-selectionEnd node) new-cursor-offset))))))
(defn input-component-set-value [this]
(when ($ this :cljsInputLive)
($! this :cljsInputDirty false)
(let [rendered-value ($ this :cljsRenderedValue)
dom-value ($ this :cljsDOMValue)
(when (.-cljsInputLive this)
(set! (.-cljsInputDirty this) false)
(let [rendered-value (.-cljsRenderedValue this)
dom-value (.-cljsDOMValue this)
;; Default to the root node within this component
node (find-dom-node this)]
(when (not= rendered-value dom-value)
(input-node-set-value node rendered-value dom-value this {})))))
(defn input-handle-change [this on-change e]
($! this :cljsDOMValue (-> e .-target .-value))
(set! (.-cljsDOMValue this) (-> e .-target .-value))
;; Make sure the input is re-rendered, in case on-change
;; wants to keep the value unchanged
(when-not ($ this :cljsInputDirty)
($! this :cljsInputDirty true)
(when-not (.-cljsInputDirty this)
(set! (.-cljsInputDirty this) true)
(batch/do-after-render #(input-component-set-value this)))
(on-change e))
@ -234,21 +233,20 @@
(.hasOwnProperty jsprops "value"))
(assert find-dom-node
"reagent.dom needs to be loaded for controlled input to work")
(let [v ($ jsprops :value)
(let [v (.-value jsprops)
value (if (nil? v) "" v)
on-change ($ jsprops :onChange)]
(when-not ($ this :cljsInputLive)
on-change (.-onChange jsprops)]
(when-not (.-cljsInputLive this)
;; set initial value
($! this :cljsInputLive true)
($! this :cljsDOMValue value))
($! this :cljsRenderedValue value)
(set! (.-cljsInputLive this) true)
(set! (.-cljsDOMValue this) value))
(set! (.-cljsRenderedValue this) value)
(js-delete jsprops "value")
(doto jsprops
($! :defaultValue value)
($! :onChange #(input-handle-change this on-change %))))))
(set! (.-defaultValue jsprops) value)
(set! (.-onChange jsprops) #(input-handle-change this on-change %)))))
(defn input-unmount [this]
($! this :cljsInputLive nil))
(set! (.-cljsInputLive this) nil))
(defn ^boolean input-component? [x]
(case x
@ -308,9 +306,9 @@
(defn reag-element [tag v]
(let [c (comp/as-class tag)
jsprops #js{:argv v}]
jsprops #js {:argv v}]
(when-some [key (key-from-vec v)]
($! jsprops :key key))
(set! (.-key jsprops) key))
(react/createElement c jsprops)))
(defn fragment-element [argv]
@ -324,33 +322,36 @@
(defn adapt-react-class
[c]
(doto (->NativeWrapper)
($! :name c)
($! :id nil)
($! :class nil)))
(let [x (->NativeWrapper)]
(set! (.-name x) c)
(set! (.-id x) nil)
(set! (.-class x) nil)
x))
(def tag-name-cache #js{})
(defn cached-parse [x]
(if-some [s (cache-get tag-name-cache x)]
s
(aset tag-name-cache x (parse-tag x))))
(let [v (parse-tag x)]
(gobj/set tag-name-cache x v)
v)))
(defn native-element [parsed argv first]
(let [comp ($ parsed :name)]
(let [props (nth argv first nil)
hasprops (or (nil? props) (map? props))
jsprops (convert-props (if hasprops props) parsed)
first-child (+ first (if hasprops 1 0))]
(if (input-component? comp)
(-> [(reagent-input) argv comp jsprops first-child]
(with-meta (meta argv))
as-element)
(let [key (-> (meta argv) get-key)
p (if (nil? key)
jsprops
(oset jsprops "key" key))]
(make-element argv comp p first-child))))))
(let [comp (.-name parsed)
props (nth argv first nil)
hasprops (or (nil? props) (map? props))
jsprops (convert-props (if hasprops props) parsed)
first-child (+ first (if hasprops 1 0))]
(if (input-component? comp)
(-> [(reagent-input) argv comp jsprops first-child]
(with-meta (meta argv))
as-element)
(let [key (-> (meta argv) get-key)
p (if (nil? key)
jsprops
(oset jsprops "key" key))]
(make-element argv comp p first-child)))))
(defn str-coll [coll]
(if (dev?)
@ -423,7 +424,7 @@
(let [val (aget a i)]
(when (and (vector? val)
(nil? (key-from-vec val)))
($! o :no-key true))
(set! (.-no-key o) true))
(aset a i (as-element val))))
a))
@ -433,7 +434,7 @@
(when derefed
(warn (hiccup-err x "Reactive deref not supported in lazy seq, "
"it should be wrapped in doall")))
(when ($ ctx :no-key)
(when (.-no-key ctx)
(warn (hiccup-err x "Every element in a seq should have a unique :key")))
res))

View File

@ -1,10 +1,9 @@
(ns reagent.impl.util
(:require [reagent.debug :refer-macros [dbg log warn]]
[reagent.interop :refer-macros [$ $!]]
[clojure.string :as string]))
(def is-client (and (exists? js/window)
(-> js/window ($ :document) nil? not)))
(-> (.-document js/window) nil? not)))
(def ^:dynamic ^boolean *non-reactive* false)
@ -40,8 +39,8 @@
(defn fun-name [f]
(let [n (or (and (fn? f)
(or ($ f :displayName)
($ f :name)))
(or (.-displayName f)
(.-name f)))
(and (implements? INamed f)
(name f))
(let [m (meta f)]
@ -137,5 +136,5 @@
(defn force-update [comp deep]
(if deep
(binding [*always-update* true]
($ comp forceUpdate))
($ comp forceUpdate)))
(.forceUpdate comp))
(.forceUpdate comp)))

View File

@ -1,56 +0,0 @@
(ns reagent.interop
(:require [clojure.string :as string :refer [join]]))
(defn- js-call [f args]
(let [argstr (->> (repeat (count args) "~{}")
(join ","))]
(list* 'js* (str "~{}(" argstr ")") f args)))
(defn- dot-args [object member]
(assert (or (symbol? member)
(keyword? member))
(str "Symbol or keyword expected, not " (pr-str member)))
(assert (or (not (symbol? object))
(not (re-find #"\." (name object))))
(str "Dot not allowed in " object))
(let [n (name member)
field? (or (keyword? member)
(= (subs n 0 1) "-"))
names (-> (if (symbol? member)
(string/replace n #"^-" "")
n)
(string/split #"\."))]
[field? names]))
(defmacro $
"Access member in a javascript object, in a Closure-safe way.
'member' is assumed to be a field if it is a keyword or if
the name starts with '-', otherwise the named function is
called with the optional args.
'member' may contain '.', to allow access in nested objects.
If 'object' is a symbol it is not allowed contain '.'.
($ o :foo) is equivalent to (.-foo o), except that it gives
the same result under advanced compilation.
($ o foo arg1 arg2) is the same as (.foo o arg1 arg2)."
[object member & args]
(let [[field names] (dot-args object member)]
(if field
(do
(assert (empty? args)
(str "Passing args to field doesn't make sense: " member))
`(aget ~object ~@names))
(js-call (list* 'aget object names) args))))
(defmacro $!
"Set field in a javascript object, in a Closure-safe way.
'field' should be a keyword or a symbol starting with '-'.
'field' may contain '.', to allow access in nested objects.
If 'object' is a symbol it is not allowed contain '.'.
($! o :foo 1) is equivalent to (set! (.-foo o) 1), except that it
gives the same result under advanced compilation."
[object field value]
(let [[field names] (dot-args object field)]
(assert field (str "Field name must start with - in " field))
`(aset ~object ~@names ~value)))

View File

@ -1,2 +0,0 @@
(ns reagent.interop
(:require-macros [reagent.interop]))

View File

@ -4,7 +4,8 @@
(:require [reagent.impl.util :as util]
[reagent.debug :refer-macros [dbg log warn error dev? time]]
[reagent.impl.batching :as batch]
[clojure.set :as s]))
[clojure.set :as s]
[goog.object :as obj]))
(declare ^:dynamic *ratom-context*)
(defonce ^boolean debug false)
@ -176,7 +177,7 @@
(def ^{:private true :const true} cache-key "reagReactionCache")
(defn- cached-reaction [f o k obj destroy]
(let [m (aget o cache-key)
(let [m (obj/get o cache-key)
m (if (nil? m) {} m)
r (m k nil)]
(cond
@ -185,15 +186,15 @@
:else (let [r (make-reaction
f :on-dispose (fn [x]
(when debug (swap! -running dec))
(as-> (aget o cache-key) _
(as-> (obj/get o cache-key) _
(dissoc _ k)
(aset o cache-key _))
(obj/set o cache-key _))
(when (some? obj)
(set! (.-reaction obj) nil))
(when (some? destroy)
(destroy x))))
v (-deref r)]
(aset o cache-key (assoc m k r))
(obj/set o cache-key (assoc m k r))
(when debug (swap! -running inc))
(when (some? obj)
(set! (.-reaction obj) r))
@ -507,7 +508,7 @@
(._set-opts r opts)
(set! (.-f r) f)
(set! (.-auto-run r) #(run obj))
(aset obj key r))
(obj/set obj key r))
res))
(defn check-derefs [f]

View File

@ -1,7 +1,6 @@
(ns reagenttest.runtests
(:require [reagenttest.testreagent]
[reagenttest.testcursor]
[reagenttest.testinterop]
[reagenttest.testratom]
[reagenttest.testratomasync]
[reagenttest.testtrack]

View File

@ -1,56 +0,0 @@
(ns reagenttest.testinterop
(:require [cljs.test :as t :refer-macros [is deftest]]
[reagent.debug :refer-macros [dbg]]
[reagent.interop :refer-macros [$ $!]]))
;; (def is-adv (let [o #js{}]
;; (set! (.-somethinglong o) true)
;; (not= (aget (.keys js/Object o) 0) "somethinglong")))
(deftest iterop-quote
(let [o #js{:foo "foo"
:foobar #js{:bar "bar"
:bar-foo "bar-foo"}
:bar-foo "barfoo"}]
(is (= "foo" ($ o :foo)))
(is (= "bar" ($ o :foobar.bar)))
(is (= "barfoo" ($ o :bar-foo)))
(is (= "foo" ($ o -foo)))
(is (= "bar" ($ o -foobar.bar)))
(is (= "bar-foo" ($ o -foobar.bar-foo)))
(is (= "bar-foo" ($ o :foobar.bar-foo)))
($! o :foo "foo1")
(is (= "foo1" ($ o :foo)))
($! o -foo "foo2")
(is (= "foo2" ($ o -foo)))
($! o :foobar.bar "bar1")
(is (= "bar1" ($ o :foobar.bar)))
($! o -foobar.bar "bar1")
(is (= "bar1" ($ o -foobar.bar)))))
(deftest interop-quote-call
(let [o #js{:bar "bar1"
:foo (fn [x]
(this-as this
(str x ($ this :bar))))}
o2 #js{:o o}]
(is (= "ybar1" ($ o foo "y")))
(is (= "xxbar1" ($ o2 o.foo "xx")))
(is (= "abar1" (-> o2
($ :o)
($ foo "a"))))
(is (= "bar1" ($ o foo)))
(is (= "bar1" ($ o2 o.foo)))
($! o :bar "bar2")
(is (= "bar2" ($ o foo)))
(is (= "1bar2" ($ ($ o :foo)
call o 1)))))

View File

@ -4,7 +4,6 @@
[create-react-class :as create-react-class]
[reagent.ratom :as rv :refer-macros [reaction]]
[reagent.debug :as debug :refer-macros [dbg println log dev?]]
[reagent.interop :refer-macros [$ $!]]
[reagent.core :as r]
[reagent.dom.server :as server]
[reagent.impl.util :as util]
@ -448,8 +447,8 @@
(this-as
this
(r/create-element
"div" #js{:className ($ this :props.className)}
($ this :props.children))))}))
"div" #js{:className (.. this -props -className)}
(.. this -props -children))))}))
(deftest test-adapt-class
(let [d1 (r/adapt-react-class ndiv)
@ -1055,7 +1054,7 @@
(let [old @spy]
(is (nil? (r/after-render
(fn []
(is (= "DIV" ($ @node :tagName)))
(is (= "DIV" (.-tagName @node)))
(swap! spy inc)))))
(is (= old @spy))
(is (= @exp @val))