Skip to content

Commit 9256fa8

Browse files
authored
Fix fragments with conditionals (#70)
* Fix fragments with conditionals * Remove broken monoid support
1 parent 8f996d1 commit 9256fa8

File tree

4 files changed

+48
-14
lines changed

4 files changed

+48
-14
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"type": "module",
1212
"scripts": {
1313
"example-dice-aff": "parcel build examples/EffectfulDice/dice.js --dist-dir examples/EffectfulDice/dist/",
14-
"example-server-side-rendering-client": "parcel build examples/ServerSideRendering/Client/server-side-rendering-client.js --dist-dir examples/ServerSideRendering/dist --no-optimize",
14+
"example-server-side-rendering-client": "parcel build examples/ServerSideRendering/Client/server-side-rendering-client.js --dist-dir examples/ServerSideRendering/dist",
1515
"example-server-side-rendering": "npm run example-server-side-rendering-client",
1616
"example-affjax": "parcel build examples/EffectfulAffjax/affjax.js --dist-dir examples/EffectfulAffjax/dist",
1717
"example-affjax-list": "parcel build examples/Affjax/affjax.js --dist-dir examples/Affjax/dist",

src/Flame/Renderer/Internal/Dom.js

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ F.prototype.runHandlers = function (handlers, messageMapper, event) {
365365
};
366366

367367
F.prototype.resume = function (updatedHtml) {
368-
this.cachedHtml = this.updateAllNodes(this.root, this.cachedHtml, updatedHtml);;
368+
this.cachedHtml = this.updateAllNodes(this.root, this.cachedHtml, updatedHtml);
369369
};
370370

371371
/** Patches over the parent element*/
@@ -375,9 +375,14 @@ F.prototype.updateAllNodes = function (parent, currentHtml, updatedHtml) {
375375
updatedHtml = shallowCopy(updatedHtml);
376376
//recreate node if it has changed tag or node type
377377
if (currentHtml.tag !== updatedHtml.tag || currentHtml.nodeType !== updatedHtml.nodeType) {
378-
//moving the node instead of using clearNode allows us to reuse nodes
379-
this.createAllNodes(parent, updatedHtml, currentHtml.node);
380-
parent.removeChild(currentHtml.node);
378+
if (currentHtml.nodeType === fragmentNode) {
379+
this.createAllNodes(parent, updatedHtml, firstFragmentChildNode(currentHtml.children));
380+
removeFragmentChildren(parent, currentHtml.children);
381+
} else {
382+
//moving the node instead of using clearNode allows us to reuse nodes
383+
this.createAllNodes(parent, updatedHtml, currentHtml.node);
384+
parent.removeChild(currentHtml.node);
385+
}
381386
}
382387
else {
383388
updatedHtml.node = currentHtml.node;
@@ -434,6 +439,31 @@ F.prototype.updateAllNodes = function (parent, currentHtml, updatedHtml) {
434439
return updatedHtml;
435440
};
436441

442+
/** Fragments are not child of any nodes, so we must find the first actual node */
443+
function firstFragmentChildNode(children) {
444+
let childrenLength = children.length;
445+
446+
for (let i = 0; i < childrenLength; ++i) {
447+
if (children[i].nodeType === fragmentNode)
448+
return firstFragmentChildNode(children[i].children);
449+
450+
return children[i].node;
451+
}
452+
453+
return undefined;
454+
}
455+
456+
/** fragments are not child of any nodes, so we must recursively remove the actual child nodes */
457+
function removeFragmentChildren(parent, children) {
458+
let childrenLength = children.length;
459+
460+
for (let i = 0; i < childrenLength; ++i)
461+
if (children[i].nodeType === fragmentNode)
462+
removeFragmentChildren(children[i].children)
463+
else
464+
parent.removeChild(children[i].node);
465+
}
466+
437467
function clearNode(node) {
438468
node.textContent = '';
439469
}

src/Flame/Types.purs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@ module Flame.Types
2020
import Data.Maybe (Maybe)
2121
import Data.Tuple (Tuple(..))
2222
import Data.Tuple.Nested (Tuple3)
23-
import Flame.Internal.Fragment as FIF
2423
import Foreign (Foreign)
25-
import Prelude (class Functor, map, class Monoid, class Show, class Semigroup)
24+
import Prelude (class Functor, class Show, map)
2625

2726
-- | `PreApplication` contains
2827
-- | * `init` – the initial model
@@ -80,9 +79,3 @@ foreign import messageMapper ∷ ∀ message mapped. (Maybe message → Maybe ma
8079

8180
instance Functor Html where
8281
map f html = messageMapper (map f) html
83-
84-
instance Semigroup (Html a) where
85-
append html otherHtml = FIF.createFragmentNode [ html, otherHtml ]
86-
87-
instance Monoid (Html a) where
88-
mempty = FIF.createFragmentNode []

test/Main.purs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,10 +420,10 @@ main = AF.launchAff_ $ TSR.runSpec [ consoleReporter ] do
420420
TS.it "update text nodes" do
421421
let html = HE.text "oi"
422422
state ← mountHtml html
423-
let updatedHtml = HE.text "ola"
424423
text ← textContent "#mount-point"
425424
TSA.shouldEqual "oi" text
426425

426+
let updatedHtml = HE.text "ola"
427427
liftEffect $ FRID.resume state updatedHtml
428428
updatedText ← textContent "#mount-point"
429429
TSA.shouldEqual "ola" updatedText
@@ -489,6 +489,17 @@ main = AF.launchAff_ $ TSR.runSpec [ consoleReporter ] do
489489
nodeAttributes ← getAttributes "svg"
490490
TSA.shouldEqual "viewBox:0 0 0 0" nodeAttributes
491491

492+
TS.it "update fragment to node" do
493+
let html = HE.div "test-div" [ HE.fragment [HE.input [ HA.id "t", HA.value "a" ], HE.br], HE.span_ "ss"]
494+
state ← mountHtml html
495+
childrenCount ← childrenNodeLengthOf "#test-div"
496+
TSA.shouldEqual 3 childrenCount
497+
498+
let updatedHtml = HE.div "test-div" [ HE.div_ "aa", HE.span_ "ss"]
499+
liftEffect $ FRID.resume state updatedHtml
500+
childrenCount2 ← childrenNodeLengthOf "#test-div"
501+
TSA.shouldEqual 2 childrenCount2
502+
492503
TS.it "inserting children" do
493504
let html = HE.div' "test-div"
494505
state ← mountHtml html

0 commit comments

Comments
 (0)