diff options
author | Andreas Kling <kling@serenityos.org> | 2022-02-17 22:43:22 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-02-18 01:49:32 +0100 |
commit | 7c33a084fb6e8e751173b6c959c30533b3f02f23 (patch) | |
tree | e5e70482a2a9d383e02b1e443f6806cdd0e47d24 | |
parent | b9b24cb1c1c73fbcbdc9bec6b9b2bf8e47efa4a6 (diff) | |
download | serenity-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.
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Selector.cpp | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Selector.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp | 32 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Dump.cpp | 3 |
5 files changed, 31 insertions, 10 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index d5154baed4..e5ace9fa06 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -551,6 +551,8 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_simple_sel simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Link; } else if (pseudo_name.equals_ignoring_case("only-child")) { simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::OnlyChild; + } else if (pseudo_name.equals_ignoring_case("only-of-type")) { + simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::OnlyOfType; } else if (pseudo_name.equals_ignoring_case("root")) { simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Root; } else if (pseudo_name.equals_ignoring_case("visited")) { diff --git a/Userland/Libraries/LibWeb/CSS/Selector.cpp b/Userland/Libraries/LibWeb/CSS/Selector.cpp index d88c18b186..6b9e27d2f9 100644 --- a/Userland/Libraries/LibWeb/CSS/Selector.cpp +++ b/Userland/Libraries/LibWeb/CSS/Selector.cpp @@ -135,6 +135,7 @@ String Selector::SimpleSelector::serialize() const case Selector::SimpleSelector::PseudoClass::Type::Root: case Selector::SimpleSelector::PseudoClass::Type::FirstOfType: case Selector::SimpleSelector::PseudoClass::Type::LastOfType: + case Selector::SimpleSelector::PseudoClass::Type::OnlyOfType: case Selector::SimpleSelector::PseudoClass::Type::Disabled: case Selector::SimpleSelector::PseudoClass::Type::Enabled: case Selector::SimpleSelector::PseudoClass::Type::Checked: @@ -281,6 +282,8 @@ constexpr StringView pseudo_class_name(Selector::SimpleSelector::PseudoClass::Ty return "first-of-type"sv; case Selector::SimpleSelector::PseudoClass::Type::LastOfType: return "last-of-type"sv; + case Selector::SimpleSelector::PseudoClass::Type::OnlyOfType: + return "only-of-type"sv; case Selector::SimpleSelector::PseudoClass::Type::Disabled: return "disabled"sv; case Selector::SimpleSelector::PseudoClass::Type::Enabled: diff --git a/Userland/Libraries/LibWeb/CSS/Selector.h b/Userland/Libraries/LibWeb/CSS/Selector.h index 9cca6a0b2b..ce5b7dc109 100644 --- a/Userland/Libraries/LibWeb/CSS/Selector.h +++ b/Userland/Libraries/LibWeb/CSS/Selector.h @@ -57,6 +57,7 @@ public: Root, FirstOfType, LastOfType, + OnlyOfType, NthChild, NthLastChild, Disabled, 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; diff --git a/Userland/Libraries/LibWeb/Dump.cpp b/Userland/Libraries/LibWeb/Dump.cpp index ce4764b603..cee57d23d4 100644 --- a/Userland/Libraries/LibWeb/Dump.cpp +++ b/Userland/Libraries/LibWeb/Dump.cpp @@ -382,6 +382,9 @@ void dump_selector(StringBuilder& builder, CSS::Selector const& selector) case CSS::Selector::SimpleSelector::PseudoClass::Type::LastOfType: pseudo_class_description = "LastOfType"; break; + case CSS::Selector::SimpleSelector::PseudoClass::Type::OnlyOfType: + pseudo_class_description = "OnlyOfType"; + break; case CSS::Selector::SimpleSelector::PseudoClass::Type::NthChild: pseudo_class_description = "NthChild"; break; |