mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 17:37:37 +00:00
LibWeb: Support multiple values in :lang()
selector
Parse them, and also don't give up completely if the first language listed doesn't match an element.
This commit is contained in:
parent
39cba61c2d
commit
12a2750d1e
5 changed files with 63 additions and 7 deletions
16
Tests/LibWeb/Ref/css-lang-selector-ref.html
Normal file
16
Tests/LibWeb/Ref/css-lang-selector-ref.html
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<html lang="en">
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
border: 1px solid black;
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
#fr, #de {
|
||||||
|
background-color: blue;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div>Red</div>
|
||||||
|
<div id="fr">Blue</div>
|
||||||
|
<div id="de">Blue</div>
|
||||||
|
</html>
|
18
Tests/LibWeb/Ref/css-lang-selector.html
Normal file
18
Tests/LibWeb/Ref/css-lang-selector.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<html lang="en">
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
div:lang(en) {
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
div:lang("fr",de) {
|
||||||
|
background-color: blue;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div>Red</div>
|
||||||
|
<div lang="fr">Blue</div>
|
||||||
|
<div lang="de">Blue</div>
|
||||||
|
</html>
|
|
@ -2,5 +2,6 @@
|
||||||
"square-flex.html": "square-ref.html",
|
"square-flex.html": "square-ref.html",
|
||||||
"separate-borders-inline-table.html": "separate-borders-ref.html",
|
"separate-borders-inline-table.html": "separate-borders-ref.html",
|
||||||
"opacity-stacking.html": "opacity-stacking-ref.html",
|
"opacity-stacking.html": "opacity-stacking-ref.html",
|
||||||
"css-gradient-currentcolor.html": "css-gradient-currentcolor-ref.html"
|
"css-gradient-currentcolor.html": "css-gradient-currentcolor-ref.html",
|
||||||
|
"css-lang-selector.html": "css-lang-selector-ref.html"
|
||||||
}
|
}
|
||||||
|
|
|
@ -664,9 +664,29 @@ Parser::ParseErrorOr<Selector::SimpleSelector> Parser::parse_pseudo_simple_selec
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case PseudoClassMetadata::ParameterType::LanguageRanges: {
|
case PseudoClassMetadata::ParameterType::LanguageRanges: {
|
||||||
// FIXME: Support multiple, comma-separated, language ranges.
|
|
||||||
Vector<FlyString> languages;
|
Vector<FlyString> languages;
|
||||||
languages.append(pseudo_function.values().first().token().to_string().release_value_but_fixme_should_propagate_errors());
|
auto function_token_stream = TokenStream(pseudo_function.values());
|
||||||
|
auto language_token_lists = parse_a_comma_separated_list_of_component_values(function_token_stream);
|
||||||
|
|
||||||
|
for (auto language_token_list : language_token_lists) {
|
||||||
|
auto language_token_stream = TokenStream(language_token_list);
|
||||||
|
language_token_stream.skip_whitespace();
|
||||||
|
auto language_token = language_token_stream.next_token();
|
||||||
|
if (!(language_token.is(Token::Type::Ident) || language_token.is(Token::Type::String))) {
|
||||||
|
dbgln_if(CSS_PARSER_DEBUG, "Invalid language range in :{}() - not a string/ident", pseudo_function.name());
|
||||||
|
return ParseError::SyntaxError;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto language_string = language_token.is(Token::Type::String) ? language_token.token().string() : language_token.token().ident();
|
||||||
|
languages.append(MUST(FlyString::from_utf8(language_string)));
|
||||||
|
|
||||||
|
language_token_stream.skip_whitespace();
|
||||||
|
if (language_token_stream.has_next_token()) {
|
||||||
|
dbgln_if(CSS_PARSER_DEBUG, "Invalid language range in :{}() - trailing tokens", pseudo_function.name());
|
||||||
|
return ParseError::SyntaxError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Selector::SimpleSelector {
|
return Selector::SimpleSelector {
|
||||||
.type = Selector::SimpleSelector::Type::PseudoClass,
|
.type = Selector::SimpleSelector::Type::PseudoClass,
|
||||||
.value = Selector::SimpleSelector::PseudoClassSelector {
|
.value = Selector::SimpleSelector::PseudoClassSelector {
|
||||||
|
|
|
@ -44,13 +44,14 @@ static inline bool matches_lang_pseudo_class(DOM::Element const& element, Vector
|
||||||
// FIXME: This is ad-hoc. Implement a proper language range matching algorithm as recommended by BCP47.
|
// FIXME: This is ad-hoc. Implement a proper language range matching algorithm as recommended by BCP47.
|
||||||
for (auto const& language : languages) {
|
for (auto const& language : languages) {
|
||||||
if (language.is_empty())
|
if (language.is_empty())
|
||||||
return false;
|
continue;
|
||||||
if (language == "*"sv)
|
if (language == "*"sv)
|
||||||
return true;
|
return true;
|
||||||
if (!element_language.to_string().contains('-'))
|
if (!element_language.to_string().contains('-') && Infra::is_ascii_case_insensitive_match(element_language, language))
|
||||||
return Infra::is_ascii_case_insensitive_match(element_language, language);
|
return true;
|
||||||
auto parts = element_language.to_string().split_limit('-', 2).release_value_but_fixme_should_propagate_errors();
|
auto parts = element_language.to_string().split_limit('-', 2).release_value_but_fixme_should_propagate_errors();
|
||||||
return Infra::is_ascii_case_insensitive_match(parts[0], language);
|
if (Infra::is_ascii_case_insensitive_match(parts[0], language))
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue