mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 17:17:44 +00:00
LibWeb: Support CSS :only-of-type selector
This matches any element that doesn't have a sibling with the same tag name as itself.
This commit is contained in:
parent
b9b24cb1c1
commit
7c33a084fb
5 changed files with 31 additions and 10 deletions
|
@ -551,6 +551,8 @@ Result<Selector::SimpleSelector, Parser::ParsingResult> Parser::parse_simple_sel
|
||||||
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Link;
|
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Link;
|
||||||
} else if (pseudo_name.equals_ignoring_case("only-child")) {
|
} else if (pseudo_name.equals_ignoring_case("only-child")) {
|
||||||
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::OnlyChild;
|
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")) {
|
} else if (pseudo_name.equals_ignoring_case("root")) {
|
||||||
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Root;
|
simple_selector.pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Root;
|
||||||
} else if (pseudo_name.equals_ignoring_case("visited")) {
|
} else if (pseudo_name.equals_ignoring_case("visited")) {
|
||||||
|
|
|
@ -135,6 +135,7 @@ String Selector::SimpleSelector::serialize() const
|
||||||
case Selector::SimpleSelector::PseudoClass::Type::Root:
|
case Selector::SimpleSelector::PseudoClass::Type::Root:
|
||||||
case Selector::SimpleSelector::PseudoClass::Type::FirstOfType:
|
case Selector::SimpleSelector::PseudoClass::Type::FirstOfType:
|
||||||
case Selector::SimpleSelector::PseudoClass::Type::LastOfType:
|
case Selector::SimpleSelector::PseudoClass::Type::LastOfType:
|
||||||
|
case Selector::SimpleSelector::PseudoClass::Type::OnlyOfType:
|
||||||
case Selector::SimpleSelector::PseudoClass::Type::Disabled:
|
case Selector::SimpleSelector::PseudoClass::Type::Disabled:
|
||||||
case Selector::SimpleSelector::PseudoClass::Type::Enabled:
|
case Selector::SimpleSelector::PseudoClass::Type::Enabled:
|
||||||
case Selector::SimpleSelector::PseudoClass::Type::Checked:
|
case Selector::SimpleSelector::PseudoClass::Type::Checked:
|
||||||
|
@ -281,6 +282,8 @@ constexpr StringView pseudo_class_name(Selector::SimpleSelector::PseudoClass::Ty
|
||||||
return "first-of-type"sv;
|
return "first-of-type"sv;
|
||||||
case Selector::SimpleSelector::PseudoClass::Type::LastOfType:
|
case Selector::SimpleSelector::PseudoClass::Type::LastOfType:
|
||||||
return "last-of-type"sv;
|
return "last-of-type"sv;
|
||||||
|
case Selector::SimpleSelector::PseudoClass::Type::OnlyOfType:
|
||||||
|
return "only-of-type"sv;
|
||||||
case Selector::SimpleSelector::PseudoClass::Type::Disabled:
|
case Selector::SimpleSelector::PseudoClass::Type::Disabled:
|
||||||
return "disabled"sv;
|
return "disabled"sv;
|
||||||
case Selector::SimpleSelector::PseudoClass::Type::Enabled:
|
case Selector::SimpleSelector::PseudoClass::Type::Enabled:
|
||||||
|
|
|
@ -57,6 +57,7 @@ public:
|
||||||
Root,
|
Root,
|
||||||
FirstOfType,
|
FirstOfType,
|
||||||
LastOfType,
|
LastOfType,
|
||||||
|
OnlyOfType,
|
||||||
NthChild,
|
NthChild,
|
||||||
NthLastChild,
|
NthLastChild,
|
||||||
Disabled,
|
Disabled,
|
||||||
|
|
|
@ -53,6 +53,24 @@ static inline bool matches_attribute(CSS::Selector::SimpleSelector::Attribute co
|
||||||
return false;
|
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)
|
static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoClass const& pseudo_class, DOM::Element const& element)
|
||||||
{
|
{
|
||||||
switch (pseudo_class.type) {
|
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:
|
case CSS::Selector::SimpleSelector::PseudoClass::Type::Root:
|
||||||
return is<HTML::HTMLHtmlElement>(element);
|
return is<HTML::HTMLHtmlElement>(element);
|
||||||
case CSS::Selector::SimpleSelector::PseudoClass::Type::FirstOfType:
|
case CSS::Selector::SimpleSelector::PseudoClass::Type::FirstOfType:
|
||||||
for (auto* sibling = element.previous_element_sibling(); sibling; sibling = sibling->previous_element_sibling()) {
|
return !previous_sibling_with_same_tag_name(element);
|
||||||
if (sibling->tag_name() == element.tag_name())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
case CSS::Selector::SimpleSelector::PseudoClass::Type::LastOfType:
|
case CSS::Selector::SimpleSelector::PseudoClass::Type::LastOfType:
|
||||||
for (auto* sibling = element.next_element_sibling(); sibling; sibling = sibling->next_element_sibling()) {
|
return !next_sibling_with_same_tag_name(element);
|
||||||
if (sibling->tag_name() == element.tag_name())
|
case CSS::Selector::SimpleSelector::PseudoClass::Type::OnlyOfType:
|
||||||
return false;
|
return !previous_sibling_with_same_tag_name(element) && !next_sibling_with_same_tag_name(element);
|
||||||
}
|
|
||||||
return true;
|
|
||||||
case CSS::Selector::SimpleSelector::PseudoClass::Type::Disabled:
|
case CSS::Selector::SimpleSelector::PseudoClass::Type::Disabled:
|
||||||
if (!element.tag_name().equals_ignoring_case(HTML::TagNames::input))
|
if (!element.tag_name().equals_ignoring_case(HTML::TagNames::input))
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -382,6 +382,9 @@ void dump_selector(StringBuilder& builder, CSS::Selector const& selector)
|
||||||
case CSS::Selector::SimpleSelector::PseudoClass::Type::LastOfType:
|
case CSS::Selector::SimpleSelector::PseudoClass::Type::LastOfType:
|
||||||
pseudo_class_description = "LastOfType";
|
pseudo_class_description = "LastOfType";
|
||||||
break;
|
break;
|
||||||
|
case CSS::Selector::SimpleSelector::PseudoClass::Type::OnlyOfType:
|
||||||
|
pseudo_class_description = "OnlyOfType";
|
||||||
|
break;
|
||||||
case CSS::Selector::SimpleSelector::PseudoClass::Type::NthChild:
|
case CSS::Selector::SimpleSelector::PseudoClass::Type::NthChild:
|
||||||
pseudo_class_description = "NthChild";
|
pseudo_class_description = "NthChild";
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue