11import { throwHierarchyRequestError , throwNotFoundError } from './errorHelpers' ;
22import { NodeType , isNodeOfType } from './NodeType' ;
3- import {
4- determineLengthOfNode ,
5- getNodeDocument ,
6- getNodeIndex ,
7- forEachInclusiveDescendant ,
8- } from './treeHelpers' ;
3+ import { getNodeDocument , getNodeIndex , forEachInclusiveDescendant } from './treeHelpers' ;
94import { insertIntoChildren , removeFromChildren } from './treeMutations' ;
105import Document from '../Document' ;
116import DocumentFragment from '../DocumentFragment' ;
@@ -179,10 +174,13 @@ export function preInsertNode<TNode extends Node>(
179174 referenceChild = node . nextSibling ;
180175 }
181176
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.
183181 insertNode ( node , parent , referenceChild ) ;
184182
185- // 5 . Return node.
183+ // 6 . Return node.
186184 return node ;
187185}
188186
@@ -247,40 +245,30 @@ export function insertNode(
247245 // 6. Let previousSibling be child’s previous sibling or parent’s last child if child is null.
248246 let previousSibling = child === null ? parent . lastChild : child . previousSibling ;
249247
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-
257248 // 7. For each node in nodes, in tree order:
258249 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.
264252 insertIntoChildren ( node , parent , child ) ;
265253
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.
267255 // (shadow dom not implemented)
268256
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
270258 // 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.
272260 // (shadow dom not implemented)
273261
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
275263 // shadow-including tree order:
276- // 7.7 .1. Run the insertion steps with inclusiveDescendant.
264+ // 7.6 .1. Run the insertion steps with inclusiveDescendant.
277265 // (insertion steps not implemented)
278266
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
281269 // reaction with inclusiveDescendant, callback name "connectedCallback", and an empty
282270 // 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
284272 // inclusiveDescendant, its connectedCallback will be enqueued automatically during the
285273 // upgrade an element algorithm.
286274 // (custom elements not implemented)
@@ -465,11 +453,13 @@ export function replaceChildWithNode<TChild extends Node>(
465453 // 9. Let previousSibling be child’s previous sibling.
466454 const previousSibling = child . previousSibling ;
467455
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.
469460 let removedNodes : Node [ ] = [ ] ;
470461
471- // 11. If child’s parent is non-null, then:
472- /* istanbul ignore else */
462+ // 12. If child’s parent is non-null, then:
473463 if ( child . parentNode !== null ) {
474464 // 11.1. Set removedNodes to « child ».
475465 removedNodes . push ( child ) ;
@@ -478,17 +468,16 @@ export function replaceChildWithNode<TChild extends Node>(
478468 removeNode ( child , true ) ;
479469 }
480470 // 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)
482471
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 ».
484473 const nodes = isNodeOfType ( node , NodeType . DOCUMENT_FRAGMENT_NODE )
485474 ? Array . from ( node . childNodes )
486475 : [ node ] ;
487476
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.
489478 insertNode ( node , parent , referenceChild , true ) ;
490479
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
492481 // referenceChild.
493482 queueMutationRecord ( 'childList' , parent , {
494483 addedNodes : nodes ,
@@ -497,7 +486,7 @@ export function replaceChildWithNode<TChild extends Node>(
497486 previousSibling : previousSibling ,
498487 } ) ;
499488
500- // 15 . Return child.
489+ // 16 . Return child.
501490 return child ;
502491}
503492
@@ -508,36 +497,41 @@ export function replaceChildWithNode<TChild extends Node>(
508497 * @param parent Parent to replace under
509498 */
510499function 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.
512506 const removedNodes = Array . from ( parent . childNodes ) ;
513507
514- // 2 . Let addedNodes be the empty set.
508+ // 3 . Let addedNodes be the empty set.
515509 let addedNodes : Node [ ] = [ ] ;
516510
517511 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.
519513 if ( isNodeOfType ( node , NodeType . DOCUMENT_FRAGMENT_NODE ) ) {
520514 node . childNodes . forEach ( ( child ) => {
521515 addedNodes . push ( child ) ;
522516 } ) ;
523517 } 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 ».
525519 addedNodes . push ( node ) ;
526520 }
527521 }
528522
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.
530524 removedNodes . forEach ( ( child ) => {
531525 removeNode ( child , true ) ;
532526 } ) ;
533527
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
535529 // flag set.
536530 if ( node !== null ) {
537531 insertNode ( node , parent , null , true ) ;
538532 }
539533
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
541535 // parent with addedNodes, removedNodes, null, and null.
542536 if ( addedNodes . length > 0 || removedNodes . length > 0 ) {
543537 queueMutationRecord ( 'childList' , parent , {
@@ -688,13 +682,18 @@ export function removeNode(node: Node, suppressObservers: boolean = false): void
688682/**
689683 * 3.5. Interface Document
690684 *
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)
692688 *
693689 * @param node - Node to adopt
694690 * @param document - Document to adopt node into
695691 */
696692export 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.
698697 const oldDocument = getNodeDocument ( node ) ;
699698
700699 // 2. If node’s parent is non-null, remove node.
@@ -708,15 +707,21 @@ export function adoptNode(node: Node, document: Document): void {
708707 }
709708
710709 // 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.
713718 // (calling code ensures that node is never a Document)
714- node . ownerDocument = document ;
719+ inclusiveDescendant . ownerDocument = document ;
715720
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
717722 // 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 ) {
720725 attr . ownerDocument = document ;
721726 }
722727 }
0 commit comments