Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/browser/dom/element.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down Expand Up @@ -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" },
Expand Down