Skip to content

Commit 8347875

Browse files
committed
fix: caret jumped to line start when clicking right of a nested list item
Fixes #1296
1 parent e3f12f3 commit 8347875

3 files changed

Lines changed: 80 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
> - :house: [Internal]
1010
> - :nail_care: [Polish]
1111

12+
## 4.12.17
13+
14+
#### :bug: Bug Fix
15+
16+
- **Lists / Selection**: in a multi-level bulleted/numbered list, clicking to the right of an item that has a nested list put the caret at the **start** of the line instead of the end (a Blink/WebKit contenteditable quirk; Firefox was already correct). A `:click` handler now moves the caret to the end of the item's own text in that case. Fixes [#1296](https://github.com/xdan/jodit/issues/1296).
17+
1218
## 4.12.16
1319

1420
#### :bug: Bug Fix

src/plugins/select/select.test.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,38 @@ describe('Test select plugin', () => {
4242
});
4343
});
4444
});
45+
46+
describe('Click to the right of a nested list item (#1296)', () => {
47+
it('Should put the cursor at the end of the line, not the start', () => {
48+
const editor = getJodit();
49+
editor.value =
50+
'<ul><li>Level one text<ul><li>Level two text</li></ul></li></ul>';
51+
52+
const li = editor.editor.querySelector('li');
53+
const text = li.firstChild;
54+
55+
// Emulate Blink placing the caret at the start of the line on click
56+
const range = editor.s.createRange();
57+
range.setStart(text, 0);
58+
range.collapse(true);
59+
editor.s.selectRange(range);
60+
61+
const measure = editor.s.createRange();
62+
measure.selectNodeContents(text);
63+
const rect = measure.getBoundingClientRect();
64+
65+
simulateEvent('click', li, e => {
66+
Object.assign(e, {
67+
clientX: rect.right + 50,
68+
clientY: (rect.top + rect.bottom) / 2
69+
});
70+
});
71+
72+
editor.s.insertHTML('X');
73+
74+
expect(sortAttributes(editor.value)).equals(
75+
'<ul><li>Level one textX<ul><li>Level two text</li></ul></li></ul>'
76+
);
77+
});
78+
});
4579
});

src/plugins/select/select.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,46 @@ export class select extends Plugin {
114114
return false;
115115
}
116116

117+
/**
118+
* Fix caret position when clicking to the right of a list item that has a
119+
* nested list. Blink/WebKit place the caret at the start of the line instead
120+
* of the end (#1296); move it to the end of the item's own text.
121+
*/
122+
@watch([':click'])
123+
protected onClickRightOfNestedListItem(e: MouseEvent): void {
124+
const { s } = this.j;
125+
const range = s.range;
126+
127+
if (
128+
!range.collapsed ||
129+
range.startOffset !== 0 ||
130+
!Dom.isText(range.startContainer)
131+
) {
132+
return;
133+
}
134+
135+
const text = range.startContainer;
136+
const li = text.parentNode;
137+
138+
// The text must be the direct content of a list item that has a nested
139+
// list (the last level has no nested list and behaves correctly).
140+
if (
141+
!Dom.isTag(li, 'li') ||
142+
!(li.querySelector('ul') || li.querySelector('ol'))
143+
) {
144+
return;
145+
}
146+
147+
const measure = this.j.ed.createRange();
148+
measure.selectNodeContents(text);
149+
const rect = measure.getBoundingClientRect();
150+
151+
// Only when the click happened to the right of the text.
152+
if (e.clientX > rect.right) {
153+
s.setCursorAfter(text);
154+
}
155+
}
156+
117157
/**
118158
* Normalize selection after triple click
119159
*/

0 commit comments

Comments
 (0)