mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 15:13:28 +00:00
Merge pull request #617 from lightpanda-io/before_and_after
Add before and after functions
This commit is contained in:
@@ -112,6 +112,16 @@ pub const CharacterData = struct {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn _before(self: *parser.CharacterData, nodes: []const Node.NodeOrText) !void {
|
||||
const ref_node = parser.characterDataToNode(self);
|
||||
return Node.before(ref_node, nodes);
|
||||
}
|
||||
|
||||
pub fn _after(self: *parser.CharacterData, nodes: []const Node.NodeOrText) !void {
|
||||
const ref_node = parser.characterDataToNode(self);
|
||||
return Node.after(ref_node, nodes);
|
||||
}
|
||||
};
|
||||
|
||||
// Tests
|
||||
|
||||
@@ -227,28 +227,17 @@ pub const Document = struct {
|
||||
return css.querySelectorAll(allocator, parser.documentToNode(self), selector);
|
||||
}
|
||||
|
||||
// TODO according with https://dom.spec.whatwg.org/#parentnode, the
|
||||
// function must accept either node or string.
|
||||
// blocked by https://github.com/lightpanda-io/jsruntime-lib/issues/114
|
||||
pub fn _prepend(self: *parser.Document, nodes: []const *parser.Node) !void {
|
||||
pub fn _prepend(self: *parser.Document, nodes: []const Node.NodeOrText) !void {
|
||||
return Node.prepend(parser.documentToNode(self), nodes);
|
||||
}
|
||||
|
||||
// TODO according with https://dom.spec.whatwg.org/#parentnode, the
|
||||
// function must accept either node or string.
|
||||
// blocked by https://github.com/lightpanda-io/jsruntime-lib/issues/114
|
||||
pub fn _append(self: *parser.Document, nodes: []const *parser.Node) !void {
|
||||
pub fn _append(self: *parser.Document, nodes: []const Node.NodeOrText) !void {
|
||||
return Node.append(parser.documentToNode(self), nodes);
|
||||
}
|
||||
|
||||
// TODO according with https://dom.spec.whatwg.org/#parentnode, the
|
||||
// function must accept either node or string.
|
||||
// blocked by https://github.com/lightpanda-io/jsruntime-lib/issues/114
|
||||
pub fn _replaceChildren(self: *parser.Document, nodes: []const *parser.Node) !void {
|
||||
pub fn _replaceChildren(self: *parser.Document, nodes: []const Node.NodeOrText) !void {
|
||||
return Node.replaceChildren(parser.documentToNode(self), nodes);
|
||||
}
|
||||
|
||||
pub fn deinit(_: *parser.Document, _: std.mem.Allocator) void {}
|
||||
};
|
||||
|
||||
const testing = @import("../../testing.zig");
|
||||
|
||||
@@ -313,24 +313,25 @@ pub const Element = struct {
|
||||
return css.querySelectorAll(state.arena, parser.elementToNode(self), selector);
|
||||
}
|
||||
|
||||
// TODO according with https://dom.spec.whatwg.org/#parentnode, the
|
||||
// function must accept either node or string.
|
||||
// blocked by https://github.com/lightpanda-io/jsruntime-lib/issues/114
|
||||
pub fn _prepend(self: *parser.Element, nodes: []const *parser.Node) !void {
|
||||
pub fn _prepend(self: *parser.Element, nodes: []const Node.NodeOrText) !void {
|
||||
return Node.prepend(parser.elementToNode(self), nodes);
|
||||
}
|
||||
|
||||
// TODO according with https://dom.spec.whatwg.org/#parentnode, the
|
||||
// function must accept either node or string.
|
||||
// blocked by https://github.com/lightpanda-io/jsruntime-lib/issues/114
|
||||
pub fn _append(self: *parser.Element, nodes: []const *parser.Node) !void {
|
||||
pub fn _append(self: *parser.Element, nodes: []const Node.NodeOrText) !void {
|
||||
return Node.append(parser.elementToNode(self), nodes);
|
||||
}
|
||||
|
||||
// TODO according with https://dom.spec.whatwg.org/#parentnode, the
|
||||
// function must accept either node or string.
|
||||
// blocked by https://github.com/lightpanda-io/jsruntime-lib/issues/114
|
||||
pub fn _replaceChildren(self: *parser.Element, nodes: []const *parser.Node) !void {
|
||||
pub fn _before(self: *parser.Element, nodes: []const Node.NodeOrText) !void {
|
||||
const ref_node = parser.elementToNode(self);
|
||||
return Node.before(ref_node, nodes);
|
||||
}
|
||||
|
||||
pub fn _after(self: *parser.Element, nodes: []const Node.NodeOrText) !void {
|
||||
const ref_node = parser.elementToNode(self);
|
||||
return Node.after(ref_node, nodes);
|
||||
}
|
||||
|
||||
pub fn _replaceChildren(self: *parser.Element, nodes: []const Node.NodeOrText) !void {
|
||||
return Node.replaceChildren(parser.elementToNode(self), nodes);
|
||||
}
|
||||
|
||||
@@ -529,4 +530,28 @@ test "Browser.DOM.Element" {
|
||||
.{ "el.matches('#9000')", "false" },
|
||||
.{ "el.matches('.notok')", "false" },
|
||||
}, .{});
|
||||
|
||||
// before
|
||||
try runner.testCases(&.{
|
||||
.{ "const before_container = document.createElement('div');", "undefined" },
|
||||
.{ "document.append(before_container);", "undefined" },
|
||||
.{ "const b1 = document.createElement('div');", "undefined" },
|
||||
.{ "before_container.append(b1);", "undefined" },
|
||||
|
||||
.{ "const b1_a = document.createElement('p');", "undefined" },
|
||||
.{ "b1.before(b1_a, 'over 9000');", "undefined" },
|
||||
.{ "before_container.innerHTML", "<p></p>over 9000<div></div>" },
|
||||
}, .{});
|
||||
|
||||
// after
|
||||
try runner.testCases(&.{
|
||||
.{ "const after_container = document.createElement('div');", "undefined" },
|
||||
.{ "document.append(after_container);", "undefined" },
|
||||
.{ "const a1 = document.createElement('div');", "undefined" },
|
||||
.{ "after_container.append(a1);", "undefined" },
|
||||
|
||||
.{ "const a1_a = document.createElement('p');", "undefined" },
|
||||
.{ "a1.after('over 9000', a1_a);", "undefined" },
|
||||
.{ "after_container.innerHTML", "<div></div>over 9000<p></p>" },
|
||||
}, .{});
|
||||
}
|
||||
|
||||
@@ -337,65 +337,72 @@ pub const Node = struct {
|
||||
// For now, it checks only if new nodes are not self.
|
||||
// TODO implements the others contraints.
|
||||
// see https://dom.spec.whatwg.org/#concept-node-tree
|
||||
pub fn hierarchy(self: *parser.Node, nodes: []const *parser.Node) !bool {
|
||||
if (nodes.len == 0) return true;
|
||||
|
||||
for (nodes) |node| if (self == node) return false;
|
||||
|
||||
pub fn hierarchy(self: *parser.Node, nodes: []const NodeOrText) bool {
|
||||
for (nodes) |n| {
|
||||
if (n.is(self)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO according with https://dom.spec.whatwg.org/#parentnode, the
|
||||
// function must accept either node or string.
|
||||
// blocked by https://github.com/lightpanda-io/jsruntime-lib/issues/114
|
||||
pub fn prepend(self: *parser.Node, nodes: []const *parser.Node) !void {
|
||||
if (nodes.len == 0) return;
|
||||
pub fn prepend(self: *parser.Node, nodes: []const NodeOrText) !void {
|
||||
if (nodes.len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check hierarchy
|
||||
if (!try hierarchy(self, nodes)) return parser.DOMError.HierarchyRequest;
|
||||
if (!hierarchy(self, nodes)) {
|
||||
return parser.DOMError.HierarchyRequest;
|
||||
}
|
||||
|
||||
const first = try parser.nodeFirstChild(self);
|
||||
if (first == null) {
|
||||
const doc = (try parser.nodeOwnerDocument(self)) orelse return;
|
||||
|
||||
if (try parser.nodeFirstChild(self)) |first| {
|
||||
for (nodes) |node| {
|
||||
_ = try parser.nodeAppendChild(self, node);
|
||||
_ = try parser.nodeInsertBefore(self, try node.toNode(doc), first);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (nodes) |node| {
|
||||
_ = try parser.nodeInsertBefore(self, node, first.?);
|
||||
_ = try parser.nodeAppendChild(self, try node.toNode(doc));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO according with https://dom.spec.whatwg.org/#parentnode, the
|
||||
// function must accept either node or string.
|
||||
// blocked by https://github.com/lightpanda-io/jsruntime-lib/issues/114
|
||||
pub fn append(self: *parser.Node, nodes: []const *parser.Node) !void {
|
||||
if (nodes.len == 0) return;
|
||||
pub fn append(self: *parser.Node, nodes: []const NodeOrText) !void {
|
||||
if (nodes.len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check hierarchy
|
||||
if (!try hierarchy(self, nodes)) return parser.DOMError.HierarchyRequest;
|
||||
if (!hierarchy(self, nodes)) {
|
||||
return parser.DOMError.HierarchyRequest;
|
||||
}
|
||||
|
||||
const doc = (try parser.nodeOwnerDocument(self)) orelse return;
|
||||
for (nodes) |node| {
|
||||
_ = try parser.nodeAppendChild(self, node);
|
||||
_ = try parser.nodeAppendChild(self, try node.toNode(doc));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO according with https://dom.spec.whatwg.org/#parentnode, the
|
||||
// function must accept either node or string.
|
||||
// blocked by https://github.com/lightpanda-io/jsruntime-lib/issues/114
|
||||
pub fn replaceChildren(self: *parser.Node, nodes: []const *parser.Node) !void {
|
||||
if (nodes.len == 0) return;
|
||||
pub fn replaceChildren(self: *parser.Node, nodes: []const NodeOrText) !void {
|
||||
if (nodes.len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check hierarchy
|
||||
if (!try hierarchy(self, nodes)) return parser.DOMError.HierarchyRequest;
|
||||
if (!hierarchy(self, nodes)) {
|
||||
return parser.DOMError.HierarchyRequest;
|
||||
}
|
||||
|
||||
// remove existing children
|
||||
try removeChildren(self);
|
||||
|
||||
const doc = (try parser.nodeOwnerDocument(self)) orelse return;
|
||||
// add new children
|
||||
for (nodes) |node| {
|
||||
_ = try parser.nodeAppendChild(self, node);
|
||||
_ = try parser.nodeAppendChild(self, try node.toNode(doc));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,7 +421,87 @@ pub const Node = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deinit(_: *parser.Node, _: std.mem.Allocator) void {}
|
||||
pub fn before(self: *parser.Node, nodes: []const NodeOrText) !void {
|
||||
const parent = try parser.nodeParentNode(self) orelse return;
|
||||
const doc = (try parser.nodeOwnerDocument(parent)) orelse return;
|
||||
|
||||
var sibling: ?*parser.Node = self;
|
||||
// have to find the first sibling that isn't in nodes
|
||||
CHECK: while (sibling) |s| {
|
||||
for (nodes) |n| {
|
||||
if (n.is(s)) {
|
||||
sibling = try parser.nodePreviousSibling(s);
|
||||
continue :CHECK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (sibling == null) {
|
||||
sibling = try parser.nodeFirstChild(parent);
|
||||
}
|
||||
|
||||
if (sibling) |ref_node| {
|
||||
for (nodes) |node| {
|
||||
_ = try parser.nodeInsertBefore(parent, try node.toNode(doc), ref_node);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
return Node.prepend(self, nodes);
|
||||
}
|
||||
|
||||
pub fn after(self: *parser.Node, nodes: []const NodeOrText) !void {
|
||||
const parent = try parser.nodeParentNode(self) orelse return;
|
||||
const doc = (try parser.nodeOwnerDocument(parent)) orelse return;
|
||||
|
||||
// have to find the first sibling that isn't in nodes
|
||||
var sibling = try parser.nodeNextSibling(self);
|
||||
CHECK: while (sibling) |s| {
|
||||
for (nodes) |n| {
|
||||
if (n.is(s)) {
|
||||
sibling = try parser.nodeNextSibling(s);
|
||||
continue :CHECK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (sibling) |ref_node| {
|
||||
for (nodes) |node| {
|
||||
_ = try parser.nodeInsertBefore(parent, try node.toNode(doc), ref_node);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (nodes) |node| {
|
||||
_ = try parser.nodeAppendChild(parent, try node.toNode(doc));
|
||||
}
|
||||
}
|
||||
|
||||
// A lot of functions take either a node or text input.
|
||||
// The text input is to be converted into a Text node.
|
||||
pub const NodeOrText = union(enum) {
|
||||
text: []const u8,
|
||||
node: *parser.Node,
|
||||
|
||||
fn toNode(self: NodeOrText, doc: *parser.Document) !*parser.Node {
|
||||
return switch (self) {
|
||||
.node => |n| n,
|
||||
.text => |txt| @ptrCast(try parser.documentCreateTextNode(doc, txt)),
|
||||
};
|
||||
}
|
||||
|
||||
// Whether the node represented by the NodeOrText is the same as the
|
||||
// given Node. Always false for text values as these represent as-of-yet
|
||||
// created Text nodes.
|
||||
fn is(self: NodeOrText, other: *parser.Node) bool {
|
||||
return switch (self) {
|
||||
.text => false,
|
||||
.node => |n| n == other,
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const testing = @import("../../testing.zig");
|
||||
|
||||
Reference in New Issue
Block a user