1
1
import { throwHierarchyRequestError , throwNotFoundError } from './errorHelpers' ;
2
2
import { NodeType , isNodeOfType } from './NodeType' ;
3
- import {
4
- determineLengthOfNode ,
5
- getNodeDocument ,
6
- getNodeIndex ,
7
- forEachInclusiveDescendant ,
8
- } from './treeHelpers' ;
3
+ import { getNodeDocument , getNodeIndex , forEachInclusiveDescendant } from './treeHelpers' ;
9
4
import { insertIntoChildren , removeFromChildren } from './treeMutations' ;
10
5
import Document from '../Document' ;
11
6
import DocumentFragment from '../DocumentFragment' ;
@@ -179,10 +174,13 @@ export function preInsertNode<TNode extends Node>(
179
174
referenceChild = node . nextSibling ;
180
175
}
181
176
182
- // 4. Insert node into parent before referenceChild.
177
+ // 4. Adopt node into parent's node document.
178
+ adoptNode ( node , getNodeDocument ( parent ) ) ;
179
+
180
+ // 5. Insert node into parent before referenceChild.
183
181
insertNode ( node , parent , referenceChild ) ;
184
182
185
- // 5 . Return node.
183
+ // 6 . Return node.
186
184
return node ;
187
185
}
188
186
@@ -247,40 +245,30 @@ export function insertNode(
247
245
// 6. Let previousSibling be child’s previous sibling or parent’s last child if child is null.
248
246
let previousSibling = child === null ? parent . lastChild : child . previousSibling ;
249
247
250
- // Non-standard: it appears the standard as of 27 January 2021 does not account for
251
- // previousSibling now possibly being node, which can happen, for instance, when doing
252
- // parent.insertBefore(child, child);
253
- if ( previousSibling === node ) {
254
- previousSibling = node . previousSibling ;
255
- }
256
-
257
248
// 7. For each node in nodes, in tree order:
258
249
nodes . forEach ( ( node ) => {
259
- // 7.1. Adopt node into parent's node document.
260
- adoptNode ( node , getNodeDocument ( parent ) ) ;
261
-
262
- // 7.2. If child is null, then append node to parent’s children.
263
- // 7.3. Otherwise, insert node into parent’s children before child’s index.
250
+ // 7.1. If child is null, then append node to parent’s children.
251
+ // 7.2. Otherwise, insert node into parent’s children before child’s index.
264
252
insertIntoChildren ( node , parent , child ) ;
265
253
266
- // 7.4 . If parent is a shadow host and node is a slottable, then assign a slot for node.
254
+ // 7.3 . If parent is a shadow host and node is a slottable, then assign a slot for node.
267
255
// (shadow dom not implemented)
268
256
269
- // 7.5 . If parent's root is a shadow root, and parent is a slot whose assigned nodes is the
257
+ // 7.4 . If parent's root is a shadow root, and parent is a slot whose assigned nodes is the
270
258
// empty list, then run signal a slot change for parent.
271
- // 7.6 . Run assign slottables for a tree with node’s tree.
259
+ // 7.5 . Run assign slottables for a tree with node’s tree.
272
260
// (shadow dom not implemented)
273
261
274
- // 7.7 . For each shadow-including inclusive descendant inclusiveDescendant of node, in
262
+ // 7.6 . For each shadow-including inclusive descendant inclusiveDescendant of node, in
275
263
// shadow-including tree order:
276
- // 7.7 .1. Run the insertion steps with inclusiveDescendant.
264
+ // 7.6 .1. Run the insertion steps with inclusiveDescendant.
277
265
// (insertion steps not implemented)
278
266
279
- // 7.7 .2. If inclusiveDescendant is connected, then:
280
- // 7.7 .2.1. If inclusiveDescendant is custom, then enqueue a custom element callback
267
+ // 7.6 .2. If inclusiveDescendant is connected, then:
268
+ // 7.6 .2.1. If inclusiveDescendant is custom, then enqueue a custom element callback
281
269
// reaction with inclusiveDescendant, callback name "connectedCallback", and an empty
282
270
// argument list.
283
- // 7.7 .2.2. Otherwise, try to upgrade inclusiveDescendant. If this successfully upgrades
271
+ // 7.6 .2.2. Otherwise, try to upgrade inclusiveDescendant. If this successfully upgrades
284
272
// inclusiveDescendant, its connectedCallback will be enqueued automatically during the
285
273
// upgrade an element algorithm.
286
274
// (custom elements not implemented)
@@ -465,11 +453,13 @@ export function replaceChildWithNode<TChild extends Node>(
465
453
// 9. Let previousSibling be child’s previous sibling.
466
454
const previousSibling = child . previousSibling ;
467
455
468
- // 10. Let removedNodes be the empty set.
456
+ // 10. Adopt node into parent's node document
457
+ adoptNode ( node , getNodeDocument ( parent ) ) ;
458
+
459
+ // 11. Let removedNodes be the empty set.
469
460
let removedNodes : Node [ ] = [ ] ;
470
461
471
- // 11. If child’s parent is non-null, then:
472
- /* istanbul ignore else */
462
+ // 12. If child’s parent is non-null, then:
473
463
if ( child . parentNode !== null ) {
474
464
// 11.1. Set removedNodes to « child ».
475
465
removedNodes . push ( child ) ;
@@ -478,17 +468,16 @@ export function replaceChildWithNode<TChild extends Node>(
478
468
removeNode ( child , true ) ;
479
469
}
480
470
// The above can only be false if child is node.
481
- // (TODO: this is no longer the case, at least until whatwg/dom#819 is merged)
482
471
483
- // 12 . Let nodes be node’s children if node is a DocumentFragment node; otherwise « node ».
472
+ // 13 . Let nodes be node’s children if node is a DocumentFragment node; otherwise « node ».
484
473
const nodes = isNodeOfType ( node , NodeType . DOCUMENT_FRAGMENT_NODE )
485
474
? Array . from ( node . childNodes )
486
475
: [ node ] ;
487
476
488
- // 13 . Insert node into parent before referenceChild with the suppress observers flag set.
477
+ // 14 . Insert node into parent before referenceChild with the suppress observers flag set.
489
478
insertNode ( node , parent , referenceChild , true ) ;
490
479
491
- // 14 . Queue a tree mutation record for parent with nodes, removedNodes, previousSibling and
480
+ // 15 . Queue a tree mutation record for parent with nodes, removedNodes, previousSibling and
492
481
// referenceChild.
493
482
queueMutationRecord ( 'childList' , parent , {
494
483
addedNodes : nodes ,
@@ -497,7 +486,7 @@ export function replaceChildWithNode<TChild extends Node>(
497
486
previousSibling : previousSibling ,
498
487
} ) ;
499
488
500
- // 15 . Return child.
489
+ // 16 . Return child.
501
490
return child ;
502
491
}
503
492
@@ -508,36 +497,41 @@ export function replaceChildWithNode<TChild extends Node>(
508
497
* @param parent Parent to replace under
509
498
*/
510
499
function replaceAllWithNode ( node : Node | null , parent : Node ) : void {
511
- // 1. Let removedNodes be parent’s children.
500
+ // 1. If node is non-null, then adopt node into parent's node document
501
+ if ( node !== null ) {
502
+ adoptNode ( node , getNodeDocument ( parent ) ) ;
503
+ }
504
+
505
+ // 2. Let removedNodes be parent’s children.
512
506
const removedNodes = Array . from ( parent . childNodes ) ;
513
507
514
- // 2 . Let addedNodes be the empty set.
508
+ // 3 . Let addedNodes be the empty set.
515
509
let addedNodes : Node [ ] = [ ] ;
516
510
517
511
if ( node !== null ) {
518
- // 3 . If node is a DocumentFragment node, then set addedNodes to node's children.
512
+ // 4 . If node is a DocumentFragment node, then set addedNodes to node's children.
519
513
if ( isNodeOfType ( node , NodeType . DOCUMENT_FRAGMENT_NODE ) ) {
520
514
node . childNodes . forEach ( ( child ) => {
521
515
addedNodes . push ( child ) ;
522
516
} ) ;
523
517
} else {
524
- // 4 . Otherwise, if node is non-null, set addedNodes to « node ».
518
+ // 5 . Otherwise, if node is non-null, set addedNodes to « node ».
525
519
addedNodes . push ( node ) ;
526
520
}
527
521
}
528
522
529
- // 5 . Remove all parent’s children, in tree order, with the suppress observers flag set.
523
+ // 6 . Remove all parent’s children, in tree order, with the suppress observers flag set.
530
524
removedNodes . forEach ( ( child ) => {
531
525
removeNode ( child , true ) ;
532
526
} ) ;
533
527
534
- // 6 . If node is non-null, then insert node into parent before null with the suppress observers
528
+ // 7 . If node is non-null, then insert node into parent before null with the suppress observers
535
529
// flag set.
536
530
if ( node !== null ) {
537
531
insertNode ( node , parent , null , true ) ;
538
532
}
539
533
540
- // 7 . If either addedNodes or removedNodes is not empty, then queue a tree mutation record for
534
+ // 8 . If either addedNodes or removedNodes is not empty, then queue a tree mutation record for
541
535
// parent with addedNodes, removedNodes, null, and null.
542
536
if ( addedNodes . length > 0 || removedNodes . length > 0 ) {
543
537
queueMutationRecord ( 'childList' , parent , {
@@ -688,13 +682,18 @@ export function removeNode(node: Node, suppressObservers: boolean = false): void
688
682
/**
689
683
* 3.5. Interface Document
690
684
*
691
- * To adopt a node into a document, run these steps:
685
+ * To adopt a node into a document, with an optional forceDocumentFragmentAdoption, run these steps:
686
+ *
687
+ * (forceDocumentFragmentAdoption is only set to true for HTML template, so is not implemented here)
692
688
*
693
689
* @param node - Node to adopt
694
690
* @param document - Document to adopt node into
695
691
*/
696
692
export function adoptNode ( node : Node , document : Document ) : void {
697
- // 1. Let oldDocument be node’s node document.
693
+ // 1. If forceDocumentFragmentAdoption is not given, then set it false.
694
+ // (value unused)
695
+
696
+ // 2. Let oldDocument be node’s node document.
698
697
const oldDocument = getNodeDocument ( node ) ;
699
698
700
699
// 2. If node’s parent is non-null, remove node.
@@ -708,15 +707,21 @@ export function adoptNode(node: Node, document: Document): void {
708
707
}
709
708
710
709
// 3.1. For each inclusiveDescendant in node’s shadow-including inclusive descendants:
711
- forEachInclusiveDescendant ( node , ( node ) => {
712
- // 3.1.1. Set inclusiveDescendant’s node document to document.
710
+ forEachInclusiveDescendant ( node , ( inclusiveDescendant ) => {
711
+ // 3.1.1. If forceDocumentFragmentAdoption is false, inclusiveDescendant is a
712
+ // DocumentFragment node, inclusiveDescendant is node, and node's host is non-null, then
713
+ // continue
714
+ // Note: this is only reasonable as long as all adopt callers remove the children of node.
715
+ // (shadow dom and HTML templates not implemented)
716
+
717
+ // 3.1.2. Set inclusiveDescendant’s node document to document.
713
718
// (calling code ensures that node is never a Document)
714
- node . ownerDocument = document ;
719
+ inclusiveDescendant . ownerDocument = document ;
715
720
716
- // 3.1.2 . If inclusiveDescendant is an element, then set the node document of each attribute
721
+ // 3.1.3 . If inclusiveDescendant is an element, then set the node document of each attribute
717
722
// in inclusiveDescendant’s attribute list to document.
718
- if ( isNodeOfType ( node , NodeType . ELEMENT_NODE ) ) {
719
- for ( const attr of ( node as Element ) . attributes ) {
723
+ if ( isNodeOfType ( inclusiveDescendant , NodeType . ELEMENT_NODE ) ) {
724
+ for ( const attr of ( inclusiveDescendant as Element ) . attributes ) {
720
725
attr . ownerDocument = document ;
721
726
}
722
727
}
0 commit comments