diff options
author | Luke <luke.wilde@live.co.uk> | 2021-05-07 00:52:23 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-05-07 08:53:37 +0200 |
commit | 46f2c278b02adc99833c089f0d639fcbe8a50bc4 (patch) | |
tree | 60e858f39cda9b6353950db20135f13ea95818dc /Userland/Libraries/LibWeb | |
parent | 228c1f496853da8869a20c9e387cc5ed65bb2be1 (diff) | |
download | serenity-46f2c278b02adc99833c089f0d639fcbe8a50bc4.zip |
LibWeb: Implement Node.replaceChild
The `if (child->parent())` check seems to be redundant, but I'm keeping
it just to match the spec.
Diffstat (limited to 'Userland/Libraries/LibWeb')
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Node.cpp | 59 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Node.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Node.idl | 1 |
3 files changed, 62 insertions, 0 deletions
diff --git a/Userland/Libraries/LibWeb/DOM/Node.cpp b/Userland/Libraries/LibWeb/DOM/Node.cpp index a7484bcb84..e84bca283e 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.cpp +++ b/Userland/Libraries/LibWeb/DOM/Node.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> * Copyright (c) 2021, Linus Groh <linusg@serenityos.org> + * Copyright (c) 2021, Luke Wilde <lukew@serenityos.org> * * SPDX-License-Identifier: BSD-2-Clause */ @@ -345,6 +346,64 @@ void Node::remove(bool suppress_observers) parent->children_changed(); } +// https://dom.spec.whatwg.org/#concept-node-replace +ExceptionOr<NonnullRefPtr<Node>> Node::replace_child(NonnullRefPtr<Node> node, NonnullRefPtr<Node> child) +{ + // NOTE: This differs slightly from ensure_pre_insertion_validity. + if (!is<Document>(this) && !is<DocumentFragment>(this) && !is<Element>(this)) + return DOM::HierarchyRequestError::create("Can only insert into a document, document fragment or element"); + + if (node->is_host_including_inclusive_ancestor_of(*this)) + return DOM::HierarchyRequestError::create("New node is an ancestor of this node"); + + if (child->parent() != this) + return DOM::NotFoundError::create("This node is not the parent of the given child"); + + // FIXME: All the following "Invalid node type for insertion" messages could be more descriptive. + + if (!is<DocumentFragment>(*node) && !is<DocumentType>(*node) && !is<Element>(*node) && !is<Text>(*node) && !is<Comment>(*node) && !is<ProcessingInstruction>(*node)) + return DOM::HierarchyRequestError::create("Invalid node type for insertion"); + + if ((is<Text>(*node) && is<Document>(this)) || (is<DocumentType>(*node) && !is<Document>(this))) + return DOM::HierarchyRequestError::create("Invalid node type for insertion"); + + if (is<Document>(this)) { + if (is<DocumentFragment>(*node)) { + auto node_element_child_count = downcast<DocumentFragment>(*node).child_element_count(); + if ((node_element_child_count > 1 || node->has_child_of_type<Text>()) + || (node_element_child_count == 1 && (first_child_of_type<Element>() != child /* FIXME: or a doctype is following child. */))) { + return DOM::HierarchyRequestError::create("Invalid node type for insertion"); + } + } else if (is<Element>(*node)) { + if (first_child_of_type<Element>() != child /* FIXME: or a doctype is following child. */) + return DOM::HierarchyRequestError::create("Invalid node type for insertion"); + } else if (is<DocumentType>(*node)) { + if (first_child_of_type<DocumentType>() != node /* FIXME: or an element is preceding child */) + return DOM::HierarchyRequestError::create("Invalid node type for insertion"); + } + } + + auto reference_child = child->next_sibling(); + if (reference_child == node) + reference_child = node->next_sibling(); + + // FIXME: Let previousSibling be child’s previous sibling. (Currently unused so not included) + // FIXME: Let removedNodes be the empty set. (Currently unused so not included) + + if (child->parent()) { + // FIXME: Set removedNodes to « child ». + child->remove(true); + } + + // FIXME: Let nodes be node’s children if node is a DocumentFragment node; otherwise « node ». (Currently unused so not included) + + insert_before(node, reference_child, true); + + // FIXME: Queue a tree mutation record for parent with nodes, removedNodes, previousSibling, and referenceChild. + + return child; +} + // https://dom.spec.whatwg.org/#concept-node-clone NonnullRefPtr<Node> Node::clone_node(Document* document, bool clone_children) const { diff --git a/Userland/Libraries/LibWeb/DOM/Node.h b/Userland/Libraries/LibWeb/DOM/Node.h index bd0a59c28f..4751a494f8 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.h +++ b/Userland/Libraries/LibWeb/DOM/Node.h @@ -82,6 +82,8 @@ public: void remove_all_children(bool suppress_observers = false); u16 compare_document_position(RefPtr<Node> other); + ExceptionOr<NonnullRefPtr<Node>> replace_child(NonnullRefPtr<Node> node, NonnullRefPtr<Node> child); + NonnullRefPtr<Node> clone_node(Document* document = nullptr, bool clone_children = false) const; ExceptionOr<NonnullRefPtr<Node>> clone_node_binding(bool deep) const; diff --git a/Userland/Libraries/LibWeb/DOM/Node.idl b/Userland/Libraries/LibWeb/DOM/Node.idl index 0c0b38cb01..00fb334369 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.idl +++ b/Userland/Libraries/LibWeb/DOM/Node.idl @@ -18,6 +18,7 @@ interface Node : EventTarget { Node appendChild(Node node); [ImplementedAs=pre_insert] Node insertBefore(Node node, Node? child); + Node replaceChild(Node node, Node child); [ImplementedAs=pre_remove] Node removeChild(Node child); [ImplementedAs=clone_node_binding] Node cloneNode(optional boolean deep = false); |