Skip to content

Commit 25f9527

Browse files
authored
Merge pull request #84 from fsw/replacewith-bugfix
fix replaceWith bugfix for node argument that is already in document tree
2 parents b96d8e3 + d3d4472 commit 25f9527

2 files changed

Lines changed: 49 additions & 58 deletions

File tree

lib/src/html/dom/node.dart

Lines changed: 21 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -393,83 +393,60 @@ abstract class Node extends EventTarget {
393393
return sb.toString();
394394
}
395395

396-
void remove() {
396+
void _removeFromTree(Node? replaceWith) {
397397
final parent = _parent;
398398
if (parent == null) {
399399
assert(_previousNode == null);
400400
assert(_nextNode == null);
401401
return;
402402
}
403403

404-
// Mark node as dirty
405-
_markDirty();
406-
407404
// Get previous and next
408405
final previous = _previousNode;
409406
final next = _nextNode;
410407

411408
if (previous == null) {
412409
// This was the first sibling
413-
parent._firstChild = next;
410+
parent._firstChild = replaceWith ?? next;
414411
} else {
415412
// Mutate the previous sibling
416-
previous._nextNode = next;
413+
previous._nextNode = replaceWith ?? next;
417414
}
418415

419416
if (next == null) {
420417
// This was the last sibling
421-
parent._lastChild = previous;
418+
parent._lastChild = replaceWith ?? previous;
422419
} else {
423420
// Mutate the next sibling
424-
next._previousNode = previous;
421+
next._previousNode = replaceWith ?? previous;
422+
}
423+
if (replaceWith != null) {
424+
// move replaceWith
425+
replaceWith._parent = parent;
426+
replaceWith._previousNode = previous;
427+
replaceWith._nextNode = next;
425428
}
426-
427429
// Set fields of this node
428430
_parent = null;
429431
_previousNode = null;
430432
_nextNode = null;
431-
parent._mutated();
432-
_mutated();
433433
}
434434

435-
void replaceWith(Node node) {
435+
void remove() {
436436
final parent = _parent;
437-
if (parent == null) {
438-
assert(_previousNode == null);
439-
assert(_nextNode == null);
440-
return;
441-
}
437+
// Mark node as dirty
438+
_markDirty();
439+
_removeFromTree(null);
440+
parent?._mutated();
441+
_mutated();
442+
}
442443

444+
void replaceWith(Node node) {
443445
// Mark nodes as dirty
444446
_markDirty();
445447
node._markDirty();
446-
447-
// Get previous and next
448-
final previous = _previousNode;
449-
final next = _nextNode;
450-
451-
if (previous == null) {
452-
// This was the first sibling
453-
parent._firstChild = node;
454-
} else {
455-
// Mutate the previous sibling
456-
previous._nextNode = node;
457-
}
458-
459-
if (next == null) {
460-
// This was the last sibling
461-
parent._lastChild = node;
462-
} else {
463-
// Mutate the next sibling
464-
next._previousNode = node;
465-
}
466-
467-
node._parent = parent;
468-
node._previousNode = previous;
469-
node._nextNode = next;
470-
_parent = null;
471-
_previousNode = null;
472-
_nextNode = null;
448+
node._removeFromTree(null);
449+
_removeFromTree(node);
473450
_mutated();
474451
node._mutated();
475452
}

test/src/html/dom/node.dart

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@ void _testNode() {
3737
test('replaceWith', () {
3838
final e0 = Element.tag('e0')..appendText('e0-text');
3939
final e1 = Element.tag('e1')..appendText('e1-text');
40-
final e2 = Element.tag('e2')..appendText('e2-text');
40+
final e2 = Element.tag('e2')..append(
41+
Element.tag('e2c1')
42+
)..append(
43+
Element.tag('e2c2')
44+
);
4145
final root = Element.tag('sometag')
4246
..setAttribute('k', 'v')
4347
..append(e0)
@@ -46,11 +50,9 @@ void _testNode() {
4650

4751
// Initial tree
4852
expect(
49-
root.outerHtml,
50-
equals(
51-
'<sometag k="v"><e0>e0-text</e0><e1>e1-text</e1><e2>e2-text</e2></sometag>',
52-
),
53-
);
53+
root.outerHtml,
54+
equals(
55+
'<sometag k="v"><e0>e0-text</e0><e1>e1-text</e1><e2><e2c1></e2c1><e2c2></e2c2></e2></sometag>'));
5456

5557
// Replace child #1 of 'e1'
5658
{
@@ -64,11 +66,9 @@ void _testNode() {
6466
expect(e1.firstChild, same(replacement));
6567
expect(e1.firstChild!.parent, same(e1));
6668
expect(
67-
root.outerHtml,
68-
equals(
69-
'<sometag k="v"><e0>e0-text</e0><e1>e1-text-replaced</e1><e2>e2-text</e2></sometag>',
70-
),
71-
);
69+
root.outerHtml,
70+
equals(
71+
'<sometag k="v"><e0>e0-text</e0><e1>e1-text-replaced</e1><e2><e2c1></e2c1><e2c2></e2c2></e2></sometag>'));
7272
}
7373

7474
// Replace child #2 of root ('e1')
@@ -84,12 +84,26 @@ void _testNode() {
8484
expect(e1.nextNode, isNull);
8585
expect(replacement.parent, same(root));
8686
expect(replacement.nextNode, same(e2));
87+
expect(
88+
root.outerHtml,
89+
equals(
90+
'<sometag k="v"><e0>e0-text</e0>e1-replaced<e2><e2c1></e2c1><e2c2></e2c2></e2></sometag>'));
91+
}
92+
// Replace with existing node to check if it moved properly
93+
{
94+
final replacement = e2.children.first;
95+
e0.replaceWith(replacement);
96+
97+
expect(e0.nextNode, isNull);
98+
expect(e0.previousNode, isNull);
99+
expect(e0.parent, isNull);
100+
expect(replacement.parent, same(root));
101+
expect(replacement.previousNode, isNull);
102+
expect(replacement.nextNode, isNotNull);
87103
expect(
88104
root.outerHtml,
89105
equals(
90-
'<sometag k="v"><e0>e0-text</e0>e1-replaced<e2>e2-text</e2></sometag>',
91-
),
92-
);
106+
'<sometag k="v"><e2c1></e2c1>e1-replaced<e2><e2c2></e2c2></e2></sometag>'));
93107
}
94108
});
95109
test('replaceWith when the node has no parent', () {

0 commit comments

Comments
 (0)