diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp index 9f42142c2d..9870fd4ca8 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.cpp +++ b/Userland/Libraries/LibWeb/DOM/Element.cpp @@ -358,6 +358,32 @@ DOM::ExceptionOr Element::matches(StringView selectors) const return false; } +// https://dom.spec.whatwg.org/#dom-element-closest +DOM::ExceptionOr Element::closest(StringView selectors) const +{ + auto maybe_selectors = parse_selector(CSS::ParsingContext(static_cast(const_cast(*this))), selectors); + if (!maybe_selectors.has_value()) + return DOM::SyntaxError::create("Failed to parse selector"); + + auto matches_selectors = [](CSS::SelectorList const& selector_list, Element const* element) { + for (auto& selector : selector_list) { + if (!SelectorEngine::matches(selector, *element)) + return false; + } + return true; + }; + + auto const selector_list = maybe_selectors.release_value(); + for (auto* element = this; element; element = element->parent_element()) { + if (!matches_selectors(selector_list, element)) + continue; + + return element; + } + + return nullptr; +} + ExceptionOr Element::set_inner_html(String const& markup) { auto result = DOMParsing::inner_html_setter(*this, markup); diff --git a/Userland/Libraries/LibWeb/DOM/Element.h b/Userland/Libraries/LibWeb/DOM/Element.h index 03a6fecff1..dec2c12879 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.h +++ b/Userland/Libraries/LibWeb/DOM/Element.h @@ -63,6 +63,7 @@ public: RefPtr const& class_list(); DOM::ExceptionOr matches(StringView selectors) const; + DOM::ExceptionOr closest(StringView selectors) const; int client_top() const; int client_left() const; diff --git a/Userland/Libraries/LibWeb/DOM/Element.idl b/Userland/Libraries/LibWeb/DOM/Element.idl index 3cf0b0f255..0569653dd0 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.idl +++ b/Userland/Libraries/LibWeb/DOM/Element.idl @@ -25,6 +25,7 @@ interface Element : Node { [SameObject, PutForwards=value] readonly attribute DOMTokenList classList; boolean matches(DOMString selectors); + Element? closest(DOMString selectors); // legacy alias of .matches [ImplementedAs=matches] boolean webkitMatchesSelector(DOMString selectors);