summaryrefslogtreecommitdiff
path: root/Userland/Libraries
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2022-03-21 18:58:00 +0100
committerAndreas Kling <kling@serenityos.org>2022-03-21 19:14:50 +0100
commitc74b1b6d65822a72aec7c31afffba5047655adbe (patch)
tree929bb95689d486fa1fdaf18d50bc4ac48a70bc2e /Userland/Libraries
parentd2f9f8bd4f4e941c782f7a8ba36f6f20653eb1d4 (diff)
downloadserenity-c74b1b6d65822a72aec7c31afffba5047655adbe.zip
LibWeb: Implement Range.insertNode(node)
Diffstat (limited to 'Userland/Libraries')
-rw-r--r--Userland/Libraries/LibWeb/DOM/Range.cpp81
-rw-r--r--Userland/Libraries/LibWeb/DOM/Range.h3
-rw-r--r--Userland/Libraries/LibWeb/DOM/Range.idl1
3 files changed, 85 insertions, 0 deletions
diff --git a/Userland/Libraries/LibWeb/DOM/Range.cpp b/Userland/Libraries/LibWeb/DOM/Range.cpp
index 5b2b9bb616..1da56a9995 100644
--- a/Userland/Libraries/LibWeb/DOM/Range.cpp
+++ b/Userland/Libraries/LibWeb/DOM/Range.cpp
@@ -6,10 +6,12 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
+#include <LibWeb/DOM/Comment.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/DocumentFragment.h>
#include <LibWeb/DOM/DocumentType.h>
#include <LibWeb/DOM/Node.h>
+#include <LibWeb/DOM/ProcessingInstruction.h>
#include <LibWeb/DOM/Range.h>
#include <LibWeb/DOM/Text.h>
#include <LibWeb/HTML/Window.h>
@@ -763,4 +765,83 @@ bool Range::partially_contains_node(Node const& node) const
return false;
}
+// https://dom.spec.whatwg.org/#dom-range-insertnode
+ExceptionOr<void> Range::insert_node(NonnullRefPtr<Node> node)
+{
+ return insert(node);
+}
+
+// https://dom.spec.whatwg.org/#concept-range-insert
+ExceptionOr<void> Range::insert(NonnullRefPtr<Node> node)
+{
+ // 1. If range’s start node is a ProcessingInstruction or Comment node, is a Text node whose parent is null, or is node, then throw a "HierarchyRequestError" DOMException.
+ if ((is<ProcessingInstruction>(*m_start_container) || is<Comment>(*m_start_container))
+ || (is<Text>(*m_start_container) && !m_start_container->parent_node())
+ || m_start_container == node.ptr()) {
+ return DOM::HierarchyRequestError::create("Range has inappropriate start node for insertion");
+ }
+
+ // 2. Let referenceNode be null.
+ RefPtr<Node> reference_node;
+
+ // 3. If range’s start node is a Text node, set referenceNode to that Text node.
+ if (is<Text>(*m_start_container)) {
+ reference_node = m_start_container;
+ }
+ // 4. Otherwise, set referenceNode to the child of start node whose index is start offset, and null if there is no such child.
+ else {
+ reference_node = m_start_container->child_at_index(m_start_offset);
+ }
+
+ // 5. Let parent be range’s start node if referenceNode is null, and referenceNode’s parent otherwise.
+ RefPtr<Node> parent;
+ if (!reference_node)
+ parent = m_start_container;
+ else
+ parent = reference_node->parent();
+
+ // 6. Ensure pre-insertion validity of node into parent before referenceNode.
+ if (auto result = parent->ensure_pre_insertion_validity(node, reference_node); result.is_exception())
+ return result.exception();
+
+ // 7. If range’s start node is a Text node, set referenceNode to the result of splitting it with offset range’s start offset.
+ if (is<Text>(*m_start_container)) {
+ auto result = static_cast<Text&>(*m_start_container).split_text(m_start_offset);
+ if (result.is_exception())
+ return result.exception();
+ reference_node = result.release_value();
+ }
+
+ // 8. If node is referenceNode, set referenceNode to its next sibling.
+ if (node == reference_node)
+ reference_node = reference_node->next_sibling();
+
+ // 9. If node’s parent is non-null, then remove node.
+ if (node->parent())
+ node->remove();
+
+ // 10. Let newOffset be parent’s length if referenceNode is null, and referenceNode’s index otherwise.
+ size_t new_offset = 0;
+ if (!reference_node)
+ new_offset = parent->length();
+ else
+ new_offset = reference_node->index();
+
+ // 11. Increase newOffset by node’s length if node is a DocumentFragment node, and one otherwise.
+ if (is<DocumentFragment>(*node))
+ new_offset += node->length();
+ else
+ new_offset += 1;
+
+ // 12. Pre-insert node into parent before referenceNode.
+ if (auto result = parent->pre_insert(node, reference_node); result.is_exception())
+ return result.exception();
+
+ // 13. If range is collapsed, then set range’s end to (parent, newOffset).
+ if (collapsed())
+ set_end(*parent, new_offset);
+
+ return {};
+}
+
}
diff --git a/Userland/Libraries/LibWeb/DOM/Range.h b/Userland/Libraries/LibWeb/DOM/Range.h
index 96f3053247..50d9ef5d1b 100644
--- a/Userland/Libraries/LibWeb/DOM/Range.h
+++ b/Userland/Libraries/LibWeb/DOM/Range.h
@@ -63,6 +63,8 @@ public:
ExceptionOr<NonnullRefPtr<DocumentFragment>> extract_contents();
+ ExceptionOr<void> insert_node(NonnullRefPtr<Node>);
+
String to_string() const;
private:
@@ -82,6 +84,7 @@ private:
ExceptionOr<void> select(Node& node);
ExceptionOr<NonnullRefPtr<DocumentFragment>> extract();
+ ExceptionOr<void> insert(NonnullRefPtr<Node>);
bool contains_node(Node const&) const;
bool partially_contains_node(Node const&) const;
diff --git a/Userland/Libraries/LibWeb/DOM/Range.idl b/Userland/Libraries/LibWeb/DOM/Range.idl
index d6b1f2649b..ac4bca149a 100644
--- a/Userland/Libraries/LibWeb/DOM/Range.idl
+++ b/Userland/Libraries/LibWeb/DOM/Range.idl
@@ -25,6 +25,7 @@ interface Range : AbstractRange {
short compareBoundaryPoints(unsigned short how, Range sourceRange);
[CEReactions, NewObject] DocumentFragment extractContents();
+ [CEReactions] undefined insertNode(Node node);
Range cloneRange();
undefined detach();