Skip to content

Commit

Permalink
LibWeb: Implement "move node preserving ranges" editing algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
gmta committed Dec 23, 2024
1 parent c9b923c commit 4d5fdf1
Showing 1 changed file with 33 additions and 7 deletions.
40 changes: 33 additions & 7 deletions Libraries/LibWeb/Editing/Internal/Algorithms.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1949,30 +1949,56 @@ void move_node_preserving_ranges(GC::Ref<DOM::Node> node, GC::Ref<DOM::Node> 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
Expand Down

0 comments on commit 4d5fdf1

Please sign in to comment.