Prevent looping of cursor position when CTRL+ARROW_LEFT/ARROW_RIGHT is pressed.
Change-Id: I3df70a614a490779155083b99fa0460bd3eb2bd8
Release-Notes: skip
Google-Bug-Id: b/340968595
diff --git a/polygerrit-ui/app/embed/gr-textarea.ts b/polygerrit-ui/app/embed/gr-textarea.ts
index 05bef49..27948fd 100644
--- a/polygerrit-ui/app/embed/gr-textarea.ts
+++ b/polygerrit-ui/app/embed/gr-textarea.ts
@@ -173,6 +173,8 @@
private focused = false;
+ private currentCursorPosition = -1;
+
private readonly isPlaintextOnlySupported = supportsPlainTextEditing();
static override get styles() {
@@ -488,6 +490,19 @@
event.preventDefault();
this.fire('saveShortcut');
}
+ // Prevent looping of cursor position when CTRL+ARROW_LEFT/ARROW_RIGHT is
+ // pressed.
+ if (event.ctrlKey || event.metaKey || event.altKey) {
+ if (event.key === 'ArrowLeft' && this.currentCursorPosition === 0) {
+ event.preventDefault();
+ }
+ if (
+ event.key === 'ArrowRight' &&
+ this.currentCursorPosition === (this.value?.length ?? 0)
+ ) {
+ event.preventDefault();
+ }
+ }
await this.toggleHintVisibilityIfAny();
}
@@ -597,7 +612,9 @@
}
private onCursorPositionChange() {
- this.fire('cursorPositionChange', {position: this.getCursorPosition()});
+ const cursorPosition = this.getCursorPosition();
+ this.fire('cursorPositionChange', {position: cursorPosition});
+ this.currentCursorPosition = cursorPosition;
}
private async updateValueInDom() {
diff --git a/polygerrit-ui/app/embed/gr-textarea_test.ts b/polygerrit-ui/app/embed/gr-textarea_test.ts
index b701dcb..d125d2f 100644
--- a/polygerrit-ui/app/embed/gr-textarea_test.ts
+++ b/polygerrit-ui/app/embed/gr-textarea_test.ts
@@ -232,4 +232,56 @@
assert.equal(element.value, oldValue + hint);
});
+
+ test('when cursor is at end, Mod + ArrowRight does not change cursor position', async () => {
+ const CURSOR_POSITION_CHANGE_EVENT = 'cursorPositionChange';
+ let cursorPosition = -1;
+ const value = 'Hola amigos';
+ const editableDiv = element.shadowRoot!.querySelector(
+ '.editableDiv'
+ ) as HTMLDivElement;
+ element.addEventListener(CURSOR_POSITION_CHANGE_EVENT, (event: Event) => {
+ const detail = (event as CustomEvent<CursorPositionChangeEventDetail>)
+ .detail;
+ cursorPosition = detail.position;
+ });
+ await element.updateComplete;
+ element.value = value;
+ await element.putCursorAtEnd();
+ await element.updateComplete;
+
+ editableDiv.dispatchEvent(
+ new KeyboardEvent('keydown', {key: 'ArrowRight', metaKey: true})
+ );
+ await element.updateComplete;
+ await rafPromise();
+
+ assert.equal(cursorPosition, value.length);
+ });
+
+ test('when cursor is at 0, Mod + ArrowLeft does not change cursor position', async () => {
+ const CURSOR_POSITION_CHANGE_EVENT = 'cursorPositionChange';
+ let cursorPosition = -1;
+ const value = 'Hola amigos';
+ const editableDiv = element.shadowRoot!.querySelector(
+ '.editableDiv'
+ ) as HTMLDivElement;
+ element.addEventListener(CURSOR_POSITION_CHANGE_EVENT, (event: Event) => {
+ const detail = (event as CustomEvent<CursorPositionChangeEventDetail>)
+ .detail;
+ cursorPosition = detail.position;
+ });
+ await element.updateComplete;
+ element.value = value;
+ element.setCursorPosition(0);
+ await element.updateComplete;
+
+ editableDiv.dispatchEvent(
+ new KeyboardEvent('keydown', {key: 'ArrowLeft', metaKey: true})
+ );
+ await element.updateComplete;
+ await rafPromise();
+
+ assert.equal(cursorPosition, 0);
+ });
});