From dd7e6d383198c31f6f69fba25a838934c78e435c Mon Sep 17 00:00:00 2001 From: sjorsdonkers <72333389+sjorsdonkers@users.noreply.github.com> Date: Mon, 12 May 2025 17:20:43 +0200 Subject: [PATCH 1/2] Element closest --- src/browser/dom/element.zig | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/browser/dom/element.zig b/src/browser/dom/element.zig index fb15304f..b256c841 100644 --- a/src/browser/dom/element.zig +++ b/src/browser/dom/element.zig @@ -135,6 +135,30 @@ pub const Element = struct { } } + // The closest() method of the Element interface traverses the element and its parents (heading toward the document root) until it finds a node that matches the specified CSS selector. + // Returns the closest ancestor Element or itself, which matches the selectors. If there are no such element, null. + pub fn _closest(self: *parser.Element, selector: []const u8, state: *SessionState) !?*parser.Element { + const cssParse = @import("../css/css.zig").parse; + const CssNodeWrap = @import("../css/libdom.zig").Node; + const select = try cssParse(state.call_arena, selector, .{}); + + var current: CssNodeWrap = .{ .node = parser.elementToNode(self) }; + while (true) { + if (try select.match(current)) { + if (!current.isElement()) { + std.debug.print("closest: is not an element: {s}\n", .{try current.tag()}); + return null; + } + return parser.nodeToElement(current.node); + } + if (try current.parent()) |parent| { + current = parent; + continue; + } + return null; + } + } + pub fn _hasAttributes(self: *parser.Element) !bool { return try parser.nodeHasAttributes(parser.elementToNode(self)); } @@ -401,6 +425,20 @@ test "Browser.DOM.Element" { .{ "cl.length", "2" }, }, .{}); + try runner.testCases(&.{ + .{ "const el2 = document.createElement('div');", "undefined" }, + .{ "el2.id = 'closest'; el2.className = 'ok';", "ok" }, + .{ "el2.closest('#closest')", "[object HTMLDivElement]" }, + .{ "el2.closest('.ok')", "[object HTMLDivElement]" }, + .{ "el2.closest('#9000')", "null" }, + .{ "el2.closest('.notok')", "null" }, + + .{ "const sp = document.createElement('span');", "undefined" }, + .{ "el2.appendChild(sp);", "[object HTMLSpanElement]" }, + .{ "sp.closest('#closest')", "[object HTMLDivElement]" }, + .{ "sp.closest('#9000')", "null" }, + }, .{}); + try runner.testCases(&.{ .{ "let a = document.getElementById('content')", "undefined" }, .{ "a.hasAttributes()", "true" }, From 0998ae753c4f138ff5a8c3339a04f355120a3a5e Mon Sep 17 00:00:00 2001 From: sjorsdonkers <72333389+sjorsdonkers@users.noreply.github.com> Date: Tue, 13 May 2025 10:31:40 +0200 Subject: [PATCH 2/2] use log an brievity --- src/browser/dom/element.zig | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/browser/dom/element.zig b/src/browser/dom/element.zig index b256c841..f48451a8 100644 --- a/src/browser/dom/element.zig +++ b/src/browser/dom/element.zig @@ -31,6 +31,8 @@ const NodeList = @import("nodelist.zig").NodeList; const HTMLElem = @import("../html/elements.zig"); pub const Union = @import("../html/elements.zig").Union; +const log = std.log.scoped(.element); + // WEB IDL https://dom.spec.whatwg.org/#element pub const Element = struct { pub const Self = parser.Element; @@ -146,16 +148,12 @@ pub const Element = struct { while (true) { if (try select.match(current)) { if (!current.isElement()) { - std.debug.print("closest: is not an element: {s}\n", .{try current.tag()}); + log.err("closest: is not an element: {s}", .{try current.tag()}); return null; } return parser.nodeToElement(current.node); } - if (try current.parent()) |parent| { - current = parent; - continue; - } - return null; + current = try current.parent() orelse return null; } }