summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2022-02-17 22:43:22 +0100
committerAndreas Kling <kling@serenityos.org>2022-02-18 01:49:32 +0100
commit7c33a084fb6e8e751173b6c959c30533b3f02f23 (patch)
treee5e70482a2a9d383e02b1e443f6806cdd0e47d24 /Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
parentb9b24cb1c1c73fbcbdc9bec6b9b2bf8e47efa4a6 (diff)
downloadserenity-7c33a084fb6e8e751173b6c959c30533b3f02f23.zip
LibWeb: Support CSS :only-of-type selector
This matches any element that doesn't have a sibling with the same tag name as itself.
Diffstat (limited to 'Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp')
-rw-r--r--Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp32
1 files changed, 22 insertions, 10 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
index cb13ee86ed..40be51417f 100644
--- a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
+++ b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
@@ -53,6 +53,24 @@ static inline bool matches_attribute(CSS::Selector::SimpleSelector::Attribute co
return false;
}
+static inline DOM::Element const* previous_sibling_with_same_tag_name(DOM::Element const& element)
+{
+ for (auto const* sibling = element.previous_element_sibling(); sibling; sibling = sibling->previous_element_sibling()) {
+ if (sibling->tag_name() == element.tag_name())
+ return sibling;
+ }
+ return nullptr;
+}
+
+static inline DOM::Element const* next_sibling_with_same_tag_name(DOM::Element const& element)
+{
+ for (auto const* sibling = element.next_element_sibling(); sibling; sibling = sibling->next_element_sibling()) {
+ if (sibling->tag_name() == element.tag_name())
+ return sibling;
+ }
+ return nullptr;
+}
+
static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoClass const& pseudo_class, DOM::Element const& element)
{
switch (pseudo_class.type) {
@@ -80,17 +98,11 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla
case CSS::Selector::SimpleSelector::PseudoClass::Type::Root:
return is<HTML::HTMLHtmlElement>(element);
case CSS::Selector::SimpleSelector::PseudoClass::Type::FirstOfType:
- for (auto* sibling = element.previous_element_sibling(); sibling; sibling = sibling->previous_element_sibling()) {
- if (sibling->tag_name() == element.tag_name())
- return false;
- }
- return true;
+ return !previous_sibling_with_same_tag_name(element);
case CSS::Selector::SimpleSelector::PseudoClass::Type::LastOfType:
- for (auto* sibling = element.next_element_sibling(); sibling; sibling = sibling->next_element_sibling()) {
- if (sibling->tag_name() == element.tag_name())
- return false;
- }
- return true;
+ return !next_sibling_with_same_tag_name(element);
+ case CSS::Selector::SimpleSelector::PseudoClass::Type::OnlyOfType:
+ return !previous_sibling_with_same_tag_name(element) && !next_sibling_with_same_tag_name(element);
case CSS::Selector::SimpleSelector::PseudoClass::Type::Disabled:
if (!element.tag_name().equals_ignoring_case(HTML::TagNames::input))
return false;