Merge pull request #1612 from egrs/fix-childnode-sibling-ordering

fix ChildNode after() and replaceWith() sibling ordering
This commit is contained in:
Karl Seguin
2026-02-20 20:24:29 +08:00
committed by GitHub
3 changed files with 35 additions and 10 deletions

View File

@@ -301,24 +301,30 @@ pub fn before(self: *CData, nodes: []const Node.NodeOrText, page: *Page) !void {
pub fn after(self: *CData, nodes: []const Node.NodeOrText, page: *Page) !void {
const node = self.asNode();
const parent = node.parentNode() orelse return;
const next = node.nextSibling();
const viable_next = Node.NodeOrText.viableNextSibling(node, nodes);
for (nodes) |node_or_text| {
const child = try node_or_text.toNode(page);
_ = try parent.insertBefore(child, next, page);
_ = try parent.insertBefore(child, viable_next, page);
}
}
pub fn replaceWith(self: *CData, nodes: []const Node.NodeOrText, page: *Page) !void {
const node = self.asNode();
const parent = node.parentNode() orelse return;
const next = node.nextSibling();
_ = try parent.removeChild(node, page);
const ref_node = self.asNode();
const parent = ref_node.parentNode() orelse return;
var rm_ref_node = true;
for (nodes) |node_or_text| {
const child = try node_or_text.toNode(page);
_ = try parent.insertBefore(child, next, page);
if (child == ref_node) {
rm_ref_node = false;
continue;
}
_ = try parent.insertBefore(child, ref_node, page);
}
if (rm_ref_node) {
_ = try parent.removeChild(ref_node, page);
}
}

View File

@@ -876,11 +876,11 @@ pub fn before(self: *Element, nodes: []const Node.NodeOrText, page: *Page) !void
pub fn after(self: *Element, nodes: []const Node.NodeOrText, page: *Page) !void {
const node = self.asNode();
const parent = node.parentNode() orelse return;
const next = node.nextSibling();
const viable_next = Node.NodeOrText.viableNextSibling(node, nodes);
for (nodes) |node_or_text| {
const child = try node_or_text.toNode(page);
_ = try parent.insertBefore(child, next, page);
_ = try parent.insertBefore(child, viable_next, page);
}
}

View File

@@ -1074,6 +1074,25 @@ pub const NodeOrText = union(enum) {
.text => |txt| page.createTextNode(txt),
};
}
/// DOM spec: first following sibling of `node` that is not in `nodes`.
pub fn viableNextSibling(node: *Node, nodes: []const NodeOrText) ?*Node {
var sibling = node.nextSibling() orelse return null;
blk: while (true) {
for (nodes) |n| {
switch (n) {
.node => |nn| if (sibling == nn) {
sibling = sibling.nextSibling() orelse return null;
continue :blk;
},
.text => {},
}
} else {
return sibling;
}
}
return null;
}
};
const testing = @import("../../testing.zig");