Explorar o código

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.
Andreas Kling %!s(int64=5) %!d(string=hai) anos
pai
achega
06aec9667e

+ 6 - 6
Base/home/anon/www/qsa.html

@@ -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")
-        throw 2;
-    if (elements[1].id !== "foo2")
+    if (elements[0].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) {

+ 2 - 0
Libraries/LibWeb/DOM/Document.cpp

@@ -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)) {

+ 1 - 0
Libraries/LibWeb/Dump.cpp

@@ -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";

+ 12 - 11
Libraries/LibWeb/Parser/CSSParser.cpp

@@ -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();
-    if (!complex_selector.has_value())
-        return {};
-    complex_selector.value().relation = Selector::ComplexSelector::Relation::None;
-    return Selector({ complex_selector.value() });
+    return parser.parse_individual_selector();
 }
 }
 
 
 RefPtr<StyleSheet> parse_css(const StringView& css)
 RefPtr<StyleSheet> parse_css(const StringView& css)