mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 03:37:43 +00:00
LibWeb: Add 'PseudoElement' as a CSS SimpleSelector::Type
Same reasoning again! This is the last one. While I was at it, I added the two remaining CSS2.2 pseudo-elements, ::first-line and ::first-letter. All 4 are handled in the new CSS parser, including with the compatibility single-colon syntax. I have not added support to the old parser.
This commit is contained in:
parent
4af7d41879
commit
8cae79cc8d
4 changed files with 66 additions and 12 deletions
|
@ -363,10 +363,24 @@ Optional<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore for now, otherwise we produce a "false positive" selector
|
if (is_pseudo) {
|
||||||
// and apply styles to the element itself, not its pseudo element
|
auto pseudo_name = ((Token)current_value).ident();
|
||||||
if (is_pseudo)
|
simple_selector.type = Selector::SimpleSelector::Type::PseudoElement;
|
||||||
return {};
|
|
||||||
|
if (pseudo_name.equals_ignoring_case("before")) {
|
||||||
|
simple_selector.pseudo_element = Selector::SimpleSelector::PseudoElement::Before;
|
||||||
|
} else if (pseudo_name.equals_ignoring_case("after")) {
|
||||||
|
simple_selector.pseudo_element = Selector::SimpleSelector::PseudoElement::After;
|
||||||
|
} else if (pseudo_name.equals_ignoring_case("first-line")) {
|
||||||
|
simple_selector.pseudo_element = Selector::SimpleSelector::PseudoElement::FirstLine;
|
||||||
|
} else if (pseudo_name.equals_ignoring_case("first-letter")) {
|
||||||
|
simple_selector.pseudo_element = Selector::SimpleSelector::PseudoElement::FirstLetter;
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return simple_selector;
|
||||||
|
}
|
||||||
|
|
||||||
auto& pseudo_class = simple_selector.pseudo_class;
|
auto& pseudo_class = simple_selector.pseudo_class;
|
||||||
|
|
||||||
|
@ -411,6 +425,22 @@ Optional<Selector> Parser::parse_single_selector(TokenStream<T>& tokens, bool is
|
||||||
pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Enabled;
|
pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Enabled;
|
||||||
} else if (pseudo_name.equals_ignoring_case("checked")) {
|
} else if (pseudo_name.equals_ignoring_case("checked")) {
|
||||||
pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Checked;
|
pseudo_class.type = Selector::SimpleSelector::PseudoClass::Type::Checked;
|
||||||
|
} else if (pseudo_name.equals_ignoring_case("before")) {
|
||||||
|
// Single-colon syntax allowed for compatibility. https://www.w3.org/TR/selectors/#pseudo-element-syntax
|
||||||
|
simple_selector.type = Selector::SimpleSelector::Type::PseudoElement;
|
||||||
|
simple_selector.pseudo_element = Selector::SimpleSelector::PseudoElement::Before;
|
||||||
|
} else if (pseudo_name.equals_ignoring_case("after")) {
|
||||||
|
// See :before
|
||||||
|
simple_selector.type = Selector::SimpleSelector::Type::PseudoElement;
|
||||||
|
simple_selector.pseudo_element = Selector::SimpleSelector::PseudoElement::After;
|
||||||
|
} else if (pseudo_name.equals_ignoring_case("first-line")) {
|
||||||
|
// See :before
|
||||||
|
simple_selector.type = Selector::SimpleSelector::Type::PseudoElement;
|
||||||
|
simple_selector.pseudo_element = Selector::SimpleSelector::PseudoElement::FirstLine;
|
||||||
|
} else if (pseudo_name.equals_ignoring_case("first-letter")) {
|
||||||
|
// See :before
|
||||||
|
simple_selector.type = Selector::SimpleSelector::Type::PseudoElement;
|
||||||
|
simple_selector.pseudo_element = Selector::SimpleSelector::PseudoElement::FirstLetter;
|
||||||
} else {
|
} else {
|
||||||
dbgln("Unknown pseudo class: '{}'", pseudo_name);
|
dbgln("Unknown pseudo class: '{}'", pseudo_name);
|
||||||
return simple_selector;
|
return simple_selector;
|
||||||
|
|
|
@ -24,6 +24,7 @@ public:
|
||||||
Class,
|
Class,
|
||||||
Attribute,
|
Attribute,
|
||||||
PseudoClass,
|
PseudoClass,
|
||||||
|
PseudoElement,
|
||||||
};
|
};
|
||||||
Type type { Type::Invalid };
|
Type type { Type::Invalid };
|
||||||
|
|
||||||
|
@ -71,6 +72,8 @@ public:
|
||||||
None,
|
None,
|
||||||
Before,
|
Before,
|
||||||
After,
|
After,
|
||||||
|
FirstLine,
|
||||||
|
FirstLetter,
|
||||||
};
|
};
|
||||||
PseudoElement pseudo_element { PseudoElement::None };
|
PseudoElement pseudo_element { PseudoElement::None };
|
||||||
|
|
||||||
|
|
|
@ -175,14 +175,6 @@ static bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoClass cons
|
||||||
|
|
||||||
static bool matches(CSS::Selector::SimpleSelector const& component, DOM::Element const& element)
|
static bool matches(CSS::Selector::SimpleSelector const& component, DOM::Element const& element)
|
||||||
{
|
{
|
||||||
switch (component.pseudo_element) {
|
|
||||||
case CSS::Selector::SimpleSelector::PseudoElement::None:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// FIXME: Implement pseudo-elements.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (component.type) {
|
switch (component.type) {
|
||||||
case CSS::Selector::SimpleSelector::Type::Universal:
|
case CSS::Selector::SimpleSelector::Type::Universal:
|
||||||
return true;
|
return true;
|
||||||
|
@ -196,6 +188,9 @@ static bool matches(CSS::Selector::SimpleSelector const& component, DOM::Element
|
||||||
return matches_attribute(component.attribute, element);
|
return matches_attribute(component.attribute, element);
|
||||||
case CSS::Selector::SimpleSelector::Type::PseudoClass:
|
case CSS::Selector::SimpleSelector::Type::PseudoClass:
|
||||||
return matches_pseudo_class(component.pseudo_class, element);
|
return matches_pseudo_class(component.pseudo_class, element);
|
||||||
|
case CSS::Selector::SimpleSelector::Type::PseudoElement:
|
||||||
|
// FIXME: Implement pseudo-elements.
|
||||||
|
return false;
|
||||||
default:
|
default:
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,6 +320,9 @@ void dump_selector(StringBuilder& builder, CSS::Selector const& selector)
|
||||||
case CSS::Selector::SimpleSelector::Type::PseudoClass:
|
case CSS::Selector::SimpleSelector::Type::PseudoClass:
|
||||||
type_description = "PseudoClass";
|
type_description = "PseudoClass";
|
||||||
break;
|
break;
|
||||||
|
case CSS::Selector::SimpleSelector::Type::PseudoElement:
|
||||||
|
type_description = "PseudoElement";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.appendff("{}:{}", type_description, simple_selector.value);
|
builder.appendff("{}:{}", type_description, simple_selector.value);
|
||||||
|
@ -397,6 +400,29 @@ void dump_selector(StringBuilder& builder, CSS::Selector const& selector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::PseudoElement) {
|
||||||
|
char const* pseudo_element_description = "";
|
||||||
|
switch (simple_selector.pseudo_element) {
|
||||||
|
case CSS::Selector::SimpleSelector::PseudoElement::None:
|
||||||
|
pseudo_element_description = "None";
|
||||||
|
break;
|
||||||
|
case CSS::Selector::SimpleSelector::PseudoElement::Before:
|
||||||
|
pseudo_element_description = "before";
|
||||||
|
break;
|
||||||
|
case CSS::Selector::SimpleSelector::PseudoElement::After:
|
||||||
|
pseudo_element_description = "after";
|
||||||
|
break;
|
||||||
|
case CSS::Selector::SimpleSelector::PseudoElement::FirstLine:
|
||||||
|
pseudo_element_description = "first-line";
|
||||||
|
break;
|
||||||
|
case CSS::Selector::SimpleSelector::PseudoElement::FirstLetter:
|
||||||
|
pseudo_element_description = "first-letter";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.appendff(" pseudo_element={}", pseudo_element_description);
|
||||||
|
}
|
||||||
|
|
||||||
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::Attribute) {
|
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::Attribute) {
|
||||||
char const* attribute_match_type_description = "";
|
char const* attribute_match_type_description = "";
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue