LibWeb: Parse the ::part() pseudo-element selector
It doesn't yet do anything, but it helps a few tests that just check serialization.
This commit is contained in:
parent
01b7800068
commit
16c12c1485
9 changed files with 49 additions and 15 deletions
|
|
@ -534,6 +534,24 @@ Parser::ParseErrorOr<Selector::SimpleSelector> Parser::parse_pseudo_simple_selec
|
|||
value = Selector::create(move(compound_selectors));
|
||||
break;
|
||||
}
|
||||
case PseudoElementMetadata::ParameterType::IdentList: {
|
||||
// <ident>+
|
||||
Selector::PseudoElementSelector::IdentList idents;
|
||||
while (function_tokens.has_next_token()) {
|
||||
if (!function_tokens.next_token().is(Token::Type::Ident)) {
|
||||
ErrorReporter::the().report(InvalidPseudoClassOrElementError {
|
||||
.name = MUST(String::formatted("::{}", pseudo_name)),
|
||||
.value_string = name_token.to_string(),
|
||||
.description = "Contains invalid <ident>."_string,
|
||||
});
|
||||
return ParseError::SyntaxError;
|
||||
}
|
||||
idents.append(function_tokens.consume_a_token().token().ident());
|
||||
function_tokens.discard_whitespace();
|
||||
}
|
||||
value = move(idents);
|
||||
break;
|
||||
}
|
||||
case PseudoElementMetadata::ParameterType::PTNameSelector: {
|
||||
// <pt-name-selector> = '*' | <custom-ident>
|
||||
// https://drafts.csswg.org/css-view-transitions-1/#typedef-pt-name-selector
|
||||
|
|
|
|||
|
|
@ -76,6 +76,11 @@
|
|||
"marker": {
|
||||
"spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-marker"
|
||||
},
|
||||
"part": {
|
||||
"spec": "https://drafts.csswg.org/css-shadow-parts/#selectordef-part",
|
||||
"type": "function",
|
||||
"function-syntax": "<ident>+"
|
||||
},
|
||||
"placeholder": {
|
||||
"spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-placeholder",
|
||||
"property-whitelist": [
|
||||
|
|
|
|||
|
|
@ -308,9 +308,9 @@ String Selector::PseudoElementSelector::serialize() const
|
|||
}
|
||||
|
||||
m_value.visit(
|
||||
[&builder](NonnullRefPtr<Selector> const& compund_selector) {
|
||||
[&builder](NonnullRefPtr<Selector> const& compound_selector) {
|
||||
builder.append('(');
|
||||
builder.append(compund_selector->serialize());
|
||||
builder.append(compound_selector->serialize());
|
||||
builder.append(')');
|
||||
},
|
||||
[&builder](PTNameSelector const& pt_name_selector) {
|
||||
|
|
@ -321,6 +321,11 @@ String Selector::PseudoElementSelector::serialize() const
|
|||
builder.append(pt_name_selector.value);
|
||||
builder.append(')');
|
||||
},
|
||||
[&builder](IdentList const& ident_list) {
|
||||
builder.append('(');
|
||||
builder.join(' ', ident_list);
|
||||
builder.append(')');
|
||||
},
|
||||
[](Empty const&) {});
|
||||
|
||||
return builder.to_string_without_validation();
|
||||
|
|
|
|||
|
|
@ -30,8 +30,9 @@ public:
|
|||
bool is_universal { false };
|
||||
FlyString value {};
|
||||
};
|
||||
using IdentList = Vector<FlyString>;
|
||||
|
||||
using Value = Variant<Empty, PTNameSelector, NonnullRefPtr<Selector>>;
|
||||
using Value = Variant<Empty, PTNameSelector, NonnullRefPtr<Selector>, IdentList>;
|
||||
|
||||
explicit PseudoElementSelector(PseudoElement type, Value value = {})
|
||||
: m_type(type)
|
||||
|
|
@ -63,6 +64,8 @@ public:
|
|||
// NOTE: This can't (currently) be a CompoundSelector due to cyclic dependencies.
|
||||
Selector const& compound_selector() const { return m_value.get<NonnullRefPtr<Selector>>(); }
|
||||
|
||||
IdentList const& ident_list() const { return m_value.get<IdentList>(); }
|
||||
|
||||
private:
|
||||
PseudoElement m_type;
|
||||
String m_name;
|
||||
|
|
|
|||
|
|
@ -595,6 +595,7 @@ void dump_selector(StringBuilder& builder, CSS::Selector const& selector, int in
|
|||
switch (pseudo_element_metadata.parameter_type) {
|
||||
case CSS::PseudoElementMetadata::ParameterType::None:
|
||||
case CSS::PseudoElementMetadata::ParameterType::CompoundSelector:
|
||||
case CSS::PseudoElementMetadata::ParameterType::IdentList:
|
||||
break;
|
||||
case CSS::PseudoElementMetadata::ParameterType::PTNameSelector: {
|
||||
auto const& [is_universal, value] = pseudo_element.pt_name_selector();
|
||||
|
|
|
|||
|
|
@ -1300,8 +1300,7 @@ GC::Ref<CSS::CSSStyleProperties> Window::get_computed_style(DOM::Element& elemen
|
|||
auto type = parse_pseudo_element_selector(CSS::Parser::ParsingParams(associated_document()), pseudo_element.value());
|
||||
|
||||
// 2. If type is failure, or is a ::slotted() or ::part() pseudo-element, let obj be null.
|
||||
// FIXME: Handle ::part() here too when we support it.
|
||||
if (!type.has_value() || type.value().type() == CSS::PseudoElement::Slotted) {
|
||||
if (!type.has_value() || first_is_one_of(type.value().type(), CSS::PseudoElement::Slotted, CSS::PseudoElement::Part)) {
|
||||
object = {};
|
||||
}
|
||||
// 3. Otherwise let obj be the given pseudo-element of elt.
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ struct PseudoElementMetadata {
|
|||
enum class ParameterType {
|
||||
None,
|
||||
CompoundSelector,
|
||||
IdentList,
|
||||
PTNameSelector,
|
||||
} parameter_type;
|
||||
bool is_valid_as_function;
|
||||
|
|
@ -515,10 +516,12 @@ PseudoElementMetadata pseudo_element_metadata(PseudoElement pseudo_element)
|
|||
String parameter_type = "None"_string;
|
||||
if (is_valid_as_function) {
|
||||
auto const& function_syntax = pseudo_element.get_string("function-syntax"sv).value();
|
||||
if (function_syntax == "<pt-name-selector>"sv) {
|
||||
parameter_type = "PTNameSelector"_string;
|
||||
} else if (function_syntax == "<compound-selector>"sv) {
|
||||
if (function_syntax == "<compound-selector>"sv) {
|
||||
parameter_type = "CompoundSelector"_string;
|
||||
} else if (function_syntax == "<ident>+"sv) {
|
||||
parameter_type = "IdentList"_string;
|
||||
} else if (function_syntax == "<pt-name-selector>"sv) {
|
||||
parameter_type = "PTNameSelector"_string;
|
||||
} else {
|
||||
warnln("Unrecognized pseudo-element parameter type: `{}`", function_syntax);
|
||||
VERIFY_NOT_REACHED();
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ Harness status: OK
|
|||
|
||||
Found 33 tests
|
||||
|
||||
24 Pass
|
||||
9 Fail
|
||||
26 Pass
|
||||
7 Fail
|
||||
Pass ":is(div )" should be a valid selector
|
||||
Pass ":where(div )" should be a valid selector
|
||||
Pass ":is(div + bar, div ~ .baz)" should be a valid selector
|
||||
|
|
@ -28,8 +28,8 @@ Fail ":is(::before)" should be a valid selector
|
|||
Fail ":where(::before)" should be a valid selector
|
||||
Pass ":is(div) + bar" should be a valid selector
|
||||
Pass ":where(div) + bar" should be a valid selector
|
||||
Fail "::part(foo):is(:hover)" should be a valid selector
|
||||
Fail "::part(foo):where(:hover)" should be a valid selector
|
||||
Pass "::part(foo):is(:hover)" should be a valid selector
|
||||
Pass "::part(foo):where(:hover)" should be a valid selector
|
||||
Fail "::part(foo):is([attr='value'])" should be a valid selector
|
||||
Fail "::part(foo):where([attr='value'])" should be a valid selector
|
||||
Pass ":not(:is(div))" should be a valid selector
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ Harness status: OK
|
|||
|
||||
Found 8 tests
|
||||
|
||||
6 Pass
|
||||
2 Fail
|
||||
7 Pass
|
||||
1 Fail
|
||||
Pass :state() parsing passes
|
||||
Pass :state() parsing failures
|
||||
Pass deprecated :--state parsing failures
|
||||
Fail :state(foo) serialization
|
||||
Pass :state(foo) serialization
|
||||
Pass :state(foo) in simple cases
|
||||
Pass :state(foo) and other pseudo classes
|
||||
Fail :state(foo) and ::part()
|
||||
|
|
|
|||
Loading…
Reference in a new issue