Skip to content

Commit dd7e6d3

Browse files
committed
Element closest
1 parent b086337 commit dd7e6d3

File tree

1 file changed

+38
-0
lines changed

1 file changed

+38
-0
lines changed

src/browser/dom/element.zig

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,30 @@ pub const Element = struct {
135135
}
136136
}
137137

138+
// 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.
139+
// Returns the closest ancestor Element or itself, which matches the selectors. If there are no such element, null.
140+
pub fn _closest(self: *parser.Element, selector: []const u8, state: *SessionState) !?*parser.Element {
141+
const cssParse = @import("../css/css.zig").parse;
142+
const CssNodeWrap = @import("../css/libdom.zig").Node;
143+
const select = try cssParse(state.call_arena, selector, .{});
144+
145+
var current: CssNodeWrap = .{ .node = parser.elementToNode(self) };
146+
while (true) {
147+
if (try select.match(current)) {
148+
if (!current.isElement()) {
149+
std.debug.print("closest: is not an element: {s}\n", .{try current.tag()});
150+
return null;
151+
}
152+
return parser.nodeToElement(current.node);
153+
}
154+
if (try current.parent()) |parent| {
155+
current = parent;
156+
continue;
157+
}
158+
return null;
159+
}
160+
}
161+
138162
pub fn _hasAttributes(self: *parser.Element) !bool {
139163
return try parser.nodeHasAttributes(parser.elementToNode(self));
140164
}
@@ -401,6 +425,20 @@ test "Browser.DOM.Element" {
401425
.{ "cl.length", "2" },
402426
}, .{});
403427

428+
try runner.testCases(&.{
429+
.{ "const el2 = document.createElement('div');", "undefined" },
430+
.{ "el2.id = 'closest'; el2.className = 'ok';", "ok" },
431+
.{ "el2.closest('#closest')", "[object HTMLDivElement]" },
432+
.{ "el2.closest('.ok')", "[object HTMLDivElement]" },
433+
.{ "el2.closest('#9000')", "null" },
434+
.{ "el2.closest('.notok')", "null" },
435+
436+
.{ "const sp = document.createElement('span');", "undefined" },
437+
.{ "el2.appendChild(sp);", "[object HTMLSpanElement]" },
438+
.{ "sp.closest('#closest')", "[object HTMLDivElement]" },
439+
.{ "sp.closest('#9000')", "null" },
440+
}, .{});
441+
404442
try runner.testCases(&.{
405443
.{ "let a = document.getElementById('content')", "undefined" },
406444
.{ "a.hasAttributes()", "true" },

0 commit comments

Comments
 (0)