From 3af716d93449308f34a7e48c60cc7b9b75d9d510 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Wed, 13 Dec 2023 15:19:46 +0100 Subject: [PATCH 1/6] dom: add element prepend and append --- src/dom/element.zig | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/dom/element.zig b/src/dom/element.zig index cd12f625..0c370160 100644 --- a/src/dom/element.zig +++ b/src/dom/element.zig @@ -5,6 +5,7 @@ const parser = @import("../netsurf.zig"); const jsruntime = @import("jsruntime"); const Case = jsruntime.test_utils.Case; const checkCases = jsruntime.test_utils.checkCases; +const Variadic = jsruntime.Variadic; const collection = @import("html_collection.zig"); @@ -281,6 +282,39 @@ pub const Element = struct { return list; } + // 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: ?Variadic(*parser.Node)) !void { + if (nodes == null) return; + if (nodes.?.slice.len == 0) return; + const nself = parser.elementToNode(self); + const first = try parser.nodeFirstChild(nself); + + if (first == null) { + for (nodes.?.slice) |node| { + _ = try parser.nodeAppendChild(nself, node); + } + return; + } + + for (nodes.?.slice) |node| { + _ = try parser.nodeInsertBefore(nself, first.?, node); + } + } + + // 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: ?Variadic(*parser.Node)) !void { + if (nodes == null) return; + if (nodes.?.slice.len == 0) return; + const nself = parser.elementToNode(self); + for (nodes.?.slice) |node| { + _ = try parser.nodeAppendChild(nself, node); + } + } + pub fn deinit(_: *parser.Element, _: std.mem.Allocator) void {} }; @@ -358,6 +392,9 @@ pub fn testExecFn( .{ .src = "c.firstElementChild.nodeName", .ex = "A" }, .{ .src = "c.lastElementChild.nodeName", .ex = "P" }, .{ .src = "c.childElementCount", .ex = "3" }, + + .{ .src = "c.prepend(document.createTextNode('foo'))", .ex = "undefined" }, + .{ .src = "c.append(document.createTextNode('bar'))", .ex = "undefined" }, }; try checkCases(js_env, &parentNode); From 84aad08806832f8a3734c0f14e45fb151900f0b0 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Wed, 13 Dec 2023 15:51:48 +0100 Subject: [PATCH 2/6] dom: add element.replaceChildren --- src/dom/element.zig | 27 +++++++++++++++++++++++++++ src/netsurf.zig | 7 +++++++ 2 files changed, 34 insertions(+) diff --git a/src/dom/element.zig b/src/dom/element.zig index 0c370160..43000655 100644 --- a/src/dom/element.zig +++ b/src/dom/element.zig @@ -315,6 +315,33 @@ pub const Element = struct { } } + // 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: ?Variadic(*parser.Node)) !void { + // if (nodes == null) return; + // if (nodes.?.slice.len == 0) return; + + const nself = parser.elementToNode(self); + + // remove existing children + if (try parser.nodeHasChildNodes(nself)) { + const children = try parser.nodeGetChildNodes(nself); + const ln = try parser.nodeListLength(children); + var i: u32 = 0; + while (i < ln) { + defer i += 1; + const child = try parser.nodeListItem(children, i) orelse continue; + _ = try parser.nodeRemoveChild(nself, child); + } + } + + // add new children + for (nodes.?.slice) |node| { + _ = try parser.nodeAppendChild(nself, node); + } + } + pub fn deinit(_: *parser.Element, _: std.mem.Allocator) void {} }; diff --git a/src/netsurf.zig b/src/netsurf.zig index dca13979..341dcd9f 100644 --- a/src/netsurf.zig +++ b/src/netsurf.zig @@ -620,6 +620,13 @@ pub fn nodeSetTextContent(node: *Node, value: []const u8) !void { try DOMErr(err); } +pub fn nodeGetChildNodes(node: *Node) !*NodeList { + var nlist: ?*NodeList = undefined; + const err = nodeVtable(node).dom_node_get_child_nodes.?(node, &nlist); + try DOMErr(err); + return nlist.?; +} + pub fn nodeAppendChild(node: *Node, child: *Node) !*Node { var res: ?*Node = undefined; const err = nodeVtable(node).dom_node_append_child.?(node, child, &res); From c0643398d7a677e05f3f1a90a7fffa7eb09caaea Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Wed, 13 Dec 2023 15:52:05 +0100 Subject: [PATCH 3/6] dom: declare document prepend/append/replaceChildren --- src/dom/document.zig | 23 +++++++++++++++++++++++ src/dom/element.zig | 6 +++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/dom/document.zig b/src/dom/document.zig index 9c878871..47582f6b 100644 --- a/src/dom/document.zig +++ b/src/dom/document.zig @@ -5,6 +5,7 @@ const parser = @import("../netsurf.zig"); const jsruntime = @import("jsruntime"); const Case = jsruntime.test_utils.Case; const checkCases = jsruntime.test_utils.checkCases; +const Variadic = jsruntime.Variadic; const Node = @import("node.zig").Node; const NodeList = @import("nodelist.zig").NodeList; @@ -228,6 +229,28 @@ pub const Document = struct { return list; } + // 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(_: *parser.Document, _: ?Variadic(*parser.Node)) !void { + return parser.DOMError.HierarchyRequest; + } + + // 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(_: *parser.Document, _: ?Variadic(*parser.Node)) !void { + return parser.DOMError.HierarchyRequest; + } + + // 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(_: *parser.Document, _: ?Variadic(*parser.Node)) !void { + // TODO implement function correctly + return parser.DOMError.HierarchyRequest; + } + pub fn deinit(_: *parser.Document, _: std.mem.Allocator) void {} }; diff --git a/src/dom/element.zig b/src/dom/element.zig index 43000655..47d42b05 100644 --- a/src/dom/element.zig +++ b/src/dom/element.zig @@ -299,7 +299,7 @@ pub const Element = struct { } for (nodes.?.slice) |node| { - _ = try parser.nodeInsertBefore(nself, first.?, node); + _ = try parser.nodeInsertBefore(nself, node, first.?); } } @@ -319,8 +319,8 @@ pub const Element = struct { // 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: ?Variadic(*parser.Node)) !void { - // if (nodes == null) return; - // if (nodes.?.slice.len == 0) return; + if (nodes == null) return; + if (nodes.?.slice.len == 0) return; const nself = parser.elementToNode(self); From f8484e9f47ddedb7132f22473b73f663e271c16f Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Mon, 15 Jan 2024 14:49:55 +0100 Subject: [PATCH 4/6] dom: add parentnode test --- tests/wpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/wpt b/tests/wpt index 28814be2..c9e76582 160000 --- a/tests/wpt +++ b/tests/wpt @@ -1 +1 @@ -Subproject commit 28814be2ea9b17bb1b73946d245fba50f746da0b +Subproject commit c9e7658223455f1e3ce11d348cb79528326c7c4c From b33fc688986af367ea33d1b906c33c77158ec3c9 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Mon, 15 Jan 2024 15:45:23 +0100 Subject: [PATCH 5/6] dom: add doc.prepend/append --- src/dom/document.zig | 58 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/src/dom/document.zig b/src/dom/document.zig index 47582f6b..8e0ade80 100644 --- a/src/dom/document.zig +++ b/src/dom/document.zig @@ -232,23 +232,61 @@ pub const Document = struct { // 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(_: *parser.Document, _: ?Variadic(*parser.Node)) !void { - return parser.DOMError.HierarchyRequest; + pub fn _prepend(self: *parser.Document, nodes: ?Variadic(*parser.Node)) !void { + if (nodes == null) return; + if (nodes.?.slice.len == 0) return; + const nself = parser.documentToNode(self); + const first = try parser.nodeFirstChild(nself); + + if (first == null) { + for (nodes.?.slice) |node| { + _ = try parser.nodeAppendChild(nself, node); + } + return; + } + + for (nodes.?.slice) |node| { + _ = try parser.nodeInsertBefore(nself, node, first.?); + } } // 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(_: *parser.Document, _: ?Variadic(*parser.Node)) !void { - return parser.DOMError.HierarchyRequest; + pub fn _append(self: *parser.Document, nodes: ?Variadic(*parser.Node)) !void { + if (nodes == null) return; + if (nodes.?.slice.len == 0) return; + const nself = parser.documentToNode(self); + for (nodes.?.slice) |node| { + _ = try parser.nodeAppendChild(nself, node); + } } // 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(_: *parser.Document, _: ?Variadic(*parser.Node)) !void { - // TODO implement function correctly - return parser.DOMError.HierarchyRequest; + pub fn _replaceChildren(self: *parser.Document, nodes: ?Variadic(*parser.Node)) !void { + if (nodes == null) return; + if (nodes.?.slice.len == 0) return; + + const nself = parser.documentToNode(self); + + // remove existing children + if (try parser.nodeHasChildNodes(nself)) { + const children = try parser.nodeGetChildNodes(nself); + const ln = try parser.nodeListLength(children); + var i: u32 = 0; + while (i < ln) { + defer i += 1; + const child = try parser.nodeListItem(children, i) orelse continue; + _ = try parser.nodeRemoveChild(nself, child); + } + } + + // add new children + for (nodes.?.slice) |node| { + _ = try parser.nodeAppendChild(nself, node); + } } pub fn deinit(_: *parser.Document, _: std.mem.Allocator) void {} @@ -404,6 +442,12 @@ pub fn testExecFn( .{ .src = "nd.firstElementChild", .ex = "null" }, .{ .src = "nd.lastElementChild", .ex = "null" }, .{ .src = "nd.childElementCount", .ex = "0" }, + + .{ .src = "let emptydoc = document.createElement('html')", .ex = "undefined" }, + .{ .src = "emptydoc.prepend(document.createElement('html'))", .ex = "undefined" }, + + .{ .src = "let emptydoc2 = document.createElement('html')", .ex = "undefined" }, + .{ .src = "emptydoc2.append(document.createElement('html'))", .ex = "undefined" }, }; try checkCases(js_env, &parentNode); From d8df27ead760fc4aa4f027640dfe716470818fde Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Thu, 18 Jan 2024 09:59:26 +0100 Subject: [PATCH 6/6] dom: refacto append/prepend/replaceChild in Node --- src/dom/document.zig | 45 +++------------------------------- src/dom/element.zig | 45 +++------------------------------- src/dom/node.zig | 58 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 84 deletions(-) diff --git a/src/dom/document.zig b/src/dom/document.zig index 8e0ade80..702d92e2 100644 --- a/src/dom/document.zig +++ b/src/dom/document.zig @@ -233,60 +233,21 @@ pub const Document = struct { // 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: ?Variadic(*parser.Node)) !void { - if (nodes == null) return; - if (nodes.?.slice.len == 0) return; - const nself = parser.documentToNode(self); - const first = try parser.nodeFirstChild(nself); - - if (first == null) { - for (nodes.?.slice) |node| { - _ = try parser.nodeAppendChild(nself, node); - } - return; - } - - for (nodes.?.slice) |node| { - _ = try parser.nodeInsertBefore(nself, node, first.?); - } + 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: ?Variadic(*parser.Node)) !void { - if (nodes == null) return; - if (nodes.?.slice.len == 0) return; - const nself = parser.documentToNode(self); - for (nodes.?.slice) |node| { - _ = try parser.nodeAppendChild(nself, node); - } + 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: ?Variadic(*parser.Node)) !void { - if (nodes == null) return; - if (nodes.?.slice.len == 0) return; - - const nself = parser.documentToNode(self); - - // remove existing children - if (try parser.nodeHasChildNodes(nself)) { - const children = try parser.nodeGetChildNodes(nself); - const ln = try parser.nodeListLength(children); - var i: u32 = 0; - while (i < ln) { - defer i += 1; - const child = try parser.nodeListItem(children, i) orelse continue; - _ = try parser.nodeRemoveChild(nself, child); - } - } - - // add new children - for (nodes.?.slice) |node| { - _ = try parser.nodeAppendChild(nself, node); - } + return Node.replaceChildren(parser.documentToNode(self), nodes); } pub fn deinit(_: *parser.Document, _: std.mem.Allocator) void {} diff --git a/src/dom/element.zig b/src/dom/element.zig index 47d42b05..ceeaeaee 100644 --- a/src/dom/element.zig +++ b/src/dom/element.zig @@ -286,60 +286,21 @@ pub const Element = struct { // 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: ?Variadic(*parser.Node)) !void { - if (nodes == null) return; - if (nodes.?.slice.len == 0) return; - const nself = parser.elementToNode(self); - const first = try parser.nodeFirstChild(nself); - - if (first == null) { - for (nodes.?.slice) |node| { - _ = try parser.nodeAppendChild(nself, node); - } - return; - } - - for (nodes.?.slice) |node| { - _ = try parser.nodeInsertBefore(nself, node, first.?); - } + 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: ?Variadic(*parser.Node)) !void { - if (nodes == null) return; - if (nodes.?.slice.len == 0) return; - const nself = parser.elementToNode(self); - for (nodes.?.slice) |node| { - _ = try parser.nodeAppendChild(nself, node); - } + 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: ?Variadic(*parser.Node)) !void { - if (nodes == null) return; - if (nodes.?.slice.len == 0) return; - - const nself = parser.elementToNode(self); - - // remove existing children - if (try parser.nodeHasChildNodes(nself)) { - const children = try parser.nodeGetChildNodes(nself); - const ln = try parser.nodeListLength(children); - var i: u32 = 0; - while (i < ln) { - defer i += 1; - const child = try parser.nodeListItem(children, i) orelse continue; - _ = try parser.nodeRemoveChild(nself, child); - } - } - - // add new children - for (nodes.?.slice) |node| { - _ = try parser.nodeAppendChild(nself, node); - } + return Node.replaceChildren(parser.elementToNode(self), nodes); } pub fn deinit(_: *parser.Element, _: std.mem.Allocator) void {} diff --git a/src/dom/node.zig b/src/dom/node.zig index 5ba2ee91..50aeb522 100644 --- a/src/dom/node.zig +++ b/src/dom/node.zig @@ -4,6 +4,8 @@ const jsruntime = @import("jsruntime"); const Case = jsruntime.test_utils.Case; const checkCases = jsruntime.test_utils.checkCases; const runScript = jsruntime.test_utils.runScript; +const Variadic = jsruntime.Variadic; + const generate = @import("../generate.zig"); const parser = @import("../netsurf.zig"); @@ -257,6 +259,62 @@ pub const Node = struct { return try Node.toInterface(res); } + // 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: ?Variadic(*parser.Node)) !void { + if (nodes == null) return; + if (nodes.?.slice.len == 0) return; + const first = try parser.nodeFirstChild(self); + + if (first == null) { + for (nodes.?.slice) |node| { + _ = try parser.nodeAppendChild(self, node); + } + return; + } + + for (nodes.?.slice) |node| { + _ = try parser.nodeInsertBefore(self, node, first.?); + } + } + + // 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: ?Variadic(*parser.Node)) !void { + if (nodes == null) return; + if (nodes.?.slice.len == 0) return; + for (nodes.?.slice) |node| { + _ = try parser.nodeAppendChild(self, node); + } + } + + // 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: ?Variadic(*parser.Node)) !void { + if (nodes == null) return; + if (nodes.?.slice.len == 0) return; + + // remove existing children + if (try parser.nodeHasChildNodes(self)) { + const children = try parser.nodeGetChildNodes(self); + const ln = try parser.nodeListLength(children); + var i: u32 = 0; + while (i < ln) { + defer i += 1; + const child = try parser.nodeListItem(children, i) orelse continue; + _ = try parser.nodeRemoveChild(self, child); + } + } + + // add new children + for (nodes.?.slice) |node| { + _ = try parser.nodeAppendChild(self, node); + } + } + pub fn deinit(_: *parser.Node, _: std.mem.Allocator) void {} };