1
1
module Halogen.VDom.DOM
2
- ( VDomMachine
3
- , VDomStep
4
- , VDomSpec (..)
2
+ ( VDomSpec (..)
5
3
, buildVDom
6
4
, buildText
7
5
, buildElem
@@ -16,26 +14,32 @@ import Data.Function.Uncurried as Fn
16
14
import Data.Maybe (Maybe (..))
17
15
import Data.Nullable (toNullable )
18
16
import Data.Tuple (Tuple (..), fst )
19
- import Effect (Effect , foreachE )
17
+ import Effect (foreachE )
20
18
import Effect.Uncurried as EFn
21
19
import Halogen.VDom.Machine (Step (..), Machine )
22
20
import Halogen.VDom.Machine as Machine
23
- import Halogen.VDom.Types (VDom (..), ElemSpec (..), Namespace (..), runGraft )
21
+ import Halogen.VDom.Types (ElemName (..), ElemSpec (..), Namespace (..), VDom (..), runGraft )
24
22
import Halogen.VDom.Util as Util
25
23
import Web.DOM.Document (Document ) as DOM
26
24
import Web.DOM.Element (Element ) as DOM
27
25
import Web.DOM.Element as DOMElement
28
26
import Web.DOM.Node (Node ) as DOM
29
27
30
- type VDomMachine a b = Machine Effect a b
28
+ type VDomMachine a w = Machine ( VDom a w ) DOM.Node
31
29
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 )
33
37
34
38
-- | Widget machines recursively reference the configured spec to potentially
35
39
-- | enable recursive trees of Widgets.
36
40
newtype 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
39
43
, document ∷ DOM.Document
40
44
}
41
45
@@ -48,184 +52,167 @@ newtype VDomSpec a w = VDomSpec
48
52
-- | machine3 ← Machine.step machine2 vdomTree3
49
53
-- | ...
50
54
-- | ````
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
53
57
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
63
67
where
64
- render s = do
68
+ render = EFn .mkEffectFn3 \( VDomSpec spec) build s → do
65
69
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
81
87
82
88
done node = do
83
- parent ← pure ( Util .unsafeParent node)
89
+ parent ← EFn .runEffectFn1 Util .parentNode node
84
90
EFn .runEffectFn2 Util .removeChild node parent
85
91
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
93
94
where
94
- render es1@(ElemSpec ns1 name1 as1) ch1 = do
95
+ render = EFn .mkEffectFn4 \( VDomSpec spec) build es1@(ElemSpec ns1 name1 as1) ch1 → do
95
96
el ← EFn .runEffectFn3 Util .createElement (toNullable ns1) name1 spec.document
96
97
let
97
98
node = DOMElement .toNode el
98
99
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
100
101
EFn .runEffectFn3 Util .insertChildIx ix n node
101
102
pure res
102
103
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
140
136
141
137
done = Fn .mkFn3 \node attrs steps → do
142
- parent ← pure ( Util .unsafeParent node)
138
+ parent ← EFn .runEffectFn1 Util .parentNode node
143
139
EFn .runEffectFn2 Util .removeChild node parent
144
140
foreachE steps Machine .halt
145
141
Machine .halt attrs
146
142
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
154
145
where
155
- render es1@(ElemSpec ns1 name1 as1) ch1 = do
146
+ render = EFn .mkEffectFn4 \( VDomSpec spec) build es1@(ElemSpec ns1 name1 as1) ch1 → do
156
147
el ← EFn .runEffectFn3 Util .createElement (toNullable ns1) name1 spec.document
157
148
let
158
149
node = DOMElement .toNode el
159
150
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
161
152
EFn .runEffectFn3 Util .insertChildIx ix n node
162
153
pure res
163
154
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
201
187
202
188
done = Fn .mkFn3 \node attrs steps → do
203
- parent ← pure ( Util .unsafeParent node)
189
+ parent ← EFn .runEffectFn1 Util .parentNode node
204
190
EFn .runEffectFn2 Util .removeChild node parent
205
191
EFn .runEffectFn2 Util .forInE steps (EFn .mkEffectFn2 \_ (Step _ _ halt) → halt)
206
192
Machine .halt attrs
207
193
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
210
196
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
224
211
225
212
eqElemSpec ∷ ∀ a . Fn.Fn2 (ElemSpec a ) (ElemSpec a ) Boolean
226
213
eqElemSpec = Fn .mkFn2 \a b →
227
214
case a, b of
228
- ElemSpec ns1 name1 _, ElemSpec ns2 name2 _ | name1 == name2 →
215
+ ElemSpec ns1 ( ElemName name1) _, ElemSpec ns2 ( ElemName name2) _ | name1 == name2 →
229
216
case ns1, ns2 of
230
217
Just (Namespace ns1'), Just (Namespace ns2') | ns1' == ns2' → true
231
218
Nothing , Nothing → true
0 commit comments