|
6 | 6 | * SPDX-License-Identifier: BSD-2-Clause
|
7 | 7 | */
|
8 | 8 |
|
| 9 | +#include <LibWeb/DOM/Comment.h> |
9 | 10 | #include <LibWeb/DOM/Document.h>
|
10 | 11 | #include <LibWeb/DOM/DocumentFragment.h>
|
11 | 12 | #include <LibWeb/DOM/DocumentType.h>
|
12 | 13 | #include <LibWeb/DOM/Node.h>
|
| 14 | +#include <LibWeb/DOM/ProcessingInstruction.h> |
13 | 15 | #include <LibWeb/DOM/Range.h>
|
14 | 16 | #include <LibWeb/DOM/Text.h>
|
15 | 17 | #include <LibWeb/HTML/Window.h>
|
@@ -763,4 +765,83 @@ bool Range::partially_contains_node(Node const& node) const
|
763 | 765 | return false;
|
764 | 766 | }
|
765 | 767 |
|
| 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 | + |
766 | 847 | }
|
0 commit comments