diff options
author | Andreas Kling <kling@serenityos.org> | 2022-03-22 20:17:52 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-03-22 20:17:52 +0100 |
commit | 2fb9eb52576529001d68063e314e848c674d076a (patch) | |
tree | 1c5c428f0abe7294c243f33f92b47951a09ae086 /Userland/Libraries/LibWeb | |
parent | e1c71b3f91c272fdc294e466ce596f1e9210611c (diff) | |
download | serenity-2fb9eb52576529001d68063e314e848c674d076a.zip |
LibWeb: Implement Range.deleteContents()
And here's another point on Acid3. :^)
Diffstat (limited to 'Userland/Libraries/LibWeb')
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Range.cpp | 67 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Range.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Range.idl | 1 |
3 files changed, 69 insertions, 0 deletions
diff --git a/Userland/Libraries/LibWeb/DOM/Range.cpp b/Userland/Libraries/LibWeb/DOM/Range.cpp index 5208ea5d41..71a5a66f38 100644 --- a/Userland/Libraries/LibWeb/DOM/Range.cpp +++ b/Userland/Libraries/LibWeb/DOM/Range.cpp @@ -1042,4 +1042,71 @@ ExceptionOr<NonnullRefPtr<DocumentFragment>> Range::clone_the_contents() return fragment; } +// https://dom.spec.whatwg.org/#dom-range-deletecontents +ExceptionOr<void> Range::delete_contents() +{ + // 1. If this is collapsed, then return. + if (collapsed()) + return {}; + + // 2. Let original start node, original start offset, original end node, and original end offset be this’s start node, start offset, end node, and end offset, respectively. + NonnullRefPtr<Node> original_start_node = m_start_container; + auto original_start_offset = m_start_offset; + NonnullRefPtr<Node> original_end_node = m_end_container; + auto original_end_offset = m_end_offset; + + // 3. If original start node is original end node and it is a CharacterData node, then replace data with node original start node, offset original start offset, + // count original end offset minus original start offset, and data the empty string, and then return. + if (original_start_node.ptr() == original_end_node.ptr() && is<CharacterData>(*original_start_node)) { + TRY(static_cast<CharacterData&>(*original_start_node).replace_data(original_start_offset, original_end_offset - original_start_offset, "")); + return {}; + } + + // 4. Let nodes to remove be a list of all the nodes that are contained in this, in tree order, omitting any node whose parent is also contained in this. + Vector<NonnullRefPtr<Node>> nodes_to_remove; + for (Node const* node = start_container(); node != end_container()->next_in_pre_order(); node = node->next_in_pre_order()) { + if (contains_node(*node) && (!node->parent_node() || !contains_node(*node->parent_node()))) + nodes_to_remove.append(*node); + } + + RefPtr<Node> new_node; + size_t new_offset = 0; + + // 5. If original start node is an inclusive ancestor of original end node, set new node to original start node and new offset to original start offset. + if (original_start_node->is_inclusive_ancestor_of(original_end_node)) { + new_node = original_start_node; + new_offset = original_start_offset; + } + // 6. Otherwise + else { + // 1. Let reference node equal original start node. + auto reference_node = original_start_node; + + // 2. While reference node’s parent is not null and is not an inclusive ancestor of original end node, set reference node to its parent. + while (reference_node->parent_node() && !reference_node->parent_node()->is_inclusive_ancestor_of(original_end_node)) + reference_node = *reference_node->parent_node(); + + // 3. Set new node to the parent of reference node, and new offset to one plus the index of reference node. + new_node = reference_node->parent_node(); + new_offset = 1 + reference_node->index(); + } + + // 7. If original start node is a CharacterData node, then replace data with node original start node, offset original start offset, count original start node’s length minus original start offset, data the empty string. + if (is<CharacterData>(*original_start_node)) + TRY(static_cast<CharacterData&>(*original_start_node).replace_data(original_start_offset, original_start_node->length() - original_start_offset, "")); + + // 8. For each node in nodes to remove, in tree order, remove node. + for (auto& node : nodes_to_remove) + node->remove(); + + // 9. If original end node is a CharacterData node, then replace data with node original end node, offset 0, count original end offset and data the empty string. + if (is<CharacterData>(*original_end_node)) + TRY(static_cast<CharacterData&>(*original_end_node).replace_data(0, original_end_offset, "")); + + // 10. Set start and end to (new node, new offset). + set_start(*new_node, new_offset); + set_end(*new_node, new_offset); + return {}; +} + } diff --git a/Userland/Libraries/LibWeb/DOM/Range.h b/Userland/Libraries/LibWeb/DOM/Range.h index 410f193e67..57a784de26 100644 --- a/Userland/Libraries/LibWeb/DOM/Range.h +++ b/Userland/Libraries/LibWeb/DOM/Range.h @@ -61,6 +61,7 @@ public: ExceptionOr<bool> is_point_in_range(Node const&, u32 offset) const; ExceptionOr<i16> compare_point(Node const&, u32 offset) const; + ExceptionOr<void> delete_contents(); ExceptionOr<NonnullRefPtr<DocumentFragment>> extract_contents(); ExceptionOr<NonnullRefPtr<DocumentFragment>> clone_contents(); diff --git a/Userland/Libraries/LibWeb/DOM/Range.idl b/Userland/Libraries/LibWeb/DOM/Range.idl index 8000471651..677954eae0 100644 --- a/Userland/Libraries/LibWeb/DOM/Range.idl +++ b/Userland/Libraries/LibWeb/DOM/Range.idl @@ -24,6 +24,7 @@ interface Range : AbstractRange { const unsigned short END_TO_START = 3; short compareBoundaryPoints(unsigned short how, Range sourceRange); + [CEReactions] undefined deleteContents(); [CEReactions, NewObject] DocumentFragment extractContents(); [CEReactions, NewObject] DocumentFragment cloneContents(); [CEReactions] undefined insertNode(Node node); |