diff --git a/src/browser/tests/node/append_child.html b/src/browser/tests/node/append_child.html index 151815b9..48bffe91 100644 --- a/src/browser/tests/node/append_child.html +++ b/src/browser/tests/node/append_child.html @@ -65,3 +65,32 @@ assertChildren(['a'], d3); testing.expectEqual(null, b.parentNode); + +
+ + diff --git a/src/browser/tests/node/insert_before.html b/src/browser/tests/node/insert_before.html index 50dff07c..1018c314 100644 --- a/src/browser/tests/node/insert_before.html +++ b/src/browser/tests/node/insert_before.html @@ -39,3 +39,34 @@ assertChildren([], d1); assertChildren([c1, c2], d2); + + + + diff --git a/src/browser/webapi/Node.zig b/src/browser/webapi/Node.zig index 718c065a..8e8eea21 100644 --- a/src/browser/webapi/Node.zig +++ b/src/browser/webapi/Node.zig @@ -253,6 +253,11 @@ pub fn appendChild(self: *Node, child: *Node, frame: *Frame) !*Node { try frame.adoptNodeTree(child, child_owner.?, parent_owner); } + // A custom element callback can re-parent the node. If it does, we're done + if (child._parent != null) { + return child; + } + try frame.appendNode(self, child, .{ .child_already_connected = child_connected, .adopting_to_new_document = adopting_to_new_document, @@ -624,6 +629,22 @@ pub fn insertBefore(self: *Node, new_node: *Node, ref_node_: ?*Node, frame: *Fra try frame.adoptNodeTree(new_node, child_owner.?, parent_owner); } + // See Node.appendChild: a callback above (disconnectedCallback or + // adoptedCallback) can re-parent new_node. Let that placement stand. + if (new_node._parent != null) { + return new_node; + } + + // The same callback could also have detached ref_node from self. Fall + // back to append so new_node still lands in self. + if (ref_node._parent != self) { + try frame.appendNode(self, new_node, .{ + .child_already_connected = child_already_connected, + .adopting_to_new_document = adopting_to_new_document, + }); + return new_node; + } + try frame.insertNodeRelative( self, new_node,