Replace KeyboardShortcutMixin by addShortcut() util in 5 components
Google-Bug-Id: b/199305453
Change-Id: I09997238cdfc8fca3e5391935519b2451dfe8cd7
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
index 50bb665..ae3eee5 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
@@ -45,7 +45,6 @@
import {GrButton} from '../../shared/gr-button/gr-button';
import {fireEvent} from '../../../utils/event-util';
import {
- KeyboardShortcutMixin,
Shortcut,
ShortcutSection,
} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
@@ -65,11 +64,8 @@
};
}
-// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
-const base = KeyboardShortcutMixin(PolymerElement);
-
@customElement('gr-file-list-header')
-export class GrFileListHeader extends base {
+export class GrFileListHeader extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
index 74c079b..4fd5ff3 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
@@ -49,8 +49,10 @@
SpecialFilePath,
} from '../../../constants/constants';
import {
+ addGlobalShortcut,
descendedFromClass,
isShiftPressed,
+ Key,
modifierPressed,
toggleClass,
} from '../../../utils/dom-util';
@@ -319,11 +321,8 @@
disconnected$ = new Subject();
- get keyBindings() {
- return {
- esc: '_handleEscKey',
- };
- }
+ /** Called in disconnectedCallback. */
+ private cleanups: (() => void)[] = [];
override keyboardShortcuts() {
return {
@@ -415,6 +414,9 @@
this.reporting.error(new Error('dynamic header/content mismatch'));
}
});
+ this.cleanups.push(
+ addGlobalShortcut({key: Key.ESC}, e => this._handleEscKey(e))
+ );
}
override disconnectedCallback() {
@@ -423,6 +425,8 @@
this.fileCursor.unsetCursor();
this._cancelDiffs();
this.loadingTask?.cancel();
+ for (const cleanup of this.cleanups) cleanup();
+ this.cleanups = [];
super.disconnectedCallback();
}
@@ -1542,10 +1546,8 @@
return undefined;
}
- _handleEscKey(e: IronKeyboardEvent) {
- if (this.shortcuts.shouldSuppress(e) || this.shortcuts.modifierPressed(e)) {
- return;
- }
+ _handleEscKey(e: KeyboardEvent) {
+ if (this.shortcuts.shouldSuppress(e)) return;
e.preventDefault();
this._displayLine = false;
}
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts
index cd79bba..e16c073 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts
@@ -22,7 +22,6 @@
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-messages-list_html';
import {
- KeyboardShortcutMixin,
Shortcut,
ShortcutSection,
} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
@@ -201,11 +200,8 @@
};
}
-// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
-const base = KeyboardShortcutMixin(PolymerElement);
-
@customElement('gr-messages-list')
-export class GrMessagesList extends base {
+export class GrMessagesList extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
index 541d877..c91ae5a 100644
--- a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
+++ b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
@@ -21,7 +21,6 @@
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-keyboard-shortcuts-dialog_html';
import {
- KeyboardShortcutMixin,
ShortcutSection,
ShortcutListener,
SectionView,
@@ -40,11 +39,8 @@
shortcuts?: SectionView;
}
-// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
-const base = KeyboardShortcutMixin(PolymerElement);
-
@customElement('gr-keyboard-shortcuts-dialog')
-export class GrKeyboardShortcutsDialog extends base {
+export class GrKeyboardShortcutsDialog extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
index 084f9f6..236f00f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
@@ -107,7 +107,7 @@
import {fireAlert, fireEvent, fireTitleChange} from '../../../utils/event-util';
import {GerritView} from '../../../services/router/router-model';
import {assertIsDefined} from '../../../utils/common-util';
-import {toggleClass} from '../../../utils/dom-util';
+import {addGlobalShortcut, Key, toggleClass} from '../../../utils/dom-util';
import {CursorMoveResult} from '../../../api/core';
import {throttleWrap} from '../../../utils/async-util';
import {changeComments$} from '../../../services/comments/comments-model';
@@ -281,11 +281,8 @@
patchNum?: PatchSetNum;
} = {};
- get keyBindings() {
- return {
- esc: '_handleEscKey',
- };
- }
+ /** Called in disconnectedCallback. */
+ private cleanups: (() => void)[] = [];
override keyboardShortcuts() {
return {
@@ -373,6 +370,9 @@
this.cursor.reInitCursor();
};
this.$.diffHost.addEventListener('render', this._onRenderHandler);
+ this.cleanups.push(
+ addGlobalShortcut({key: Key.ESC}, e => this._handleEscKey(e))
+ );
}
override disconnectedCallback() {
@@ -381,6 +381,8 @@
if (this._onRenderHandler) {
this.$.diffHost.removeEventListener('render', this._onRenderHandler);
}
+ for (const cleanup of this.cleanups) cleanup();
+ this.cleanups = [];
super.disconnectedCallback();
}
@@ -531,10 +533,8 @@
this._setReviewed(!this.$.reviewed.checked);
}
- _handleEscKey(e: IronKeyboardEvent) {
+ _handleEscKey(e: KeyboardEvent) {
if (this.shortcuts.shouldSuppress(e)) return;
- if (this.shortcuts.modifierPressed(e)) return;
-
e.preventDefault();
this.$.diffHost.displayLine = false;
}
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js
index cc35c3c..d45ca0e 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js
@@ -512,7 +512,7 @@
assert(computeContainerClassStub.lastCall.calledWithExactly(
false, 'SIDE_BY_SIDE', true));
- MockInteractions.pressAndReleaseKeyOn(element, 27, null, 'esc');
+ MockInteractions.pressAndReleaseKeyOn(element, 27, null, 'Escape');
assert(computeContainerClassStub.lastCall.calledWithExactly(
false, 'SIDE_BY_SIDE', false));
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts
index a629d0e..e7137e4 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts
@@ -20,12 +20,12 @@
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-autocomplete-dropdown_html';
-import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
import {IronFitMixin} from '../../../mixins/iron-fit-mixin/iron-fit-mixin';
import {customElement, property, observe} from '@polymer/decorators';
import {IronFitBehavior} from '@polymer/iron-fit-behavior/iron-fit-behavior';
import {GrCursorManager} from '../gr-cursor-manager/gr-cursor-manager';
import {fireEvent} from '../../../utils/event-util';
+import {addShortcut, Key} from '../../../utils/dom-util';
export interface GrAutocompleteDropdown {
$: {
@@ -53,10 +53,7 @@
}
// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
-const base = IronFitMixin(
- KeyboardShortcutMixin(PolymerElement),
- IronFitBehavior as IronFitBehavior
-);
+const base = IronFitMixin(PolymerElement, IronFitBehavior as IronFitBehavior);
@customElement('gr-autocomplete-dropdown')
export class GrAutocompleteDropdown extends base {
@@ -91,15 +88,8 @@
@property({type: Array})
suggestions: Item[] = [];
- get keyBindings() {
- return {
- up: '_handleUp',
- down: '_handleDown',
- enter: '_handleEnter',
- esc: '_handleEscape',
- tab: '_handleTab',
- };
- }
+ /** Called in disconnectedCallback. */
+ private cleanups: (() => void)[] = [];
// visible for testing
cursor = new GrCursorManager();
@@ -110,8 +100,29 @@
this.cursor.focusOnMove = true;
}
+ override connectedCallback() {
+ super.connectedCallback();
+ this.cleanups.push(
+ addShortcut(this, {key: Key.UP}, e => this._handleUp(e))
+ );
+ this.cleanups.push(
+ addShortcut(this, {key: Key.DOWN}, e => this._handleDown(e))
+ );
+ this.cleanups.push(
+ addShortcut(this, {key: Key.ENTER}, e => this._handleEnter(e))
+ );
+ this.cleanups.push(
+ addShortcut(this, {key: Key.ESC}, _ => this._handleEscape())
+ );
+ this.cleanups.push(
+ addShortcut(this, {key: Key.TAB}, e => this._handleTab(e))
+ );
+ }
+
override disconnectedCallback() {
this.cursor.unsetCursor();
+ for (const cleanup of this.cleanups) cleanup();
+ this.cleanups = [];
super.disconnectedCallback();
}
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_test.ts b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_test.ts
index bb47dbc0..86de3b3 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown_test.ts
@@ -50,7 +50,7 @@
test('escape key', () => {
const closeSpy = sinon.spy(element, 'close');
- MockInteractions.pressAndReleaseKeyOn(element, 27);
+ MockInteractions.pressAndReleaseKeyOn(element, 27, null, 'Escape');
flush();
assert.isTrue(closeSpy.called);
});
@@ -59,7 +59,7 @@
const handleTabSpy = sinon.spy(element, '_handleTab');
const itemSelectedStub = sinon.stub();
element.addEventListener('item-selected', itemSelectedStub);
- MockInteractions.pressAndReleaseKeyOn(element, 9);
+ MockInteractions.pressAndReleaseKeyOn(element, 9, null, 'Tab');
assert.isTrue(handleTabSpy.called);
assert.equal(element.cursor.index, 0);
assert.isTrue(itemSelectedStub.called);
@@ -73,7 +73,7 @@
const handleEnterSpy = sinon.spy(element, '_handleEnter');
const itemSelectedStub = sinon.stub();
element.addEventListener('item-selected', itemSelectedStub);
- MockInteractions.pressAndReleaseKeyOn(element, 13);
+ MockInteractions.pressAndReleaseKeyOn(element, 13, null, 'Enter');
assert.isTrue(handleEnterSpy.called);
assert.equal(element.cursor.index, 0);
assert.deepEqual(itemSelectedStub.lastCall.args[0].detail, {
@@ -85,11 +85,11 @@
test('down key', () => {
element.isHidden = true;
const nextSpy = sinon.spy(element.cursor, 'next');
- MockInteractions.pressAndReleaseKeyOn(element, 40);
+ MockInteractions.pressAndReleaseKeyOn(element, 40, null, 'ArrowDown');
assert.isFalse(nextSpy.called);
assert.equal(element.cursor.index, 0);
element.isHidden = false;
- MockInteractions.pressAndReleaseKeyOn(element, 40);
+ MockInteractions.pressAndReleaseKeyOn(element, 40, null, 'ArrowDown');
assert.isTrue(nextSpy.called);
assert.equal(element.cursor.index, 1);
});
@@ -97,13 +97,13 @@
test('up key', () => {
element.isHidden = true;
const prevSpy = sinon.spy(element.cursor, 'previous');
- MockInteractions.pressAndReleaseKeyOn(element, 38);
+ MockInteractions.pressAndReleaseKeyOn(element, 38, null, 'ArrowUp');
assert.isFalse(prevSpy.called);
assert.equal(element.cursor.index, 0);
element.isHidden = false;
element.cursor.setCursorAtIndex(1);
assert.equal(element.cursor.index, 1);
- MockInteractions.pressAndReleaseKeyOn(element, 38);
+ MockInteractions.pressAndReleaseKeyOn(element, 38, null, 'ArrowUp');
assert.isTrue(prevSpy.called);
assert.equal(element.cursor.index, 0);
});
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
index 524b197..8e84aa2 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
@@ -22,7 +22,6 @@
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-autocomplete_html';
-import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
import {property, customElement, observe} from '@polymer/decorators';
import {GrAutocompleteDropdown} from '../gr-autocomplete-dropdown/gr-autocomplete-dropdown';
import {PaperInputElementExt} from '../../../types/types';
@@ -65,11 +64,8 @@
export type AutocompleteCommitEvent =
CustomEvent<AutocompleteCommitEventDetail>;
-// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
-const base = KeyboardShortcutMixin(PolymerElement);
-
@customElement('gr-autocomplete')
-export class GrAutocomplete extends base {
+export class GrAutocomplete extends PolymerElement {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
index deb45d3..6b2e5c4 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
@@ -84,8 +84,6 @@
@customElement('gr-comment-thread')
export class GrCommentThread extends PolymerElement {
- // KeyboardShortcutMixin Not used in this element rather other elements tests
-
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts
index f4179f4..2b56de6 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts
@@ -24,10 +24,10 @@
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-dropdown_html';
import {getBaseUrl} from '../../../utils/url-util';
-import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
import {IronDropdownElement} from '@polymer/iron-dropdown/iron-dropdown';
import {GrCursorManager} from '../gr-cursor-manager/gr-cursor-manager';
import {property, customElement, observe} from '@polymer/decorators';
+import {addShortcut, Key} from '../../../utils/dom-util';
const REL_NOOPENER = 'noopener';
const REL_EXTERNAL = 'external';
@@ -67,11 +67,8 @@
bold?: boolean;
}
-// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
-const base = KeyboardShortcutMixin(PolymerElement);
-
@customElement('gr-dropdown')
-export class GrDropdown extends base {
+export class GrDropdown extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -121,14 +118,8 @@
@property({type: Array})
disabledIds: string[] = [];
- get keyBindings() {
- return {
- down: '_handleDown',
- 'enter space': '_handleEnter',
- tab: '_handleTab',
- up: '_handleUp',
- };
- }
+ /** Called in disconnectedCallback. */
+ private cleanups: (() => void)[] = [];
// Used within the tests so needs to be non-private.
cursor = new GrCursorManager();
@@ -139,15 +130,36 @@
this.cursor.focusOnMove = true;
}
+ override connectedCallback() {
+ super.connectedCallback();
+ this.cleanups.push(
+ addShortcut(this, {key: Key.UP}, e => this._handleUp(e))
+ );
+ this.cleanups.push(
+ addShortcut(this, {key: Key.DOWN}, e => this._handleDown(e))
+ );
+ this.cleanups.push(
+ addShortcut(this, {key: Key.TAB}, e => this._handleTab(e))
+ );
+ this.cleanups.push(
+ addShortcut(this, {key: Key.ENTER}, e => this._handleEnter(e))
+ );
+ this.cleanups.push(
+ addShortcut(this, {key: Key.SPACE}, e => this._handleEnter(e))
+ );
+ }
+
override disconnectedCallback() {
this.cursor.unsetCursor();
+ for (const cleanup of this.cleanups) cleanup();
+ this.cleanups = [];
super.disconnectedCallback();
}
/**
* Handle the up key.
*/
- _handleUp(e: MouseEvent) {
+ _handleUp(e: Event) {
if (this.$.dropdown.opened) {
e.preventDefault();
e.stopPropagation();
@@ -160,7 +172,7 @@
/**
* Handle the down key.
*/
- _handleDown(e: MouseEvent) {
+ _handleDown(e: Event) {
if (this.$.dropdown.opened) {
e.preventDefault();
e.stopPropagation();
@@ -173,7 +185,7 @@
/**
* Handle the tab key.
*/
- _handleTab(e: MouseEvent) {
+ _handleTab(e: Event) {
if (this.$.dropdown.opened) {
// Tab in a native select is a no-op. Emulate this.
e.preventDefault();
@@ -184,7 +196,7 @@
/**
* Handle the enter key.
*/
- _handleEnter(e: MouseEvent) {
+ _handleEnter(e: Event) {
e.preventDefault();
e.stopPropagation();
if (this.$.dropdown.opened) {
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.ts b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.ts
index e14d523..393f44e 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.ts
@@ -170,18 +170,18 @@
test('down', () => {
const stub = sinon.stub(element.cursor, 'next');
assert.isFalse(element.$.dropdown.opened);
- MockInteractions.pressAndReleaseKeyOn(element, 40);
+ MockInteractions.pressAndReleaseKeyOn(element, 40, null, 'ArrowDown');
assert.isTrue(element.$.dropdown.opened);
- MockInteractions.pressAndReleaseKeyOn(element, 40);
+ MockInteractions.pressAndReleaseKeyOn(element, 40, null, 'ArrowDown');
assert.isTrue(stub.called);
});
test('up', () => {
const stub = sinon.stub(element.cursor, 'previous');
assert.isFalse(element.$.dropdown.opened);
- MockInteractions.pressAndReleaseKeyOn(element, 38);
+ MockInteractions.pressAndReleaseKeyOn(element, 38, null, 'ArrowUp');
assert.isTrue(element.$.dropdown.opened);
- MockInteractions.pressAndReleaseKeyOn(element, 38);
+ MockInteractions.pressAndReleaseKeyOn(element, 38, null, 'ArrowUp');
assert.isTrue(stub.called);
});
@@ -189,7 +189,7 @@
// Because enter and space are handled by the same fn, we need only to
// test one.
assert.isFalse(element.$.dropdown.opened);
- MockInteractions.pressAndReleaseKeyOn(element, 32); // Space
+ MockInteractions.pressAndReleaseKeyOn(element, 32, null, ' ');
assert.isTrue(element.$.dropdown.opened);
const el = queryAndAssert<HTMLAnchorElement>(
@@ -197,7 +197,7 @@
':not([hidden]) a'
);
const stub = sinon.stub(el, 'click');
- MockInteractions.pressAndReleaseKeyOn(element, 32); // Space
+ MockInteractions.pressAndReleaseKeyOn(element, 32, null, ' ');
assert.isTrue(stub.called);
});
});
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
index 434da1f..337d595 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
@@ -23,7 +23,6 @@
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-textarea_html';
-import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
import {appContext} from '../../../services/app-context';
import {customElement, property} from '@polymer/decorators';
import {ReportingService} from '../../../services/gr-reporting/gr-reporting';
@@ -33,7 +32,7 @@
Item,
ItemSelectedEvent,
} from '../gr-autocomplete-dropdown/gr-autocomplete-dropdown';
-import {IronKeyboardEvent} from '../../../types/events';
+import {addShortcut, Key} from '../../../utils/dom-util';
const MAX_ITEMS_DROPDOWN = 10;
@@ -85,11 +84,8 @@
}
}
-// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
-const base = KeyboardShortcutMixin(PolymerElement);
-
@customElement('gr-textarea')
-export class GrTextarea extends base {
+export class GrTextarea extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -150,21 +146,39 @@
disableEnterKeyForSelectingEmoji = false;
- get keyBindings() {
- return {
- esc: '_handleEscKey',
- tab: '_handleTabKey',
- enter: '_handleEnterByKey',
- up: '_handleUpKey',
- down: '_handleDownKey',
- };
- }
+ /** Called in disconnectedCallback. */
+ private cleanups: (() => void)[] = [];
constructor() {
super();
this.reporting = appContext.reportingService;
}
+ override disconnectedCallback() {
+ super.disconnectedCallback();
+ for (const cleanup of this.cleanups) cleanup();
+ this.cleanups = [];
+ }
+
+ override connectedCallback() {
+ super.connectedCallback();
+ this.cleanups.push(
+ addShortcut(this, {key: Key.UP}, e => this._handleUpKey(e))
+ );
+ this.cleanups.push(
+ addShortcut(this, {key: Key.DOWN}, e => this._handleDownKey(e))
+ );
+ this.cleanups.push(
+ addShortcut(this, {key: Key.TAB}, e => this._handleTabKey(e))
+ );
+ this.cleanups.push(
+ addShortcut(this, {key: Key.ENTER}, e => this._handleEnterByKey(e))
+ );
+ this.cleanups.push(
+ addShortcut(this, {key: Key.ESC}, e => this._handleEscKey(e))
+ );
+ }
+
override ready() {
super.ready();
if (this.monospace) {
@@ -238,16 +252,11 @@
this._setEmoji(this.$.emojiSuggestions.getCurrentText());
}
- _handleEnterByKey(e: IronKeyboardEvent) {
+ _handleEnterByKey(e: KeyboardEvent) {
// Enter should have newline behavior if the picker is closed or if the user
// has only typed ':'. Also make sure that shortcuts aren't clobbered.
if (this._hideEmojiAutocomplete || this.disableEnterKeyForSelectingEmoji) {
- if (
- !e.detail.keyboardEvent?.metaKey &&
- !e.detail.keyboardEvent?.ctrlKey
- ) {
- this.indent(e);
- }
+ this.indent(e);
return;
}
@@ -420,7 +429,7 @@
);
}
- private indent(e: IronKeyboardEvent): void {
+ private indent(e: KeyboardEvent): void {
if (!document.queryCommandSupported('insertText')) {
return;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.ts b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.ts
index 7e59692..318c720 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea_test.ts
@@ -20,7 +20,6 @@
import {GrTextarea} from './gr-textarea';
import {html} from '@polymer/polymer/lib/utils/html-tag';
import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
-import {IronKeyboardEvent} from '../../../types/events';
import {ItemSelectedEvent} from '../gr-autocomplete-dropdown/gr-autocomplete-dropdown';
const basicFixture = fixtureFromElement('gr-textarea');
@@ -238,34 +237,12 @@
const indentCommand = sinon.stub(document, 'execCommand');
element.$.textarea.value = ' a';
element._handleEnterByKey(
- new CustomEvent('keydown', {
- detail: {keyboardEvent: {keyCode: 13}},
- }) as IronKeyboardEvent
+ new KeyboardEvent('keydown', {key: 'Enter', keyCode: 13})
);
await flush();
assert.deepEqual(indentCommand.args[0], ['insertText', false, '\n ']);
});
- test('ctrl+enter and meta+enter do not indent', async () => {
- const indentCommand = sinon.stub(document, 'execCommand');
- element.$.textarea.value = ' a';
- element._handleEnterByKey(
- new CustomEvent('keydown', {
- detail: {keyboardEvent: {keyCode: 13, ctrlKey: true}},
- }) as IronKeyboardEvent
- );
- await flush();
- assert.isTrue(indentCommand.notCalled);
-
- element._handleEnterByKey(
- new CustomEvent('keydown', {
- detail: {keyboardEvent: {keyCode: 13, metaKey: true}},
- }) as IronKeyboardEvent
- );
- await flush();
- assert.isTrue(indentCommand.notCalled);
- });
-
test('emoji dropdown is closed when iron-overlay-closed is fired', () => {
const resetSpy = sinon.spy(element, '_resetEmojiDropdown');
element.$.emojiSuggestions.dispatchEvent(
@@ -301,38 +278,78 @@
test('escape key', () => {
const resetSpy = sinon.spy(element, '_resetEmojiDropdown');
- MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 27);
+ MockInteractions.pressAndReleaseKeyOn(
+ element.$.textarea,
+ 27,
+ null,
+ 'Escape'
+ );
assert.isFalse(resetSpy.called);
setupDropdown();
- MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 27);
+ MockInteractions.pressAndReleaseKeyOn(
+ element.$.textarea,
+ 27,
+ null,
+ 'Escape'
+ );
assert.isTrue(resetSpy.called);
assert.isFalse(!element.$.emojiSuggestions.isHidden);
});
test('up key', () => {
const upSpy = sinon.spy(element.$.emojiSuggestions, 'cursorUp');
- MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 38);
+ MockInteractions.pressAndReleaseKeyOn(
+ element.$.textarea,
+ 38,
+ null,
+ 'ArrowUp'
+ );
assert.isFalse(upSpy.called);
setupDropdown();
- MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 38);
+ MockInteractions.pressAndReleaseKeyOn(
+ element.$.textarea,
+ 38,
+ null,
+ 'ArrowUp'
+ );
assert.isTrue(upSpy.called);
});
test('down key', () => {
const downSpy = sinon.spy(element.$.emojiSuggestions, 'cursorDown');
- MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 40);
+ MockInteractions.pressAndReleaseKeyOn(
+ element.$.textarea,
+ 40,
+ null,
+ 'ArrowDown'
+ );
assert.isFalse(downSpy.called);
setupDropdown();
- MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 40);
+ MockInteractions.pressAndReleaseKeyOn(
+ element.$.textarea,
+ 40,
+ null,
+ 'ArrowDown'
+ );
assert.isTrue(downSpy.called);
});
test('enter key', () => {
const enterSpy = sinon.spy(element.$.emojiSuggestions, 'getCursorTarget');
- MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 13);
+ MockInteractions.pressAndReleaseKeyOn(
+ element.$.textarea,
+ 13,
+ null,
+ 'Enter'
+ );
assert.isFalse(enterSpy.called);
setupDropdown();
- MockInteractions.pressAndReleaseKeyOn(element.$.textarea, 13);
+ MockInteractions.pressAndReleaseKeyOn(
+ element.$.textarea,
+ 13,
+ null,
+ 'Enter'
+ );
assert.isTrue(enterSpy.called);
flush();
assert.equal(element.text, '💯');