From 4d5fdf1f96e71875a2c731b4d35c9649fca5c1d0 Mon Sep 17 00:00:00 2001 From: Jelle Raaijmakers Date: Mon, 23 Dec 2024 14:10:25 +0100 Subject: [PATCH] LibWeb: Implement "move node preserving ranges" editing algorithm --- .../LibWeb/Editing/Internal/Algorithms.cpp | 40 +++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/Libraries/LibWeb/Editing/Internal/Algorithms.cpp b/Libraries/LibWeb/Editing/Internal/Algorithms.cpp index 6040920e6e6d7..531900dd5e3f8 100644 --- a/Libraries/LibWeb/Editing/Internal/Algorithms.cpp +++ b/Libraries/LibWeb/Editing/Internal/Algorithms.cpp @@ -1949,30 +1949,56 @@ void move_node_preserving_ranges(GC::Ref node, GC::Ref new // (if any), then insert it in the new location. In doing so, follow these rules instead of // those defined by the insert and remove algorithms: - // FIXME: Currently this is a simple range-destroying move. Implement "follow these rules" as - // described above. + // AD-HOC: We implement this spec by taking note of the current active range (if any), performing the remove and + // insertion of node, and then restoring the range after performing any necessary adjustments. + auto& selection = *node->document().get_selection(); + auto active_range = selection.range(); + auto start_container = active_range->start_container(); + auto start_offset = active_range->start_offset(); + auto end_container = active_range->end_container(); + auto end_offset = active_range->end_offset(); // 1. Let node be the moved node, old parent and old index be the old parent (which may be null) // and index, and new parent and new index be the new parent and index. auto* old_parent = node->parent(); - [[maybe_unused]] auto old_index = node->index(); + auto old_index = node->index(); if (old_parent) node->remove(); auto* new_next_sibling = new_parent->child_at_index(new_index); new_parent->insert_before(node, new_next_sibling); - // FIXME: 2. If a boundary point's node is the same as or a descendant of node, leave it unchanged, so + // AD-HOC: Return early if there was no active range + if (!active_range) + return; + + // 2. If a boundary point's node is the same as or a descendant of node, leave it unchanged, so // it moves to the new location. + // NOTE: This step exists for completeness. - // FIXME: 3. If a boundary point's node is new parent and its offset is greater than new index, add one + // 3. If a boundary point's node is new parent and its offset is greater than new index, add one // to its offset. + if (start_container == new_parent && start_offset > new_index) + MUST(active_range->set_start(start_container, start_offset + 1)); + if (end_container == new_parent && end_offset > new_index) + MUST(active_range->set_end(end_container, end_offset + 1)); - // FIXME: 4. If a boundary point's node is old parent and its offset is old index or old index + 1, set + // 4. If a boundary point's node is old parent and its offset is old index or old index + 1, set // its node to new parent and add new index − old index to its offset. + if (start_container == old_parent && (start_offset == old_index || start_offset == old_index + 1)) + MUST(active_range->set_start(new_parent, start_offset + new_index - old_index)); + if (end_container == old_parent && (end_offset == old_index || end_offset == old_index + 1)) + MUST(active_range->set_end(new_parent, end_offset + new_index - old_index)); - // FIXME: 5. If a boundary point's node is old parent and its offset is greater than old index + 1, + // 5. If a boundary point's node is old parent and its offset is greater than old index + 1, // subtract one from its offset. + if (start_container == old_parent && start_offset > old_index + 1) + MUST(active_range->set_start(*old_parent, start_offset - 1)); + if (end_container == old_parent && end_offset > old_index + 1) + MUST(active_range->set_end(*old_parent, end_offset - 1)); + + // AD-HOC: Set the new active range + selection.add_range(*active_range); } // https://w3c.github.io/editing/docs/execCommand/#next-equivalent-point