Skip to content

Commit 2674bd4

Browse files
committed
LibWeb: Implement up/down arrow navigation for EditingHostManager
1 parent f529a4d commit 2674bd4

File tree

5 files changed

+119
-4
lines changed

5 files changed

+119
-4
lines changed

Libraries/LibWeb/DOM/EditingHostManager.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,14 +161,14 @@ void EditingHostManager::decrement_cursor_position_to_previous_word(CollapseSele
161161

162162
void EditingHostManager::increment_cursor_position_to_next_line(CollapseSelection collapse)
163163
{
164-
(void)collapse;
165-
// FIXME: Implement this method
164+
if (auto selection = m_document->get_selection())
165+
selection->move_offset_to_next_line(collapse == CollapseSelection::Yes);
166166
}
167167

168168
void EditingHostManager::decrement_cursor_position_to_previous_line(CollapseSelection collapse)
169169
{
170-
(void)collapse;
171-
// FIXME: Implement this method
170+
if (auto selection = m_document->get_selection())
171+
selection->move_offset_to_previous_line(collapse == CollapseSelection::Yes);
172172
}
173173

174174
void EditingHostManager::handle_delete(DeleteDirection direction)

Libraries/LibWeb/Selection/Selection.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <LibWeb/DOM/Position.h>
1414
#include <LibWeb/DOM/Range.h>
1515
#include <LibWeb/DOM/Text.h>
16+
#include <LibWeb/GraphemeEdgeTracker.h>
1617
#include <LibWeb/Selection/Selection.h>
1718

1819
namespace Web::Selection {
@@ -650,4 +651,40 @@ void Selection::move_offset_to_previous_word(bool collapse_selection)
650651
}
651652
}
652653

654+
void Selection::move_offset_to_next_line(bool collapse_selection)
655+
{
656+
auto* text_node = as_if<DOM::Text>(anchor_node().ptr());
657+
if (!text_node)
658+
return;
659+
660+
auto new_offset = compute_cursor_position_on_next_line(*text_node, focus_offset());
661+
if (!new_offset.has_value())
662+
return;
663+
664+
if (collapse_selection) {
665+
MUST(collapse(text_node, *new_offset));
666+
m_document->reset_cursor_blink_cycle();
667+
} else {
668+
MUST(set_base_and_extent(*text_node, anchor_offset(), *text_node, *new_offset));
669+
}
670+
}
671+
672+
void Selection::move_offset_to_previous_line(bool collapse_selection)
673+
{
674+
auto* text_node = as_if<DOM::Text>(anchor_node().ptr());
675+
if (!text_node)
676+
return;
677+
678+
auto new_offset = compute_cursor_position_on_previous_line(*text_node, focus_offset());
679+
if (!new_offset.has_value())
680+
return;
681+
682+
if (collapse_selection) {
683+
MUST(collapse(text_node, *new_offset));
684+
m_document->reset_cursor_blink_cycle();
685+
} else {
686+
MUST(set_base_and_extent(*text_node, anchor_offset(), *text_node, *new_offset));
687+
}
688+
}
689+
653690
}

Libraries/LibWeb/Selection/Selection.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ class WEB_API Selection final : public Bindings::PlatformObject {
6868
void move_offset_to_previous_character(bool collapse_selection);
6969
void move_offset_to_next_word(bool collapse_selection);
7070
void move_offset_to_previous_word(bool collapse_selection);
71+
void move_offset_to_next_line(bool collapse_selection);
72+
void move_offset_to_previous_line(bool collapse_selection);
7173

7274
private:
7375
Selection(GC::Ref<JS::Realm>, GC::Ref<DOM::Document>);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Home: position=0 character="h"
2+
Right: position=1 character="e"
3+
Right: position=2 character="l"
4+
Right: position=3 character="l"
5+
Right: position=4 character="o"
6+
Right: position=5 character=" "
7+
Down: position=28 character="👩🏼‍❤️‍👨🏻"
8+
Left: position=27 character=" "
9+
Up: position=2 character="l"
10+
Right: position=3 character="l"
11+
Right: position=4 character="o"
12+
Right: position=5 character=" "
13+
Right: position=6 character="👩🏼‍❤️‍👨🏻"
14+
Down: position=40 character=" "
15+
Up: position=6 character="👩🏼‍❤️‍👨🏻"
16+
Down: position=40 character=" "
17+
Left: position=28 character="👩🏼‍❤️‍👨🏻"
18+
Left: position=27 character=" "
19+
Up: position=2 character="l"
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<!DOCTYPE html>
2+
<script src="../include.js"></script>
3+
<p id="text" contenteditable style="width: 120px">hello 👩🏼‍❤️‍👨🏻 there
4+
my 👩🏼‍❤️‍👨🏻 friends!</p>
5+
<script>
6+
test(() => {
7+
// We need to ensure layout has occurred for arrow navigation to have a layout node to interact with.
8+
document.body.offsetWidth;
9+
10+
const segmenter = new Intl.Segmenter("en", { granularity: "grapheme" });
11+
const content = text.innerText.trim();
12+
13+
const cursorLocation = () => {
14+
return window.getSelection().getRangeAt(0).startOffset;
15+
};
16+
17+
const graphemeAtLocation = (cursor) => {
18+
const segments = segmenter.segment(content.substring(cursor));
19+
return Array.from(segments)[0].segment;
20+
};
21+
22+
const moveCursor = direction => {
23+
internals.sendKey(text, direction);
24+
25+
const cursor = cursorLocation();
26+
const character = graphemeAtLocation(cursor);
27+
28+
println(`${direction}: position=${cursor} character="${character}"`);
29+
};
30+
31+
moveCursor("Home");
32+
33+
moveCursor("Right");
34+
moveCursor("Right");
35+
moveCursor("Right");
36+
moveCursor("Right");
37+
moveCursor("Right");
38+
39+
moveCursor("Down");
40+
moveCursor("Left");
41+
moveCursor("Up");
42+
43+
moveCursor("Right");
44+
moveCursor("Right");
45+
moveCursor("Right");
46+
moveCursor("Right");
47+
48+
moveCursor("Down");
49+
moveCursor("Up");
50+
moveCursor("Down");
51+
52+
moveCursor("Left");
53+
moveCursor("Left");
54+
55+
moveCursor("Up");
56+
});
57+
</script>

0 commit comments

Comments
 (0)