Skip to content

Commit c74b1b6

Browse files
committed
LibWeb: Implement Range.insertNode(node)
1 parent d2f9f8b commit c74b1b6

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

Userland/Libraries/LibWeb/DOM/Range.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
* SPDX-License-Identifier: BSD-2-Clause
77
*/
88

9+
#include <LibWeb/DOM/Comment.h>
910
#include <LibWeb/DOM/Document.h>
1011
#include <LibWeb/DOM/DocumentFragment.h>
1112
#include <LibWeb/DOM/DocumentType.h>
1213
#include <LibWeb/DOM/Node.h>
14+
#include <LibWeb/DOM/ProcessingInstruction.h>
1315
#include <LibWeb/DOM/Range.h>
1416
#include <LibWeb/DOM/Text.h>
1517
#include <LibWeb/HTML/Window.h>
@@ -763,4 +765,83 @@ bool Range::partially_contains_node(Node const& node) const
763765
return false;
764766
}
765767

768+
// https://dom.spec.whatwg.org/#dom-range-insertnode
769+
ExceptionOr<void> Range::insert_node(NonnullRefPtr<Node> node)
770+
{
771+
return insert(node);
772+
}
773+
774+
// https://dom.spec.whatwg.org/#concept-range-insert
775+
ExceptionOr<void> Range::insert(NonnullRefPtr<Node> node)
776+
{
777+
// 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.
778+
if ((is<ProcessingInstruction>(*m_start_container) || is<Comment>(*m_start_container))
779+
|| (is<Text>(*m_start_container) && !m_start_container->parent_node())
780+
|| m_start_container == node.ptr()) {
781+
return DOM::HierarchyRequestError::create("Range has inappropriate start node for insertion");
782+
}
783+
784+
// 2. Let referenceNode be null.
785+
RefPtr<Node> reference_node;
786+
787+
// 3. If range’s start node is a Text node, set referenceNode to that Text node.
788+
if (is<Text>(*m_start_container)) {
789+
reference_node = m_start_container;
790+
}
791+
// 4. Otherwise, set referenceNode to the child of start node whose index is start offset, and null if there is no such child.
792+
else {
793+
reference_node = m_start_container->child_at_index(m_start_offset);
794+
}
795+
796+
// 5. Let parent be range’s start node if referenceNode is null, and referenceNode’s parent otherwise.
797+
RefPtr<Node> parent;
798+
if (!reference_node)
799+
parent = m_start_container;
800+
else
801+
parent = reference_node->parent();
802+
803+
// 6. Ensure pre-insertion validity of node into parent before referenceNode.
804+
if (auto result = parent->ensure_pre_insertion_validity(node, reference_node); result.is_exception())
805+
return result.exception();
806+
807+
// 7. If range’s start node is a Text node, set referenceNode to the result of splitting it with offset range’s start offset.
808+
if (is<Text>(*m_start_container)) {
809+
auto result = static_cast<Text&>(*m_start_container).split_text(m_start_offset);
810+
if (result.is_exception())
811+
return result.exception();
812+
reference_node = result.release_value();
813+
}
814+
815+
// 8. If node is referenceNode, set referenceNode to its next sibling.
816+
if (node == reference_node)
817+
reference_node = reference_node->next_sibling();
818+
819+
// 9. If node’s parent is non-null, then remove node.
820+
if (node->parent())
821+
node->remove();
822+
823+
// 10. Let newOffset be parent’s length if referenceNode is null, and referenceNode’s index otherwise.
824+
size_t new_offset = 0;
825+
if (!reference_node)
826+
new_offset = parent->length();
827+
else
828+
new_offset = reference_node->index();
829+
830+
// 11. Increase newOffset by node’s length if node is a DocumentFragment node, and one otherwise.
831+
if (is<DocumentFragment>(*node))
832+
new_offset += node->length();
833+
else
834+
new_offset += 1;
835+
836+
// 12. Pre-insert node into parent before referenceNode.
837+
if (auto result = parent->pre_insert(node, reference_node); result.is_exception())
838+
return result.exception();
839+
840+
// 13. If range is collapsed, then set range’s end to (parent, newOffset).
841+
if (collapsed())
842+
set_end(*parent, new_offset);
843+
844+
return {};
845+
}
846+
766847
}

Userland/Libraries/LibWeb/DOM/Range.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ class Range final : public AbstractRange {
6363

6464
ExceptionOr<NonnullRefPtr<DocumentFragment>> extract_contents();
6565

66+
ExceptionOr<void> insert_node(NonnullRefPtr<Node>);
67+
6668
String to_string() const;
6769

6870
private:
@@ -82,6 +84,7 @@ class Range final : public AbstractRange {
8284
ExceptionOr<void> select(Node& node);
8385

8486
ExceptionOr<NonnullRefPtr<DocumentFragment>> extract();
87+
ExceptionOr<void> insert(NonnullRefPtr<Node>);
8588

8689
bool contains_node(Node const&) const;
8790
bool partially_contains_node(Node const&) const;

Userland/Libraries/LibWeb/DOM/Range.idl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ interface Range : AbstractRange {
2525
short compareBoundaryPoints(unsigned short how, Range sourceRange);
2626

2727
[CEReactions, NewObject] DocumentFragment extractContents();
28+
[CEReactions] undefined insertNode(Node node);
2829

2930
Range cloneRange();
3031
undefined detach();

0 commit comments

Comments
 (0)