Prechádzať zdrojové kódy

LibWeb: Add Comment and DocumentFragment bindings, move querySelector...

...{All} to ParentNode. Exposes createDocumentFragment and
createComment on Document. Stubs out the document.body setter. 

Also adds ParentNode back :^).
Luke 4 rokov pred
rodič
commit
8b807e65d7

+ 7 - 1
Libraries/LibWeb/Bindings/NodeWrapperFactory.cpp

@@ -26,8 +26,10 @@
  */
  */
 
 
 #include <LibWeb/Bindings/CharacterDataWrapper.h>
 #include <LibWeb/Bindings/CharacterDataWrapper.h>
-#include <LibWeb/Bindings/DocumentTypeWrapper.h>
+#include <LibWeb/Bindings/CommentWrapper.h>
 #include <LibWeb/Bindings/DocumentWrapper.h>
 #include <LibWeb/Bindings/DocumentWrapper.h>
+#include <LibWeb/Bindings/DocumentFragmentWrapper.h>
+#include <LibWeb/Bindings/DocumentTypeWrapper.h>
 #include <LibWeb/Bindings/HTMLAnchorElementWrapper.h>
 #include <LibWeb/Bindings/HTMLAnchorElementWrapper.h>
 #include <LibWeb/Bindings/HTMLAreaElementWrapper.h>
 #include <LibWeb/Bindings/HTMLAreaElementWrapper.h>
 #include <LibWeb/Bindings/HTMLAudioElementWrapper.h>
 #include <LibWeb/Bindings/HTMLAudioElementWrapper.h>
@@ -315,6 +317,10 @@ NodeWrapper* wrap(JS::GlobalObject& global_object, DOM::Node& node)
         return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLElement>(node)));
         return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<HTML::HTMLElement>(node)));
     if (is<DOM::Element>(node))
     if (is<DOM::Element>(node))
         return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<DOM::Element>(node)));
         return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<DOM::Element>(node)));
+    if (is<DOM::DocumentFragment>(node))
+        return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<DOM::DocumentFragment>(node)));
+    if (is<DOM::Comment>(node))
+        return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<DOM::Comment>(node)));
     if (is<DOM::Text>(node))
     if (is<DOM::Text>(node))
         return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<DOM::Text>(node)));
         return static_cast<NodeWrapper*>(wrap_impl(global_object, downcast<DOM::Text>(node)));
     if (is<DOM::CharacterData>(node))
     if (is<DOM::CharacterData>(node))

+ 3 - 0
Libraries/LibWeb/CMakeLists.txt

@@ -27,6 +27,7 @@ set(SOURCES
     DOM/CharacterData.idl
     DOM/CharacterData.idl
     DOM/Comment.cpp
     DOM/Comment.cpp
     DOM/Document.cpp
     DOM/Document.cpp
+    DOM/DocumentFragment.cpp
     DOM/DocumentType.cpp
     DOM/DocumentType.cpp
     DOM/Element.cpp
     DOM/Element.cpp
     DOM/ElementFactory.cpp
     DOM/ElementFactory.cpp
@@ -210,7 +211,9 @@ function(libweb_js_wrapper class)
 endfunction()
 endfunction()
 
 
 libweb_js_wrapper(DOM/CharacterData)
 libweb_js_wrapper(DOM/CharacterData)
+libweb_js_wrapper(DOM/Comment)
 libweb_js_wrapper(DOM/Document)
 libweb_js_wrapper(DOM/Document)
+libweb_js_wrapper(DOM/DocumentFragment)
 libweb_js_wrapper(DOM/DocumentType)
 libweb_js_wrapper(DOM/DocumentType)
 libweb_js_wrapper(DOM/Element)
 libweb_js_wrapper(DOM/Element)
 libweb_js_wrapper(DOM/Event)
 libweb_js_wrapper(DOM/Event)

+ 5 - 0
Libraries/LibWeb/CSS/Parser/CSSParser.cpp

@@ -58,6 +58,11 @@ ParsingContext::ParsingContext(const DOM::Document& document)
 {
 {
 }
 }
 
 
+ParsingContext::ParsingContext(const DOM::ParentNode& parent_node)
+    : m_document(&parent_node.document())
+{
+}
+
 bool ParsingContext::in_quirks_mode() const
 bool ParsingContext::in_quirks_mode() const
 {
 {
     return m_document ? m_document->in_quirks_mode() : false;
     return m_document ? m_document->in_quirks_mode() : false;

+ 1 - 0
Libraries/LibWeb/CSS/Parser/CSSParser.h

@@ -34,6 +34,7 @@ class ParsingContext {
 public:
 public:
     ParsingContext();
     ParsingContext();
     explicit ParsingContext(const DOM::Document&);
     explicit ParsingContext(const DOM::Document&);
+    explicit ParsingContext(const DOM::ParentNode&);
 
 
     bool in_quirks_mode() const;
     bool in_quirks_mode() const;
 
 

+ 9 - 1
Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp

@@ -486,11 +486,15 @@ void generate_implementation(const IDL::Interface& interface)
     out() << "#include <LibWeb/DOM/Element.h>";
     out() << "#include <LibWeb/DOM/Element.h>";
     out() << "#include <LibWeb/HTML/HTMLElement.h>";
     out() << "#include <LibWeb/HTML/HTMLElement.h>";
     out() << "#include <LibWeb/DOM/EventListener.h>";
     out() << "#include <LibWeb/DOM/EventListener.h>";
+    out() << "#include <LibWeb/Bindings/CommentWrapper.h>";
     out() << "#include <LibWeb/Bindings/DocumentWrapper.h>";
     out() << "#include <LibWeb/Bindings/DocumentWrapper.h>";
+    out() << "#include <LibWeb/Bindings/DocumentFragmentWrapper.h>";
     out() << "#include <LibWeb/Bindings/DocumentTypeWrapper.h>";
     out() << "#include <LibWeb/Bindings/DocumentTypeWrapper.h>";
     out() << "#include <LibWeb/Bindings/HTMLCanvasElementWrapper.h>";
     out() << "#include <LibWeb/Bindings/HTMLCanvasElementWrapper.h>";
+    out() << "#include <LibWeb/Bindings/HTMLHeadElementWrapper.h>";
     out() << "#include <LibWeb/Bindings/HTMLImageElementWrapper.h>";
     out() << "#include <LibWeb/Bindings/HTMLImageElementWrapper.h>";
     out() << "#include <LibWeb/Bindings/ImageDataWrapper.h>";
     out() << "#include <LibWeb/Bindings/ImageDataWrapper.h>";
+    out() << "#include <LibWeb/Bindings/TextWrapper.h>";
     out() << "#include <LibWeb/Bindings/CanvasRenderingContext2DWrapper.h>";
     out() << "#include <LibWeb/Bindings/CanvasRenderingContext2DWrapper.h>";
 
 
     // FIXME: This is a total hack until we can figure out the namespace for a given type somehow.
     // FIXME: This is a total hack until we can figure out the namespace for a given type somehow.
@@ -681,7 +685,11 @@ void generate_implementation(const IDL::Interface& interface)
         out() << "        return {};";
         out() << "        return {};";
         if (function.length() > 0) {
         if (function.length() > 0) {
             out() << "    if (interpreter.argument_count() < " << function.length() << ")";
             out() << "    if (interpreter.argument_count() < " << function.length() << ")";
-            out() << "        return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountMany, \"" << function.name << "\", \"" << function.length() << "\");";
+
+            if (function.length() == 1)
+                out() << "        return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountOne, \"" << function.name << "\");";
+            else
+                out() << "        return interpreter.throw_exception<JS::TypeError>(JS::ErrorType::BadArgCountMany, \"" << function.name << "\", \"" << function.length() << "\");";
         }
         }
 
 
         StringBuilder arguments_builder;
         StringBuilder arguments_builder;

+ 2 - 0
Libraries/LibWeb/DOM/Comment.h

@@ -33,6 +33,8 @@ namespace Web::DOM {
 
 
 class Comment final : public CharacterData {
 class Comment final : public CharacterData {
 public:
 public:
+    using WrapperType = Bindings::CommentWrapper;
+
     explicit Comment(Document&, const String&);
     explicit Comment(Document&, const String&);
     virtual ~Comment() override;
     virtual ~Comment() override;
 
 

+ 3 - 0
Libraries/LibWeb/DOM/Comment.idl

@@ -0,0 +1,3 @@
+interface Comment : CharacterData {
+
+}

+ 44 - 44
Libraries/LibWeb/DOM/Document.cpp

@@ -32,21 +32,20 @@
 #include <LibJS/Interpreter.h>
 #include <LibJS/Interpreter.h>
 #include <LibJS/Parser.h>
 #include <LibJS/Parser.h>
 #include <LibJS/Runtime/Function.h>
 #include <LibJS/Runtime/Function.h>
-#include <LibJS/Runtime/GlobalObject.h>
 #include <LibWeb/Bindings/DocumentWrapper.h>
 #include <LibWeb/Bindings/DocumentWrapper.h>
 #include <LibWeb/Bindings/WindowObject.h>
 #include <LibWeb/Bindings/WindowObject.h>
-#include <LibWeb/CSS/Parser/CSSParser.h>
-#include <LibWeb/CSS/SelectorEngine.h>
 #include <LibWeb/CSS/StyleResolver.h>
 #include <LibWeb/CSS/StyleResolver.h>
+#include <LibWeb/DOM/Comment.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Document.h>
+#include <LibWeb/DOM/DocumentFragment.h>
 #include <LibWeb/DOM/DocumentType.h>
 #include <LibWeb/DOM/DocumentType.h>
 #include <LibWeb/DOM/Element.h>
 #include <LibWeb/DOM/Element.h>
 #include <LibWeb/DOM/ElementFactory.h>
 #include <LibWeb/DOM/ElementFactory.h>
 #include <LibWeb/DOM/Text.h>
 #include <LibWeb/DOM/Text.h>
 #include <LibWeb/DOM/Window.h>
 #include <LibWeb/DOM/Window.h>
-#include <LibWeb/Dump.h>
 #include <LibWeb/HTML/AttributeNames.h>
 #include <LibWeb/HTML/AttributeNames.h>
 #include <LibWeb/HTML/HTMLBodyElement.h>
 #include <LibWeb/HTML/HTMLBodyElement.h>
+#include <LibWeb/HTML/HTMLFrameSetElement.h>
 #include <LibWeb/HTML/HTMLHeadElement.h>
 #include <LibWeb/HTML/HTMLHeadElement.h>
 #include <LibWeb/HTML/HTMLHtmlElement.h>
 #include <LibWeb/HTML/HTMLHtmlElement.h>
 #include <LibWeb/HTML/HTMLScriptElement.h>
 #include <LibWeb/HTML/HTMLScriptElement.h>
@@ -149,7 +148,37 @@ const HTML::HTMLElement* Document::body() const
     auto* html = html_element();
     auto* html = html_element();
     if (!html)
     if (!html)
         return nullptr;
         return nullptr;
-    return html->first_child_of_type<HTML::HTMLBodyElement>();
+    auto* first_body = html->first_child_of_type<HTML::HTMLBodyElement>();
+    if (first_body)
+        return first_body;
+    auto* first_frameset = html->first_child_of_type<HTML::HTMLFrameSetElement>();
+    if (first_frameset)
+        return first_frameset;
+    return nullptr;
+}
+
+void Document::set_body(HTML::HTMLElement& new_body)
+{
+    if (!is<HTML::HTMLBodyElement>(new_body) && !is<HTML::HTMLFrameSetElement>(new_body)) {
+        // FIXME: throw a "HierarchyRequestError" DOMException.
+        return;
+    }
+
+    auto* existing_body = body();
+    if (existing_body) {
+        TODO();
+        return;
+    }
+
+    auto* html = document_element();
+    if (!html) {
+        // FIXME: throw a "HierarchyRequestError" DOMException.
+        return;
+    }
+
+    // FIXME: Implement this once there's a non-const first_child_of_type:
+    //        "Otherwise, the body element is null, but there's a document element. Append the new value to the document element."
+    TODO();
 }
 }
 
 
 String Document::title() const
 String Document::title() const
@@ -351,45 +380,6 @@ NonnullRefPtrVector<Element> Document::get_elements_by_tag_name(const FlyString&
     return elements;
     return elements;
 }
 }
 
 
-RefPtr<Element> Document::query_selector(const StringView& selector_text)
-{
-    auto selector = parse_selector(CSS::ParsingContext(*this), selector_text);
-    if (!selector.has_value())
-        return {};
-
-    dump_selector(selector.value());
-
-    RefPtr<Element> result;
-    for_each_in_subtree_of_type<Element>([&](auto& element) {
-        if (SelectorEngine::matches(selector.value(), element)) {
-            result = element;
-            return IterationDecision::Break;
-        }
-        return IterationDecision::Continue;
-    });
-
-    return result;
-}
-
-NonnullRefPtrVector<Element> Document::query_selector_all(const StringView& selector_text)
-{
-    auto selector = parse_selector(CSS::ParsingContext(*this), selector_text);
-    if (!selector.has_value())
-        return {};
-
-    dump_selector(selector.value());
-
-    NonnullRefPtrVector<Element> elements;
-    for_each_in_subtree_of_type<Element>([&](auto& element) {
-        if (SelectorEngine::matches(selector.value(), element)) {
-            elements.append(element);
-        }
-        return IterationDecision::Continue;
-    });
-
-    return elements;
-}
-
 Color Document::link_color() const
 Color Document::link_color() const
 {
 {
     if (m_link_color.has_value())
     if (m_link_color.has_value())
@@ -444,11 +434,21 @@ NonnullRefPtr<Element> Document::create_element(const String& tag_name)
     return DOM::create_element(*this, tag_name);
     return DOM::create_element(*this, tag_name);
 }
 }
 
 
+NonnullRefPtr<DocumentFragment> Document::create_document_fragment()
+{
+    return adopt(*new DocumentFragment(*this));
+}
+
 NonnullRefPtr<Text> Document::create_text_node(const String& data)
 NonnullRefPtr<Text> Document::create_text_node(const String& data)
 {
 {
     return adopt(*new Text(*this, data));
     return adopt(*new Text(*this, data));
 }
 }
 
 
+NonnullRefPtr<Comment> Document::create_comment(const String& data)
+{
+    return adopt(*new Comment(*this, data));
+}
+
 void Document::set_pending_parsing_blocking_script(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement* script)
 void Document::set_pending_parsing_blocking_script(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement* script)
 {
 {
     m_pending_parsing_blocking_script = script;
     m_pending_parsing_blocking_script = script;

+ 3 - 2
Libraries/LibWeb/DOM/Document.h

@@ -89,6 +89,7 @@ public:
     const HTML::HTMLHtmlElement* html_element() const;
     const HTML::HTMLHtmlElement* html_element() const;
     const HTML::HTMLHeadElement* head() const;
     const HTML::HTMLHeadElement* head() const;
     const HTML::HTMLElement* body() const;
     const HTML::HTMLElement* body() const;
+    void set_body(HTML::HTMLElement& new_body);
 
 
     String title() const;
     String title() const;
 
 
@@ -126,8 +127,6 @@ public:
 
 
     Vector<const Element*> get_elements_by_name(const String&) const;
     Vector<const Element*> get_elements_by_name(const String&) const;
     NonnullRefPtrVector<Element> get_elements_by_tag_name(const FlyString&) const;
     NonnullRefPtrVector<Element> get_elements_by_tag_name(const FlyString&) const;
-    RefPtr<Element> query_selector(const StringView&);
-    NonnullRefPtrVector<Element> query_selector_all(const StringView&);
 
 
     const String& source() const { return m_source; }
     const String& source() const { return m_source; }
     void set_source(const String& source) { m_source = source; }
     void set_source(const String& source) { m_source = source; }
@@ -137,7 +136,9 @@ public:
     JS::Value run_javascript(const StringView&);
     JS::Value run_javascript(const StringView&);
 
 
     NonnullRefPtr<Element> create_element(const String& tag_name);
     NonnullRefPtr<Element> create_element(const String& tag_name);
+    NonnullRefPtr<DocumentFragment> create_document_fragment();
     NonnullRefPtr<Text> create_text_node(const String& data);
     NonnullRefPtr<Text> create_text_node(const String& data);
+    NonnullRefPtr<Comment> create_comment(const String& data);
 
 
     void set_pending_parsing_blocking_script(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement*);
     void set_pending_parsing_blocking_script(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement*);
     HTML::HTMLScriptElement* pending_parsing_blocking_script() { return m_pending_parsing_blocking_script; }
     HTML::HTMLScriptElement* pending_parsing_blocking_script() { return m_pending_parsing_blocking_script; }

+ 6 - 1
Libraries/LibWeb/DOM/Document.idl

@@ -4,12 +4,17 @@ interface Document : Node {
     Element? querySelector(DOMString selectors);
     Element? querySelector(DOMString selectors);
     ArrayFromVector getElementsByTagName(DOMString tagName);
     ArrayFromVector getElementsByTagName(DOMString tagName);
     ArrayFromVector querySelectorAll(DOMString selectors);
     ArrayFromVector querySelectorAll(DOMString selectors);
+
     Element createElement(DOMString tagName);
     Element createElement(DOMString tagName);
+    DocumentFragment createDocumentFragment();
+    Text createTextNode(DOMString data);
+    Comment createComment(DOMString data);
 
 
     readonly attribute DOMString compatMode;
     readonly attribute DOMString compatMode;
     readonly attribute DocumentType? doctype;
     readonly attribute DocumentType? doctype;
 
 
     readonly attribute Element? documentElement;
     readonly attribute Element? documentElement;
-    readonly attribute HTMLElement? body;
+    attribute HTMLElement? body;
+    readonly attribute HTMLHeadElement? head;
 
 
 }
 }

+ 40 - 0
Libraries/LibWeb/DOM/DocumentFragment.cpp

@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020, Luke Wilde <luke.wilde@live.co.uk>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <LibWeb/DOM/DocumentFragment.h>
+
+namespace Web::DOM {
+
+DocumentFragment::DocumentFragment(Document& document)
+    : ParentNode(document, NodeType::DOCUMENT_FRAGMENT_NODE)
+{
+}
+
+DocumentFragment::~DocumentFragment()
+{
+}
+
+}

+ 2 - 4
Libraries/LibWeb/DOM/DocumentFragment.h

@@ -36,10 +36,8 @@ class DocumentFragment
     : public ParentNode
     : public ParentNode
     , public NonElementParentNode<DocumentFragment> {
     , public NonElementParentNode<DocumentFragment> {
 public:
 public:
-    DocumentFragment(Document& document)
-        : ParentNode(document, NodeType::DOCUMENT_FRAGMENT_NODE)
-    {
-    }
+    DocumentFragment(Document& document);
+    virtual ~DocumentFragment() override;
 
 
     virtual FlyString node_name() const override { return "#document-fragment"; }
     virtual FlyString node_name() const override { return "#document-fragment"; }
 };
 };

+ 7 - 0
Libraries/LibWeb/DOM/DocumentFragment.idl

@@ -0,0 +1,7 @@
+interface DocumentFragment : Node {
+
+    Element? getElementById(DOMString id);
+    Element? querySelector(DOMString selectors);
+    ArrayFromVector querySelectorAll(DOMString selectors);
+
+}

+ 3 - 0
Libraries/LibWeb/DOM/Element.idl

@@ -5,6 +5,9 @@ interface Element : Node {
     DOMString? getAttribute(DOMString qualifiedName);
     DOMString? getAttribute(DOMString qualifiedName);
     void setAttribute(DOMString qualifiedName, DOMString value);
     void setAttribute(DOMString qualifiedName, DOMString value);
 
 
+    Element? querySelector(DOMString selectors);
+    ArrayFromVector querySelectorAll(DOMString selectors);
+
     attribute DOMString innerHTML;
     attribute DOMString innerHTML;
     [Reflect] attribute DOMString id;
     [Reflect] attribute DOMString id;
     [Reflect=class] attribute DOMString className;
     [Reflect=class] attribute DOMString className;

+ 80 - 0
Libraries/LibWeb/DOM/ParentNode.cpp

@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <LibWeb/CSS/Parser/CSSParser.h>
+#include <LibWeb/CSS/SelectorEngine.h>
+#include <LibWeb/DOM/ParentNode.h>
+#include <LibWeb/Dump.h>
+
+namespace Web::DOM {
+
+void ParentNode::remove_all_children()
+{
+    while (RefPtr<Node> child = first_child()) {
+        remove_child(*child);
+    }
+}
+
+RefPtr<Element> ParentNode::query_selector(const StringView& selector_text)
+{
+    auto selector = parse_selector(CSS::ParsingContext(*this), selector_text);
+    if (!selector.has_value())
+        return {};
+
+    dump_selector(selector.value());
+
+    RefPtr<Element> result;
+    for_each_in_subtree_of_type<Element>([&](auto& element) {
+        if (SelectorEngine::matches(selector.value(), element)) {
+            result = element;
+            return IterationDecision::Break;
+        }
+        return IterationDecision::Continue;
+    });
+
+    return result;
+}
+
+NonnullRefPtrVector<Element> ParentNode::query_selector_all(const StringView& selector_text)
+{
+    auto selector = parse_selector(CSS::ParsingContext(*this), selector_text);
+    if (!selector.has_value())
+        return {};
+
+    dump_selector(selector.value());
+
+    NonnullRefPtrVector<Element> elements;
+    for_each_in_subtree_of_type<Element>([&](auto& element) {
+        if (SelectorEngine::matches(selector.value(), element)) {
+            elements.append(element);
+        }
+        return IterationDecision::Continue;
+    });
+
+    return elements;
+}
+
+}

+ 4 - 1
Libraries/LibWeb/DOM/ParentNode.h

@@ -35,8 +35,11 @@ public:
     template<typename F> void for_each_child(F) const;
     template<typename F> void for_each_child(F) const;
     template<typename F> void for_each_child(F);
     template<typename F> void for_each_child(F);
 
 
+    RefPtr<Element> query_selector(const StringView&);
+    NonnullRefPtrVector<Element> query_selector_all(const StringView&);
+
 protected:
 protected:
-    explicit ParentNode(Document& document, NodeType type)
+    ParentNode(Document& document, NodeType type)
         : Node(document, type)
         : Node(document, type)
     {
     {
     }
     }

+ 4 - 0
Libraries/LibWeb/Forward.h

@@ -35,7 +35,10 @@ class StyleSheet;
 }
 }
 
 
 namespace Web::DOM {
 namespace Web::DOM {
+class CharacterData;
+class Comment;
 class Document;
 class Document;
+class DocumentFragment;
 class DocumentType;
 class DocumentType;
 class Element;
 class Element;
 class Event;
 class Event;
@@ -155,6 +158,7 @@ namespace Web::Bindings {
 
 
 class CanvasRenderingContext2DWrapper;
 class CanvasRenderingContext2DWrapper;
 class CharacterDataWrapper;
 class CharacterDataWrapper;
+class CommentWrapper;
 class DocumentTypeWrapper;
 class DocumentTypeWrapper;
 class DocumentWrapper;
 class DocumentWrapper;
 class ElementWrapper;
 class ElementWrapper;