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:
parent
c1c56b1131
commit
06aec9667e
4 changed files with 21 additions and 17 deletions
|
@ -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) {
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue