diff --git a/src/browser/webapi/CData.zig b/src/browser/webapi/CData.zig index 761ce9ea..6ea89268 100644 --- a/src/browser/webapi/CData.zig +++ b/src/browser/webapi/CData.zig @@ -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); } } diff --git a/src/browser/webapi/Element.zig b/src/browser/webapi/Element.zig index f772b3b1..2f2ba2c2 100644 --- a/src/browser/webapi/Element.zig +++ b/src/browser/webapi/Element.zig @@ -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); } } diff --git a/src/browser/webapi/Node.zig b/src/browser/webapi/Node.zig index 42eae2e1..cf4ef5f9 100644 --- a/src/browser/webapi/Node.zig +++ b/src/browser/webapi/Node.zig @@ -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");