Replace KeyboardShortcutMixin by addShortcut() util in 3 dialogs Google-Bug-Id: b/199305453 Change-Id: Id5e1ece4e5eb8cbaa6bc627c05d2bd61c39b6d6d
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts index 07da53f..df537e0 100644 --- a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts +++ b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts
@@ -19,9 +19,9 @@ import '../../../styles/shared-styles'; import {PolymerElement} from '@polymer/polymer/polymer-element'; import {htmlTemplate} from './gr-confirm-abandon-dialog_html'; -import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin'; import {customElement, property} from '@polymer/decorators'; import {IronAutogrowTextareaElement} from '@polymer/iron-autogrow-textarea/iron-autogrow-textarea'; +import {addShortcut, Key, Modifier} from '../../../utils/dom-util'; export interface GrConfirmAbandonDialog { $: { @@ -35,11 +35,8 @@ } } -// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error. -const base = KeyboardShortcutMixin(PolymerElement); - @customElement('gr-confirm-abandon-dialog') -export class GrConfirmAbandonDialog extends base { +export class GrConfirmAbandonDialog extends PolymerElement { static get template() { return htmlTemplate; } @@ -59,20 +56,33 @@ @property({type: String}) message = ''; - get keyBindings() { - return { - 'ctrl+enter meta+enter': '_handleEnterKey', - }; + /** Called in disconnectedCallback. */ + private cleanups: (() => void)[] = []; + + override disconnectedCallback() { + super.disconnectedCallback(); + for (const cleanup of this.cleanups) cleanup(); + this.cleanups = []; + } + + override connectedCallback() { + super.connectedCallback(); + this.cleanups.push( + addShortcut(this, {key: Key.ENTER, modifiers: [Modifier.CTRL_KEY]}, _ => + this._confirm() + ) + ); + this.cleanups.push( + addShortcut(this, {key: Key.ENTER, modifiers: [Modifier.META_KEY]}, _ => + this._confirm() + ) + ); } resetFocus() { this.$.messageInput.textarea.focus(); } - _handleEnterKey() { - this._confirm(); - } - _handleConfirmTap(e: Event) { e.preventDefault(); e.stopPropagation();
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts index 8e6521d..b3bbc8a 100644 --- a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts +++ b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts
@@ -19,17 +19,14 @@ import '../../shared/gr-dialog/gr-dialog'; import {PolymerElement} from '@polymer/polymer/polymer-element'; import {htmlTemplate} from './gr-confirm-move-dialog_html'; -import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin'; import {customElement, property} from '@polymer/decorators'; import {BranchName, RepoName} from '../../../types/common'; import {appContext} from '../../../services/app-context'; import {GrTypedAutocomplete} from '../../shared/gr-autocomplete/gr-autocomplete'; +import {addShortcut, Key, Modifier} from '../../../utils/dom-util'; const SUGGESTIONS_LIMIT = 15; -// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error. -const base = KeyboardShortcutMixin(PolymerElement); - // This is used to make sure 'branch' // can be typed as BranchName. export interface GrConfirmMoveDialog { @@ -39,7 +36,7 @@ } @customElement('gr-confirm-move-dialog') -export class GrConfirmMoveDialog extends base { +export class GrConfirmMoveDialog extends PolymerElement { static get template() { return htmlTemplate; } @@ -68,10 +65,27 @@ @property({type: Object}) _query?: (input: string) => Promise<{name: BranchName}[]>; - get keyBindings() { - return { - 'ctrl+enter meta+enter': '_handleConfirmTap', - }; + /** Called in disconnectedCallback. */ + private cleanups: (() => void)[] = []; + + override disconnectedCallback() { + super.disconnectedCallback(); + for (const cleanup of this.cleanups) cleanup(); + this.cleanups = []; + } + + override connectedCallback() { + super.connectedCallback(); + this.cleanups.push( + addShortcut(this, {key: Key.ENTER, modifiers: [Modifier.CTRL_KEY]}, e => + this._handleConfirmTap(e) + ) + ); + this.cleanups.push( + addShortcut(this, {key: Key.ENTER, modifiers: [Modifier.META_KEY]}, e => + this._handleConfirmTap(e) + ) + ); } private readonly restApiService = appContext.restApiService;
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts index 17036e6..be57ef6 100644 --- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts +++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
@@ -38,7 +38,6 @@ ReviewerState, SpecialFilePath, } from '../../../constants/constants'; -import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin'; import { accountOrGroupKey, isReviewerOrCC, @@ -116,6 +115,7 @@ import {StorageLocation} from '../../../services/storage/gr-storage'; import {Interaction, Timing} from '../../../constants/reporting'; import {getReplyByReason} from '../../../utils/attention-set-util'; +import {addShortcut, Key, Modifier} from '../../../utils/dom-util'; const STORAGE_DEBOUNCE_INTERVAL_MS = 400; @@ -163,11 +163,8 @@ }; } -// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error. -const base = KeyboardShortcutMixin(PolymerElement); - @customElement('gr-reply-dialog') -export class GrReplyDialog extends base { +export class GrReplyDialog extends PolymerElement { static get template() { return htmlTemplate; } @@ -368,12 +365,8 @@ private storeTask?: DelayedTask; - get keyBindings() { - return { - esc: '_handleEscKey', - 'ctrl+enter meta+enter': '_handleEnterKey', - }; - } + /** Called in disconnectedCallback. */ + private cleanups: (() => void)[] = []; constructor() { super(); @@ -391,6 +384,17 @@ if (account) this._account = account; }); + this.cleanups.push( + addShortcut(this, {key: Key.ENTER, modifiers: [Modifier.CTRL_KEY]}, _ => + this._submit() + ) + ); + this.cleanups.push( + addShortcut(this, {key: Key.ENTER, modifiers: [Modifier.META_KEY]}, _ => + this._submit() + ) + ); + this.cleanups.push(addShortcut(this, {key: Key.ESC}, _ => this.cancel())); this.addEventListener('comment-editing-changed', e => { this._commentEditing = (e as CustomEvent).detail; }); @@ -418,6 +422,8 @@ override disconnectedCallback() { this.storeTask?.cancel(); + for (const cleanup of this.cleanups) cleanup(); + this.cleanups = []; super.disconnectedCallback(); } @@ -492,14 +498,6 @@ return (selectorEl as GrLabelScoreRow).selectedValue; } - _handleEscKey() { - this.cancel(); - } - - _handleEnterKey() { - this._submit(); - } - @observe('_ccs.splices') _ccsChanged(splices: PolymerSpliceChange<AccountInfo[] | GroupInfo[]>) { this._reviewerTypeChanged(splices, ReviewerType.CC);
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.ts index e57ffc7..91b8603 100644 --- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.ts +++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.ts
@@ -1799,7 +1799,7 @@ test('emits cancel on esc key', () => { const cancelHandler = sinon.spy(); element.addEventListener('cancel', cancelHandler); - pressAndReleaseKeyOn(element, 27, null, 'esc'); + pressAndReleaseKeyOn(element, 27, null, 'Escape'); flush(); assert.isTrue(cancelHandler.called); @@ -1808,14 +1808,14 @@ test('should not send on enter key', () => { stubSaveReview(() => undefined); element.addEventListener('send', () => assert.fail('wrongly called')); - pressAndReleaseKeyOn(element, 13, null, 'enter'); + pressAndReleaseKeyOn(element, 13, null, 'Enter'); }); test('emit send on ctrl+enter key', async () => { stubSaveReview(() => undefined); const promise = mockPromise(); element.addEventListener('send', () => promise.resolve()); - pressAndReleaseKeyOn(element, 13, 'ctrl', 'enter'); + pressAndReleaseKeyOn(element, 13, 'ctrl', 'Enter'); await promise; });
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 e7417f4..deb45d3 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
@@ -70,7 +70,7 @@ import {anyLineTooLong} from '../../diff/gr-diff/gr-diff-utils'; import {getUserName} from '../../../utils/display-name-util'; import {generateAbsoluteUrl} from '../../../utils/url-util'; -import {addShortcut} from '../../../utils/dom-util'; +import {addGlobalShortcut} from '../../../utils/dom-util'; const UNRESOLVED_EXPAND_COUNT = 5; const NEWLINE_PATTERN = /\n/g; @@ -239,10 +239,10 @@ override connectedCallback() { super.connectedCallback(); this.cleanups.push( - addShortcut({key: 'e'}, e => this.handleExpandShortcut(e)) + addGlobalShortcut({key: 'e'}, e => this.handleExpandShortcut(e)) ); this.cleanups.push( - addShortcut({key: 'E'}, e => this.handleCollapseShortcut(e)) + addGlobalShortcut({key: 'E'}, e => this.handleCollapseShortcut(e)) ); this._getLoggedIn().then(loggedIn => { this._showActions = loggedIn;
diff --git a/polygerrit-ui/app/utils/dom-util.ts b/polygerrit-ui/app/utils/dom-util.ts index cdcadb0..a7ad6e1 100644 --- a/polygerrit-ui/app/utils/dom-util.ts +++ b/polygerrit-ui/app/utils/dom-util.ts
@@ -379,7 +379,15 @@ return true; } +export function addGlobalShortcut( + shortcut: Shortcut, + listener: (e: KeyboardEvent) => void +) { + return addShortcut(document.body, shortcut, listener); +} + export function addShortcut( + element: HTMLElement, shortcut: Shortcut, listener: (e: KeyboardEvent) => void ) { @@ -387,8 +395,8 @@ if (e.repeat) return; if (eventMatchesShortcut(e, shortcut)) listener(e); }; - document.addEventListener('keydown', wrappedListener); - return () => document.removeEventListener('keydown', wrappedListener); + element.addEventListener('keydown', wrappedListener); + return () => element.removeEventListener('keydown', wrappedListener); } export function modifierPressed(e: KeyboardEvent) {