1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-30 23:48:11 +00:00

LibWeb: Support more advanced selectors in document.querySelectorAll()

I made some mistakes in the selector parsing code. It's now able to
parse selectors composed of multiple complex selectors, instead of just
one complex selector.
This commit is contained in:
Andreas Kling 2020-03-29 22:45:38 +02:00
parent c1c56b1131
commit 06aec9667e
4 changed files with 21 additions and 17 deletions

View file

@ -4,20 +4,20 @@
</head> </head>
<body> <body>
<div id="foo1" class="foo"></div> <div id="foo1" class="foo"></div>
<code>
<div id="foo2" class="foo"></div> <div id="foo2" class="foo"></div>
<div id="foo3" class="foo"></div> <div id="foo3" class="foo"></div>
</code>
<pre id="out"></pre> <pre id="out"></pre>
<script> <script>
var elements = document.querySelectorAll(".foo"); var elements = document.querySelectorAll("code .foo");
try { try {
if (elements.length !== 3) if (elements.length !== 2)
throw 1; throw 1;
if (elements[0].id !== "foo1") if (elements[0].id !== "foo2")
throw 2;
if (elements[1].id !== "foo2")
throw 3; throw 3;
if (elements[2].id !== "foo3") if (elements[1].id !== "foo3")
throw 4; throw 4;
document.getElementById('out').innerHTML = "Success!"; document.getElementById('out').innerHTML = "Success!";
} catch (e) { } catch (e) {

View file

@ -315,6 +315,8 @@ NonnullRefPtrVector<Element> Document::query_selector_all(const StringView& sele
if (!selector.has_value()) if (!selector.has_value())
return {}; return {};
dump_selector(selector.value());
NonnullRefPtrVector<Element> elements; NonnullRefPtrVector<Element> elements;
for_each_in_subtree_of_type<Element>([&](auto& element) { for_each_in_subtree_of_type<Element>([&](auto& element) {
if (SelectorEngine::matches(selector.value(), element)) { if (SelectorEngine::matches(selector.value(), element)) {

View file

@ -180,6 +180,7 @@ void dump_selector(const Selector& selector)
const char* relation_description = ""; const char* relation_description = "";
switch (complex_selector.relation) { switch (complex_selector.relation) {
case Selector::ComplexSelector::Relation::None: case Selector::ComplexSelector::Relation::None:
relation_description = "None";
break; break;
case Selector::ComplexSelector::Relation::ImmediateChild: case Selector::ComplexSelector::Relation::ImmediateChild:
relation_description = "ImmediateChild"; relation_description = "ImmediateChild";

View file

@ -267,13 +267,10 @@ public:
Optional<Selector::SimpleSelector> parse_simple_selector() Optional<Selector::SimpleSelector> parse_simple_selector()
{ {
if (!peek())
return {};
if (consume_whitespace_or_comments()) if (consume_whitespace_or_comments())
return {}; return {};
if (peek() == '{' || peek() == ',' || is_combinator(peek())) if (!peek() || peek() == '{' || peek() == ',' || is_combinator(peek()))
return {}; return {};
Selector::SimpleSelector::Type type; Selector::SimpleSelector::Type type;
@ -447,7 +444,7 @@ public:
if (complex_selector.has_value()) if (complex_selector.has_value())
complex_selectors.append(complex_selector.value()); complex_selectors.append(complex_selector.value());
consume_whitespace_or_comments(); consume_whitespace_or_comments();
if (peek() == ',' || peek() == '{') if (!peek() || peek() == ',' || peek() == '{')
break; break;
} }
@ -456,7 +453,15 @@ public:
complex_selectors.first().relation = Selector::ComplexSelector::Relation::None; complex_selectors.first().relation = Selector::ComplexSelector::Relation::None;
current_rule.selectors.append(Selector(move(complex_selectors))); current_rule.selectors.append(Selector(move(complex_selectors)));
}; }
Optional<Selector> parse_individual_selector()
{
parse_selector();
if (current_rule.selectors.is_empty())
return {};
return current_rule.selectors.last();
}
void parse_selector_list() void parse_selector_list()
{ {
@ -664,11 +669,7 @@ private:
Optional<Selector> parse_selector(const StringView& selector_text) Optional<Selector> parse_selector(const StringView& selector_text)
{ {
CSSParser parser(selector_text); CSSParser parser(selector_text);
auto complex_selector = parser.parse_complex_selector(); return parser.parse_individual_selector();
if (!complex_selector.has_value())
return {};
complex_selector.value().relation = Selector::ComplexSelector::Relation::None;
return Selector({ complex_selector.value() });
} }
RefPtr<StyleSheet> parse_css(const StringView& css) RefPtr<StyleSheet> parse_css(const StringView& css)