diff options
author | Luke Wilde <lukew@serenityos.org> | 2022-01-29 20:23:48 +0000 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-01-31 15:25:36 +0100 |
commit | d5c96c3ccf6cc7bacf865d158ab23c040704f50e (patch) | |
tree | 95ae6afe87e837f479793a51862dbce6e364a9a0 /Userland/Libraries | |
parent | d7998c5dbdbe98000554a432f47565d41f8b095c (diff) | |
download | serenity-d5c96c3ccf6cc7bacf865d158ab23c040704f50e.zip |
LibWeb: Implement ParentNode.prepend
`convert_nodes_to_single_node` is inside its own file so ChildNode can
include and use it without having to include other headers such as
DOM/Node.h. This is to prevent circular includes.
Diffstat (limited to 'Userland/Libraries')
-rw-r--r-- | Userland/Libraries/LibWeb/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/ChildNode.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Document.idl | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/DocumentFragment.idl | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Element.idl | 4 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/NodeOperations.cpp | 46 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/NodeOperations.h | 16 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/ParentNode.cpp | 19 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/ParentNode.h | 2 |
9 files changed, 92 insertions, 2 deletions
diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 928734fbbf..3204cc484f 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -80,6 +80,7 @@ set(SOURCES DOM/LiveNodeList.cpp DOM/NamedNodeMap.cpp DOM/Node.cpp + DOM/NodeOperations.cpp DOM/ParentNode.cpp DOM/Position.cpp DOM/ProcessingInstruction.cpp diff --git a/Userland/Libraries/LibWeb/DOM/ChildNode.h b/Userland/Libraries/LibWeb/DOM/ChildNode.h index d038406b44..559ff33fe3 100644 --- a/Userland/Libraries/LibWeb/DOM/ChildNode.h +++ b/Userland/Libraries/LibWeb/DOM/ChildNode.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Luke Wilde <lukew@serenityos.org> + * Copyright (c) 2021-2022, Luke Wilde <lukew@serenityos.org> * * SPDX-License-Identifier: BSD-2-Clause */ diff --git a/Userland/Libraries/LibWeb/DOM/Document.idl b/Userland/Libraries/LibWeb/DOM/Document.idl index 6e6c1e80d2..c5229063f0 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.idl +++ b/Userland/Libraries/LibWeb/DOM/Document.idl @@ -65,6 +65,8 @@ interface Document : Node { readonly attribute Element? lastElementChild; readonly attribute unsigned long childElementCount; + [CEReactions, Unscopable] undefined prepend((Node or DOMString)... nodes); + Element? querySelector(DOMString selectors); [NewObject] NodeList querySelectorAll(DOMString selectors); diff --git a/Userland/Libraries/LibWeb/DOM/DocumentFragment.idl b/Userland/Libraries/LibWeb/DOM/DocumentFragment.idl index ac2d2b97c0..938e05e9e9 100644 --- a/Userland/Libraries/LibWeb/DOM/DocumentFragment.idl +++ b/Userland/Libraries/LibWeb/DOM/DocumentFragment.idl @@ -9,6 +9,8 @@ interface DocumentFragment : Node { readonly attribute Element? lastElementChild; readonly attribute unsigned long childElementCount; + [CEReactions, Unscopable] undefined prepend((Node or DOMString)... nodes); + Element? querySelector(DOMString selectors); [NewObject] NodeList querySelectorAll(DOMString selectors); diff --git a/Userland/Libraries/LibWeb/DOM/Element.idl b/Userland/Libraries/LibWeb/DOM/Element.idl index bb4aa457c9..c796cdd9c8 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.idl +++ b/Userland/Libraries/LibWeb/DOM/Element.idl @@ -33,11 +33,13 @@ interface Element : Node { [ImplementedAs=style_for_bindings] readonly attribute CSSStyleDeclaration style; - // FIXME: These should all come from a ParentNode mixin + // FIXME: These should all come from a ParentNode mixin (up to and including children) readonly attribute Element? firstElementChild; readonly attribute Element? lastElementChild; readonly attribute unsigned long childElementCount; + [CEReactions, Unscopable] undefined prepend((Node or DOMString)... nodes); + Element? querySelector(DOMString selectors); [NewObject] NodeList querySelectorAll(DOMString selectors); diff --git a/Userland/Libraries/LibWeb/DOM/NodeOperations.cpp b/Userland/Libraries/LibWeb/DOM/NodeOperations.cpp new file mode 100644 index 0000000000..8e8685ad18 --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/NodeOperations.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022, Luke Wilde <lukew@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/String.h> +#include <AK/Vector.h> +#include <LibWeb/DOM/DocumentFragment.h> +#include <LibWeb/DOM/NodeOperations.h> +#include <LibWeb/DOM/Text.h> + +namespace Web::DOM { + +// https://dom.spec.whatwg.org/#converting-nodes-into-a-node +ExceptionOr<NonnullRefPtr<Node>> convert_nodes_to_single_node(Vector<Variant<NonnullRefPtr<Node>, String>> const& nodes, DOM::Document& document) +{ + // 1. Let node be null. + // 2. Replace each string in nodes with a new Text node whose data is the string and node document is document. + // 3. If nodes contains one node, then set node to nodes[0]. + // 4. Otherwise, set node to a new DocumentFragment node whose node document is document, and then append each node in nodes, if any, to it. + // 5. Return node. + + auto potentially_convert_string_to_text_node = [&document](Variant<NonnullRefPtr<Node>, String> const& node) -> NonnullRefPtr<Node> { + if (node.has<NonnullRefPtr<Node>>()) + return node.get<NonnullRefPtr<Node>>(); + + return adopt_ref(*new Text(document, node.get<String>())); + }; + + if (nodes.size() == 1) + return potentially_convert_string_to_text_node(nodes.first()); + + // This is NNRP<Node> instead of NNRP<DocumentFragment> to be compatible with the return type. + NonnullRefPtr<Node> document_fragment = adopt_ref(*new DocumentFragment(document)); + for (auto& unconverted_node : nodes) { + auto node = potentially_convert_string_to_text_node(unconverted_node); + auto result = document_fragment->append_child(node); + if (result.is_exception()) + return result.exception(); + } + + return document_fragment; +} + +} diff --git a/Userland/Libraries/LibWeb/DOM/NodeOperations.h b/Userland/Libraries/LibWeb/DOM/NodeOperations.h new file mode 100644 index 0000000000..251a320104 --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/NodeOperations.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2022, Luke Wilde <lukew@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/NonnullRefPtr.h> +#include <LibWeb/Forward.h> + +namespace Web::DOM { + +ExceptionOr<NonnullRefPtr<Node>> convert_nodes_to_single_node(Vector<Variant<NonnullRefPtr<Node>, String>> const& nodes, DOM::Document& document); + +} diff --git a/Userland/Libraries/LibWeb/DOM/ParentNode.cpp b/Userland/Libraries/LibWeb/DOM/ParentNode.cpp index eee4fc3100..24d8675ea9 100644 --- a/Userland/Libraries/LibWeb/DOM/ParentNode.cpp +++ b/Userland/Libraries/LibWeb/DOM/ParentNode.cpp @@ -7,6 +7,7 @@ #include <LibWeb/CSS/Parser/Parser.h> #include <LibWeb/CSS/SelectorEngine.h> #include <LibWeb/DOM/HTMLCollection.h> +#include <LibWeb/DOM/NodeOperations.h> #include <LibWeb/DOM/ParentNode.h> #include <LibWeb/DOM/StaticNodeList.h> #include <LibWeb/Dump.h> @@ -155,4 +156,22 @@ NonnullRefPtr<HTMLCollection> ParentNode::get_elements_by_tag_name_ns(FlyString }); } +// https://dom.spec.whatwg.org/#dom-parentnode-prepend +ExceptionOr<void> ParentNode::prepend(Vector<Variant<NonnullRefPtr<Node>, String>> const& nodes) +{ + // 1. Let node be the result of converting nodes into a node given nodes and this’s node document. + auto node_or_exception = convert_nodes_to_single_node(nodes, document()); + if (node_or_exception.is_exception()) + return node_or_exception.exception(); + + auto node = node_or_exception.release_value(); + + // 2. Pre-insert node into this before this’s first child. + auto result = pre_insert(node, first_child()); + if (result.is_exception()) + return result.exception(); + + return {}; +} + } diff --git a/Userland/Libraries/LibWeb/DOM/ParentNode.h b/Userland/Libraries/LibWeb/DOM/ParentNode.h index fc7f962847..feaa1a73c8 100644 --- a/Userland/Libraries/LibWeb/DOM/ParentNode.h +++ b/Userland/Libraries/LibWeb/DOM/ParentNode.h @@ -30,6 +30,8 @@ public: NonnullRefPtr<HTMLCollection> get_elements_by_tag_name(FlyString const&); NonnullRefPtr<HTMLCollection> get_elements_by_tag_name_ns(FlyString const&, FlyString const&); + ExceptionOr<void> prepend(Vector<Variant<NonnullRefPtr<Node>, String>> const& nodes); + protected: ParentNode(Document& document, NodeType type) : Node(document, type) |