diff --git a/Libraries/LibWeb/Bindings/NodeWrapperFactory.cpp b/Libraries/LibWeb/Bindings/NodeWrapperFactory.cpp index 499c36177e..adebbc6515 100644 --- a/Libraries/LibWeb/Bindings/NodeWrapperFactory.cpp +++ b/Libraries/LibWeb/Bindings/NodeWrapperFactory.cpp @@ -26,8 +26,10 @@ */ #include -#include +#include #include +#include +#include #include #include #include @@ -315,6 +317,10 @@ NodeWrapper* wrap(JS::GlobalObject& global_object, DOM::Node& node) return static_cast(wrap_impl(global_object, downcast(node))); if (is(node)) return static_cast(wrap_impl(global_object, downcast(node))); + if (is(node)) + return static_cast(wrap_impl(global_object, downcast(node))); + if (is(node)) + return static_cast(wrap_impl(global_object, downcast(node))); if (is(node)) return static_cast(wrap_impl(global_object, downcast(node))); if (is(node)) diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 6417cbd94a..eadee3dd8e 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -27,6 +27,7 @@ set(SOURCES DOM/CharacterData.idl DOM/Comment.cpp DOM/Document.cpp + DOM/DocumentFragment.cpp DOM/DocumentType.cpp DOM/Element.cpp DOM/ElementFactory.cpp @@ -210,7 +211,9 @@ function(libweb_js_wrapper class) endfunction() libweb_js_wrapper(DOM/CharacterData) +libweb_js_wrapper(DOM/Comment) libweb_js_wrapper(DOM/Document) +libweb_js_wrapper(DOM/DocumentFragment) libweb_js_wrapper(DOM/DocumentType) libweb_js_wrapper(DOM/Element) libweb_js_wrapper(DOM/Event) diff --git a/Libraries/LibWeb/CSS/Parser/CSSParser.cpp b/Libraries/LibWeb/CSS/Parser/CSSParser.cpp index 517cc556b1..0a9dd97adc 100644 --- a/Libraries/LibWeb/CSS/Parser/CSSParser.cpp +++ b/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 { return m_document ? m_document->in_quirks_mode() : false; diff --git a/Libraries/LibWeb/CSS/Parser/CSSParser.h b/Libraries/LibWeb/CSS/Parser/CSSParser.h index 42dd29f2b3..c71331558d 100644 --- a/Libraries/LibWeb/CSS/Parser/CSSParser.h +++ b/Libraries/LibWeb/CSS/Parser/CSSParser.h @@ -34,6 +34,7 @@ class ParsingContext { public: ParsingContext(); explicit ParsingContext(const DOM::Document&); + explicit ParsingContext(const DOM::ParentNode&); bool in_quirks_mode() const; diff --git a/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp b/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp index 8472ab3dd7..4150cf69d5 100644 --- a/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp +++ b/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp @@ -486,11 +486,15 @@ void generate_implementation(const IDL::Interface& interface) out() << "#include "; out() << "#include "; out() << "#include "; + out() << "#include "; out() << "#include "; + out() << "#include "; out() << "#include "; out() << "#include "; + out() << "#include "; out() << "#include "; out() << "#include "; + out() << "#include "; out() << "#include "; // 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 {};"; if (function.length() > 0) { out() << " if (interpreter.argument_count() < " << function.length() << ")"; - out() << " return interpreter.throw_exception(JS::ErrorType::BadArgCountMany, \"" << function.name << "\", \"" << function.length() << "\");"; + + if (function.length() == 1) + out() << " return interpreter.throw_exception(JS::ErrorType::BadArgCountOne, \"" << function.name << "\");"; + else + out() << " return interpreter.throw_exception(JS::ErrorType::BadArgCountMany, \"" << function.name << "\", \"" << function.length() << "\");"; } StringBuilder arguments_builder; diff --git a/Libraries/LibWeb/DOM/Comment.h b/Libraries/LibWeb/DOM/Comment.h index f0cdc7907a..855c710ded 100644 --- a/Libraries/LibWeb/DOM/Comment.h +++ b/Libraries/LibWeb/DOM/Comment.h @@ -33,6 +33,8 @@ namespace Web::DOM { class Comment final : public CharacterData { public: + using WrapperType = Bindings::CommentWrapper; + explicit Comment(Document&, const String&); virtual ~Comment() override; diff --git a/Libraries/LibWeb/DOM/Comment.idl b/Libraries/LibWeb/DOM/Comment.idl new file mode 100644 index 0000000000..a8c42f6a5e --- /dev/null +++ b/Libraries/LibWeb/DOM/Comment.idl @@ -0,0 +1,3 @@ +interface Comment : CharacterData { + +} diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index ebd6466456..61ba9f5b50 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -32,21 +32,20 @@ #include #include #include -#include #include #include -#include -#include #include +#include #include +#include #include #include #include #include #include -#include #include #include +#include #include #include #include @@ -149,7 +148,37 @@ const HTML::HTMLElement* Document::body() const auto* html = html_element(); if (!html) return nullptr; - return html->first_child_of_type(); + auto* first_body = html->first_child_of_type(); + if (first_body) + return first_body; + auto* first_frameset = html->first_child_of_type(); + if (first_frameset) + return first_frameset; + return nullptr; +} + +void Document::set_body(HTML::HTMLElement& new_body) +{ + if (!is(new_body) && !is(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 @@ -351,45 +380,6 @@ NonnullRefPtrVector Document::get_elements_by_tag_name(const FlyString& return elements; } -RefPtr 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 result; - for_each_in_subtree_of_type([&](auto& element) { - if (SelectorEngine::matches(selector.value(), element)) { - result = element; - return IterationDecision::Break; - } - return IterationDecision::Continue; - }); - - return result; -} - -NonnullRefPtrVector 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 elements; - for_each_in_subtree_of_type([&](auto& element) { - if (SelectorEngine::matches(selector.value(), element)) { - elements.append(element); - } - return IterationDecision::Continue; - }); - - return elements; -} - Color Document::link_color() const { if (m_link_color.has_value()) @@ -444,11 +434,21 @@ NonnullRefPtr Document::create_element(const String& tag_name) return DOM::create_element(*this, tag_name); } +NonnullRefPtr Document::create_document_fragment() +{ + return adopt(*new DocumentFragment(*this)); +} + NonnullRefPtr Document::create_text_node(const String& data) { return adopt(*new Text(*this, data)); } +NonnullRefPtr Document::create_comment(const String& data) +{ + return adopt(*new Comment(*this, data)); +} + void Document::set_pending_parsing_blocking_script(Badge, HTML::HTMLScriptElement* script) { m_pending_parsing_blocking_script = script; diff --git a/Libraries/LibWeb/DOM/Document.h b/Libraries/LibWeb/DOM/Document.h index fc6910c490..03ed3108b0 100644 --- a/Libraries/LibWeb/DOM/Document.h +++ b/Libraries/LibWeb/DOM/Document.h @@ -89,6 +89,7 @@ public: const HTML::HTMLHtmlElement* html_element() const; const HTML::HTMLHeadElement* head() const; const HTML::HTMLElement* body() const; + void set_body(HTML::HTMLElement& new_body); String title() const; @@ -126,8 +127,6 @@ public: Vector get_elements_by_name(const String&) const; NonnullRefPtrVector get_elements_by_tag_name(const FlyString&) const; - RefPtr query_selector(const StringView&); - NonnullRefPtrVector query_selector_all(const StringView&); const String& source() const { return m_source; } void set_source(const String& source) { m_source = source; } @@ -137,7 +136,9 @@ public: JS::Value run_javascript(const StringView&); NonnullRefPtr create_element(const String& tag_name); + NonnullRefPtr create_document_fragment(); NonnullRefPtr create_text_node(const String& data); + NonnullRefPtr create_comment(const String& data); void set_pending_parsing_blocking_script(Badge, HTML::HTMLScriptElement*); HTML::HTMLScriptElement* pending_parsing_blocking_script() { return m_pending_parsing_blocking_script; } diff --git a/Libraries/LibWeb/DOM/Document.idl b/Libraries/LibWeb/DOM/Document.idl index f2cbf8eafa..48c2fd6765 100644 --- a/Libraries/LibWeb/DOM/Document.idl +++ b/Libraries/LibWeb/DOM/Document.idl @@ -4,12 +4,17 @@ interface Document : Node { Element? querySelector(DOMString selectors); ArrayFromVector getElementsByTagName(DOMString tagName); ArrayFromVector querySelectorAll(DOMString selectors); + Element createElement(DOMString tagName); + DocumentFragment createDocumentFragment(); + Text createTextNode(DOMString data); + Comment createComment(DOMString data); readonly attribute DOMString compatMode; readonly attribute DocumentType? doctype; readonly attribute Element? documentElement; - readonly attribute HTMLElement? body; + attribute HTMLElement? body; + readonly attribute HTMLHeadElement? head; } diff --git a/Libraries/LibWeb/DOM/DocumentFragment.cpp b/Libraries/LibWeb/DOM/DocumentFragment.cpp new file mode 100644 index 0000000000..92400feb70 --- /dev/null +++ b/Libraries/LibWeb/DOM/DocumentFragment.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020, Luke Wilde + * 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 + +namespace Web::DOM { + +DocumentFragment::DocumentFragment(Document& document) + : ParentNode(document, NodeType::DOCUMENT_FRAGMENT_NODE) +{ +} + +DocumentFragment::~DocumentFragment() +{ +} + +} diff --git a/Libraries/LibWeb/DOM/DocumentFragment.h b/Libraries/LibWeb/DOM/DocumentFragment.h index 9bc8f39d14..b969fbde4a 100644 --- a/Libraries/LibWeb/DOM/DocumentFragment.h +++ b/Libraries/LibWeb/DOM/DocumentFragment.h @@ -36,10 +36,8 @@ class DocumentFragment : public ParentNode , public NonElementParentNode { 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"; } }; diff --git a/Libraries/LibWeb/DOM/DocumentFragment.idl b/Libraries/LibWeb/DOM/DocumentFragment.idl new file mode 100644 index 0000000000..0b42cb9bfe --- /dev/null +++ b/Libraries/LibWeb/DOM/DocumentFragment.idl @@ -0,0 +1,7 @@ +interface DocumentFragment : Node { + + Element? getElementById(DOMString id); + Element? querySelector(DOMString selectors); + ArrayFromVector querySelectorAll(DOMString selectors); + +} diff --git a/Libraries/LibWeb/DOM/Element.idl b/Libraries/LibWeb/DOM/Element.idl index f586296c5d..082d0a951a 100644 --- a/Libraries/LibWeb/DOM/Element.idl +++ b/Libraries/LibWeb/DOM/Element.idl @@ -5,6 +5,9 @@ interface Element : Node { DOMString? getAttribute(DOMString qualifiedName); void setAttribute(DOMString qualifiedName, DOMString value); + Element? querySelector(DOMString selectors); + ArrayFromVector querySelectorAll(DOMString selectors); + attribute DOMString innerHTML; [Reflect] attribute DOMString id; [Reflect=class] attribute DOMString className; diff --git a/Libraries/LibWeb/DOM/ParentNode.cpp b/Libraries/LibWeb/DOM/ParentNode.cpp new file mode 100644 index 0000000000..31a84b9017 --- /dev/null +++ b/Libraries/LibWeb/DOM/ParentNode.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * 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 +#include +#include +#include + +namespace Web::DOM { + +void ParentNode::remove_all_children() +{ + while (RefPtr child = first_child()) { + remove_child(*child); + } +} + +RefPtr 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 result; + for_each_in_subtree_of_type([&](auto& element) { + if (SelectorEngine::matches(selector.value(), element)) { + result = element; + return IterationDecision::Break; + } + return IterationDecision::Continue; + }); + + return result; +} + +NonnullRefPtrVector 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 elements; + for_each_in_subtree_of_type([&](auto& element) { + if (SelectorEngine::matches(selector.value(), element)) { + elements.append(element); + } + return IterationDecision::Continue; + }); + + return elements; +} + +} diff --git a/Libraries/LibWeb/DOM/ParentNode.h b/Libraries/LibWeb/DOM/ParentNode.h index 16b911fa80..23f0999795 100644 --- a/Libraries/LibWeb/DOM/ParentNode.h +++ b/Libraries/LibWeb/DOM/ParentNode.h @@ -35,8 +35,11 @@ public: template void for_each_child(F) const; template void for_each_child(F); + RefPtr query_selector(const StringView&); + NonnullRefPtrVector query_selector_all(const StringView&); + protected: - explicit ParentNode(Document& document, NodeType type) + ParentNode(Document& document, NodeType type) : Node(document, type) { } diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index ee53b36647..f553a823d6 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -35,7 +35,10 @@ class StyleSheet; } namespace Web::DOM { +class CharacterData; +class Comment; class Document; +class DocumentFragment; class DocumentType; class Element; class Event; @@ -155,6 +158,7 @@ namespace Web::Bindings { class CanvasRenderingContext2DWrapper; class CharacterDataWrapper; +class CommentWrapper; class DocumentTypeWrapper; class DocumentWrapper; class ElementWrapper;