11module Halogen.VDom.DOM
2- ( VDomMachine
3- , VDomStep
4- , VDomSpec (..)
2+ ( VDomSpec (..)
53 , buildVDom
64 , buildText
75 , buildElem
@@ -16,26 +14,32 @@ import Data.Function.Uncurried as Fn
1614import Data.Maybe (Maybe (..))
1715import Data.Nullable (toNullable )
1816import Data.Tuple (Tuple (..), fst )
19- import Effect (Effect , foreachE )
17+ import Effect (foreachE )
2018import Effect.Uncurried as EFn
2119import Halogen.VDom.Machine (Step (..), Machine )
2220import Halogen.VDom.Machine as Machine
23- import Halogen.VDom.Types (VDom (..), ElemSpec (..), Namespace (..), runGraft )
21+ import Halogen.VDom.Types (ElemName (..), ElemSpec (..), Namespace (..), VDom (..), runGraft )
2422import Halogen.VDom.Util as Util
2523import Web.DOM.Document (Document ) as DOM
2624import Web.DOM.Element (Element ) as DOM
2725import Web.DOM.Element as DOMElement
2826import Web.DOM.Node (Node ) as DOM
2927
30- type VDomMachine a b = Machine Effect a b
28+ type VDomMachine a w = Machine ( VDom a w ) DOM.Node
3129
32- type VDomStep a b = Effect (Step Effect a b )
30+ type VDomStep a w = Step (VDom a w ) DOM.Node
31+
32+ type VDomInit i a w = EFn.EffectFn1 i (VDomStep a w )
33+
34+ type VDomBuilder i a w = EFn.EffectFn3 (VDomSpec a w ) (VDomMachine a w ) i (VDomStep a w )
35+
36+ type VDomBuilder2 i j a w = EFn.EffectFn4 (VDomSpec a w ) (VDomMachine a w ) i j (VDomStep a w )
3337
3438-- | Widget machines recursively reference the configured spec to potentially
3539-- | enable recursive trees of Widgets.
3640newtype VDomSpec a w = VDomSpec
37- { buildWidget ∷ VDomSpec a w → VDomMachine w DOM.Node
38- , buildAttributes ∷ DOM.Element → VDomMachine a Unit
41+ { buildWidget ∷ VDomSpec a w → Machine w DOM.Node
42+ , buildAttributes ∷ DOM.Element → Machine a Unit
3943 , document ∷ DOM.Document
4044 }
4145
@@ -48,184 +52,167 @@ newtype VDomSpec a w = VDomSpec
4852-- | machine3 ← Machine.step machine2 vdomTree3
4953-- | ...
5054-- | ````
51- buildVDom ∷ ∀ a w . VDomSpec a w → VDomMachine ( VDom a w ) DOM.Node
52- buildVDom spec = render
55+ buildVDom ∷ ∀ a w . VDomSpec a w → VDomMachine a w
56+ buildVDom spec = build
5357 where
54- render = case _ of
55- Text s → buildText spec s
56- Elem es ch → buildElem spec es ch
57- Keyed es ch → buildKeyed spec es ch
58- Widget w → buildWidget spec w
59- Grafted g → buildVDom spec (runGraft g)
60-
61- buildText ∷ ∀ a w . VDomSpec a w → String → VDomStep ( VDom a w ) DOM.Node
62- buildText ( VDomSpec spec) = render
58+ build = EFn .mkEffectFn1 case _ of
59+ Text s → EFn .runEffectFn3 buildText spec build s
60+ Elem es ch → EFn .runEffectFn4 buildElem spec build es ch
61+ Keyed es ch → EFn .runEffectFn4 buildKeyed spec build es ch
62+ Widget w → EFn .runEffectFn3 buildWidget spec build w
63+ Grafted g → EFn .runEffectFn1 build (runGraft g)
64+
65+ buildText ∷ ∀ a w . VDomBuilder String a w
66+ buildText = render
6367 where
64- render s = do
68+ render = EFn .mkEffectFn3 \( VDomSpec spec) build s → do
6569 node ← EFn .runEffectFn2 Util .createTextNode s spec.document
66- pure (Step node (Fn .runFn2 patch node s) (done node))
67-
68- patch = Fn .mkFn2 \node s1 → case _ of
69- Grafted g →
70- Fn .runFn2 patch node s1 (runGraft g)
71- Text s2 → do
72- let res = Step node (Fn .runFn2 patch node s2) (done node)
73- case s1 == s2 of
74- true → pure res
75- _ → do
76- EFn .runEffectFn2 Util .setTextContent s2 node
77- pure res
78- vdom → do
79- done node
80- buildVDom (VDomSpec spec) vdom
70+ let halt = done node
71+ pure (Step node (Fn .runFn4 patch build halt node s) halt)
72+
73+ patch = Fn .mkFn4 \build halt node s1 →
74+ EFn .mkEffectFn1 case _ of
75+ Grafted g →
76+ EFn .runEffectFn1 (Fn .runFn4 patch build halt node s1) (runGraft g)
77+ Text s2 → do
78+ let res = Step node (Fn .runFn4 patch build halt node s2) halt
79+ if s1 == s2
80+ then pure res
81+ else do
82+ EFn .runEffectFn2 Util .setTextContent s2 node
83+ pure res
84+ vdom → do
85+ halt
86+ EFn .runEffectFn1 build vdom
8187
8288 done node = do
83- parent ← pure ( Util .unsafeParent node)
89+ parent ← EFn .runEffectFn1 Util .parentNode node
8490 EFn .runEffectFn2 Util .removeChild node parent
8591
86- buildElem
87- ∷ ∀ a w
88- . VDomSpec a w
89- → ElemSpec a
90- → Array (VDom a w )
91- → VDomStep (VDom a w ) DOM.Node
92- buildElem (VDomSpec spec) = render
92+ buildElem ∷ ∀ a w . VDomBuilder2 (ElemSpec a ) (Array (VDom a w )) a w
93+ buildElem = render
9394 where
94- render es1@(ElemSpec ns1 name1 as1) ch1 = do
95+ render = EFn .mkEffectFn4 \( VDomSpec spec) build es1@(ElemSpec ns1 name1 as1) ch1 → do
9596 el ← EFn .runEffectFn3 Util .createElement (toNullable ns1) name1 spec.document
9697 let
9798 node = DOMElement .toNode el
9899 onChild = EFn .mkEffectFn2 \ix child → do
99- res@Step n m h ← buildVDom ( VDomSpec spec) child
100+ res@Step n m h ← EFn .runEffectFn1 build child
100101 EFn .runEffectFn3 Util .insertChildIx ix n node
101102 pure res
102103 steps ← EFn .runEffectFn2 Util .forE ch1 onChild
103- attrs ← spec.buildAttributes el as1
104- pure
105- (Step node
106- (Fn .runFn4 patch node attrs es1 steps)
107- (Fn .runFn3 done node attrs steps))
108-
109- patch = Fn .mkFn4 \node attrs (es1@(ElemSpec ns1 name1 as1)) ch1 → case _ of
110- Grafted g →
111- Fn .runFn4 patch node attrs es1 ch1 (runGraft g)
112- Elem es2@(ElemSpec ns2 name2 as2) ch2 | Fn .runFn2 eqElemSpec es1 es2 → do
113- case Array .length ch1, Array .length ch2 of
114- 0 , 0 → do
115- attrs' ← Machine .step attrs as2
116- pure
117- (Step node
118- (Fn .runFn4 patch node attrs' es2 ch1)
119- (Fn .runFn3 done node attrs' ch1))
120- _, _ → do
121- let
122- onThese = EFn .mkEffectFn3 \ix (prev@Step n step halt) vdom → do
123- res@Step n' m' h' ← step vdom
124- EFn .runEffectFn3 Util .insertChildIx ix n' node
125- pure res
126- onThis = EFn .mkEffectFn2 \ix (Step n _ halt) → halt
127- onThat = EFn .mkEffectFn2 \ix vdom → do
128- res@Step n m h ← buildVDom (VDomSpec spec) vdom
129- EFn .runEffectFn3 Util .insertChildIx ix n node
130- pure res
131- steps ← EFn .runEffectFn5 Util .diffWithIxE ch1 ch2 onThese onThis onThat
132- attrs' ← Machine .step attrs as2
133- pure
134- (Step node
135- (Fn .runFn4 patch node attrs' es2 steps)
136- (Fn .runFn3 done node attrs' steps))
137- vdom → do
138- Fn .runFn3 done node attrs ch1
139- buildVDom (VDomSpec spec) vdom
104+ attrs ← EFn .runEffectFn1 (spec.buildAttributes el) as1
105+ let halt = Fn .runFn3 done node attrs steps
106+ pure (Step node (Fn .runFn6 patch build halt node attrs es1 steps) halt)
107+
108+ patch = Fn .mkFn6 \build halt node attrs (es1@(ElemSpec ns1 name1 as1)) ch1 →
109+ EFn .mkEffectFn1 case _ of
110+ Grafted g →
111+ EFn .runEffectFn1 (Fn .runFn6 patch build halt node attrs es1 ch1) (runGraft g)
112+ Elem es2@(ElemSpec ns2 name2 as2) ch2 | Fn .runFn2 eqElemSpec es1 es2 → do
113+ case Array .length ch1, Array .length ch2 of
114+ 0 , 0 → do
115+ attrs' ← EFn .runEffectFn1 (Machine .step attrs) as2
116+ let halt' = Fn .runFn3 done node attrs' ch1
117+ pure (Step node (Fn .runFn6 patch build halt' node attrs' es2 ch1) halt')
118+ _, _ → do
119+ let
120+ onThese = EFn .mkEffectFn3 \ix prev@(Step _ step _) vdom → do
121+ res@(Step n' _ _) ← EFn .runEffectFn1 step vdom
122+ EFn .runEffectFn3 Util .insertChildIx ix n' node
123+ pure res
124+ onThis = EFn .mkEffectFn2 \ix (Step _ _ h) → h
125+ onThat = EFn .mkEffectFn2 \ix vdom → do
126+ res@(Step n _ _) ← EFn .runEffectFn1 build vdom
127+ EFn .runEffectFn3 Util .insertChildIx ix n node
128+ pure res
129+ steps ← EFn .runEffectFn5 Util .diffWithIxE ch1 ch2 onThese onThis onThat
130+ attrs' ← EFn .runEffectFn1 (Machine .step attrs) as2
131+ let halt' = Fn .runFn3 done node attrs' steps
132+ pure (Step node (Fn .runFn6 patch build halt' node attrs' es2 steps) halt')
133+ vdom → do
134+ halt
135+ EFn .runEffectFn1 build vdom
140136
141137 done = Fn .mkFn3 \node attrs steps → do
142- parent ← pure ( Util .unsafeParent node)
138+ parent ← EFn .runEffectFn1 Util .parentNode node
143139 EFn .runEffectFn2 Util .removeChild node parent
144140 foreachE steps Machine .halt
145141 Machine .halt attrs
146142
147- buildKeyed
148- ∷ ∀ a w
149- . VDomSpec a w
150- → ElemSpec a
151- → Array (Tuple String (VDom a w ))
152- → VDomStep (VDom a w ) DOM.Node
153- buildKeyed (VDomSpec spec) = render
143+ buildKeyed ∷ ∀ a w . VDomBuilder2 (ElemSpec a ) (Array (Tuple String (VDom a w ))) a w
144+ buildKeyed = render
154145 where
155- render es1@(ElemSpec ns1 name1 as1) ch1 = do
146+ render = EFn .mkEffectFn4 \( VDomSpec spec) build es1@(ElemSpec ns1 name1 as1) ch1 → do
156147 el ← EFn .runEffectFn3 Util .createElement (toNullable ns1) name1 spec.document
157148 let
158149 node = DOMElement .toNode el
159150 onChild = EFn .mkEffectFn3 \k ix (Tuple _ vdom) → do
160- res@Step n m h ← buildVDom ( VDomSpec spec) vdom
151+ res@( Step n _ _) ← EFn .runEffectFn1 build vdom
161152 EFn .runEffectFn3 Util .insertChildIx ix n node
162153 pure res
163154 steps ← EFn .runEffectFn3 Util .strMapWithIxE ch1 fst onChild
164- attrs ← spec.buildAttributes el as1
165- pure
166- (Step node
167- (Fn .runFn5 patch node attrs es1 steps (Array .length ch1))
168- (Fn .runFn3 done node attrs steps))
169-
170- patch = Fn .mkFn5 \node attrs (es1@(ElemSpec ns1 name1 as1)) ch1 len1 → case _ of
171- Grafted g →
172- Fn .runFn5 patch node attrs es1 ch1 len1 (runGraft g)
173- Keyed es2@(ElemSpec ns2 name2 as2) ch2 | Fn .runFn2 eqElemSpec es1 es2 →
174- case len1, Array .length ch2 of
175- 0 , 0 → do
176- attrs' ← Machine .step attrs as2
177- pure
178- (Step node
179- (Fn .runFn5 patch node attrs' es2 ch1 0 )
180- (Fn .runFn3 done node attrs' ch1))
181- _, len2 → do
182- let
183- onThese = EFn .mkEffectFn4 \k ix' (Step n step _) (Tuple _ vdom) → do
184- res@Step n' m' h' ← step vdom
185- EFn .runEffectFn3 Util .insertChildIx ix' n' node
186- pure res
187- onThis = EFn .mkEffectFn2 \k (Step n _ halt) → halt
188- onThat = EFn .mkEffectFn3 \k ix (Tuple _ vdom) → do
189- res@Step n' m' h' ← buildVDom (VDomSpec spec) vdom
190- EFn .runEffectFn3 Util .insertChildIx ix n' node
191- pure res
192- steps ← EFn .runEffectFn6 Util .diffWithKeyAndIxE ch1 ch2 fst onThese onThis onThat
193- attrs' ← Machine .step attrs as2
194- pure
195- (Step node
196- (Fn .runFn5 patch node attrs' es2 steps len2)
197- (Fn .runFn3 done node attrs' steps))
198- vdom → do
199- Fn .runFn3 done node attrs ch1
200- buildVDom (VDomSpec spec) vdom
155+ attrs ← EFn .runEffectFn1 (spec.buildAttributes el) as1
156+ let halt = Fn .runFn3 done node attrs steps
157+ pure (Step node (Fn .runFn7 patch build halt node attrs es1 steps (Array .length ch1)) halt)
158+
159+ patch = Fn .mkFn7 \build halt node attrs (es1@(ElemSpec ns1 name1 as1)) ch1 len1 →
160+ EFn .mkEffectFn1 case _ of
161+ Grafted g →
162+ EFn .runEffectFn1 (Fn .runFn7 patch build halt node attrs es1 ch1 len1) (runGraft g)
163+ Keyed es2@(ElemSpec ns2 name2 as2) ch2 | Fn .runFn2 eqElemSpec es1 es2 →
164+ case len1, Array .length ch2 of
165+ 0 , 0 → do
166+ attrs' ← EFn .runEffectFn1 (Machine .step attrs) as2
167+ let halt' = Fn .runFn3 done node attrs' ch1
168+ pure (Step node (Fn .runFn7 patch build halt' node attrs' es2 ch1 0 ) halt')
169+ _, len2 → do
170+ let
171+ onThese = EFn .mkEffectFn4 \_ ix' (Step _ step _) (Tuple _ vdom) → do
172+ res@(Step n' _ _) ← EFn .runEffectFn1 step vdom
173+ EFn .runEffectFn3 Util .insertChildIx ix' n' node
174+ pure res
175+ onThis = EFn .mkEffectFn2 \_ (Step _ _ h) → h
176+ onThat = EFn .mkEffectFn3 \_ ix (Tuple _ vdom) → do
177+ res@(Step n' _ _) ← EFn .runEffectFn1 build vdom
178+ EFn .runEffectFn3 Util .insertChildIx ix n' node
179+ pure res
180+ steps ← EFn .runEffectFn6 Util .diffWithKeyAndIxE ch1 ch2 fst onThese onThis onThat
181+ attrs' ← EFn .runEffectFn1 (Machine .step attrs) as2
182+ let halt' = Fn .runFn3 done node attrs' steps
183+ pure (Step node (Fn .runFn7 patch build halt' node attrs' es2 steps len2) halt')
184+ vdom → do
185+ halt
186+ EFn .runEffectFn1 build vdom
201187
202188 done = Fn .mkFn3 \node attrs steps → do
203- parent ← pure ( Util .unsafeParent node)
189+ parent ← EFn .runEffectFn1 Util .parentNode node
204190 EFn .runEffectFn2 Util .removeChild node parent
205191 EFn .runEffectFn2 Util .forInE steps (EFn .mkEffectFn2 \_ (Step _ _ halt) → halt)
206192 Machine .halt attrs
207193
208- buildWidget ∷ ∀ a w . VDomSpec a w → w → VDomStep ( VDom a w ) DOM.Node
209- buildWidget ( VDomSpec spec) = render
194+ buildWidget ∷ ∀ a w . VDomBuilder w a w
195+ buildWidget = render
210196 where
211- render w = do
212- res@Step n m h ← spec.buildWidget (VDomSpec spec) w
213- pure (Step n (patch res) h)
214-
215- patch prev@(Step node step halt) = case _ of
216- Grafted g →
217- patch prev (runGraft g)
218- Widget w → do
219- res@Step n m h ← step w
220- pure (Step n (patch res) h)
221- vdom → do
222- halt
223- buildVDom (VDomSpec spec) vdom
197+ render = EFn .mkEffectFn3 \(VDomSpec spec) build w → do
198+ res@(Step n _ h) ← EFn .runEffectFn1 (spec.buildWidget (VDomSpec spec)) w
199+ pure (Step n (Fn .runFn2 patch build res) h)
200+
201+ patch = Fn .mkFn2 \build prev@(Step node step halt) →
202+ EFn .mkEffectFn1 case _ of
203+ Grafted g →
204+ EFn .runEffectFn1 (Fn .runFn2 patch build prev) (runGraft g)
205+ Widget w → do
206+ res@(Step n _ h) ← EFn .runEffectFn1 step w
207+ pure (Step n (Fn .runFn2 patch build res) h)
208+ vdom → do
209+ halt
210+ EFn .runEffectFn1 build vdom
224211
225212eqElemSpec ∷ ∀ a . Fn.Fn2 (ElemSpec a ) (ElemSpec a ) Boolean
226213eqElemSpec = Fn .mkFn2 \a b →
227214 case a, b of
228- ElemSpec ns1 name1 _, ElemSpec ns2 name2 _ | name1 == name2 →
215+ ElemSpec ns1 ( ElemName name1) _, ElemSpec ns2 ( ElemName name2) _ | name1 == name2 →
229216 case ns1, ns2 of
230217 Just (Namespace ns1'), Just (Namespace ns2') | ns1' == ns2' → true
231218 Nothing , Nothing → true
0 commit comments