summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb
diff options
context:
space:
mode:
authorLuke <luke.wilde@live.co.uk>2021-05-07 00:52:23 +0100
committerAndreas Kling <kling@serenityos.org>2021-05-07 08:53:37 +0200
commit46f2c278b02adc99833c089f0d639fcbe8a50bc4 (patch)
tree60e858f39cda9b6353950db20135f13ea95818dc /Userland/Libraries/LibWeb
parent228c1f496853da8869a20c9e387cc5ed65bb2be1 (diff)
downloadserenity-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.cpp59
-rw-r--r--Userland/Libraries/LibWeb/DOM/Node.h2
-rw-r--r--Userland/Libraries/LibWeb/DOM/Node.idl1
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);