mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-22 04:34:44 +00:00
fix ChildNode after() and replaceWith() sibling ordering
after() captured node.nextSibling() once, which went stale when that sibling was one of the nodes being inserted. Use viableNextSibling() to find the first following sibling not in the nodes list per the DOM spec. replaceWith() in CData had the same stale-reference problem and also removed self before inserting, unlike Element.replaceWith() which keeps self as the insertion anchor. Adopt the same anchor pattern: insert before self, then remove self at the end. Flips ChildNode-after.html from 33/45 to 45/45 and ChildNode-replaceWith.html from 27/33 to 33/33.
This commit is contained in:
@@ -227,24 +227,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 {
|
pub fn after(self: *CData, nodes: []const Node.NodeOrText, page: *Page) !void {
|
||||||
const node = self.asNode();
|
const node = self.asNode();
|
||||||
const parent = node.parentNode() orelse return;
|
const parent = node.parentNode() orelse return;
|
||||||
const next = node.nextSibling();
|
const viable_next = Node.NodeOrText.viableNextSibling(node, nodes);
|
||||||
|
|
||||||
for (nodes) |node_or_text| {
|
for (nodes) |node_or_text| {
|
||||||
const child = try node_or_text.toNode(page);
|
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 {
|
pub fn replaceWith(self: *CData, nodes: []const Node.NodeOrText, page: *Page) !void {
|
||||||
const node = self.asNode();
|
const ref_node = self.asNode();
|
||||||
const parent = node.parentNode() orelse return;
|
const parent = ref_node.parentNode() orelse return;
|
||||||
const next = node.nextSibling();
|
|
||||||
|
|
||||||
_ = try parent.removeChild(node, page);
|
|
||||||
|
|
||||||
|
var rm_ref_node = true;
|
||||||
for (nodes) |node_or_text| {
|
for (nodes) |node_or_text| {
|
||||||
const child = try node_or_text.toNode(page);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -870,11 +870,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 {
|
pub fn after(self: *Element, nodes: []const Node.NodeOrText, page: *Page) !void {
|
||||||
const node = self.asNode();
|
const node = self.asNode();
|
||||||
const parent = node.parentNode() orelse return;
|
const parent = node.parentNode() orelse return;
|
||||||
const next = node.nextSibling();
|
const viable_next = Node.NodeOrText.viableNextSibling(node, nodes);
|
||||||
|
|
||||||
for (nodes) |node_or_text| {
|
for (nodes) |node_or_text| {
|
||||||
const child = try node_or_text.toNode(page);
|
const child = try node_or_text.toNode(page);
|
||||||
_ = try parent.insertBefore(child, next, page);
|
_ = try parent.insertBefore(child, viable_next, page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1069,6 +1069,25 @@ pub const NodeOrText = union(enum) {
|
|||||||
.text => |txt| page.createTextNode(txt),
|
.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");
|
const testing = @import("../../testing.zig");
|
||||||
|
|||||||
Reference in New Issue
Block a user