diff options
Diffstat (limited to 'ext/js/pages/settings/extension-keyboard-shortcuts-controller.js')
-rw-r--r-- | ext/js/pages/settings/extension-keyboard-shortcuts-controller.js | 135 |
1 files changed, 116 insertions, 19 deletions
diff --git a/ext/js/pages/settings/extension-keyboard-shortcuts-controller.js b/ext/js/pages/settings/extension-keyboard-shortcuts-controller.js index 4f3ed569..6c9a3864 100644 --- a/ext/js/pages/settings/extension-keyboard-shortcuts-controller.js +++ b/ext/js/pages/settings/extension-keyboard-shortcuts-controller.js @@ -22,24 +22,36 @@ import {yomitan} from '../../yomitan.js'; import {KeyboardMouseInputField} from './keyboard-mouse-input-field.js'; export class ExtensionKeyboardShortcutController { + /** + * @param {SettingsController} settingsController + */ constructor(settingsController) { + /** @type {SettingsController} */ this._settingsController = settingsController; + /** @type {?HTMLButtonElement} */ this._resetButton = null; + /** @type {?HTMLButtonElement} */ this._clearButton = null; + /** @type {?HTMLElement} */ this._listContainer = null; + /** @type {HotkeyUtil} */ this._hotkeyUtil = new HotkeyUtil(); + /** @type {?import('environment').OperatingSystem} */ this._os = null; + /** @type {ExtensionKeyboardShortcutHotkeyEntry[]} */ this._entries = []; } + /** @type {HotkeyUtil} */ get hotkeyUtil() { return this._hotkeyUtil; } + /** */ async prepare() { - this._resetButton = document.querySelector('#extension-hotkey-list-reset-all'); - this._clearButton = document.querySelector('#extension-hotkey-list-clear-all'); - this._listContainer = document.querySelector('#extension-hotkey-list'); + this._resetButton = /** @type {HTMLButtonElement} */ (document.querySelector('#extension-hotkey-list-reset-all')); + this._clearButton = /** @type {HTMLButtonElement} */ (document.querySelector('#extension-hotkey-list-clear-all')); + this._listContainer = /** @type {HTMLElement} */ (document.querySelector('#extension-hotkey-list')); const canResetCommands = this.canResetCommands(); const canModifyCommands = this.canModifyCommands(); @@ -61,10 +73,16 @@ export class ExtensionKeyboardShortcutController { this._setupCommands(commands); } + /** + * @param {string} name + * @returns {Promise<{key: ?string, modifiers: import('input').Modifier[]}>} + */ async resetCommand(name) { await this._resetCommand(name); + /** @type {?string} */ let key = null; + /** @type {import('input').Modifier[]} */ let modifiers = []; const commands = await this._getCommands(); @@ -78,32 +96,60 @@ export class ExtensionKeyboardShortcutController { return {key, modifiers}; } + /** + * @param {string} name + * @param {?string} key + * @param {import('input').Modifier[]} modifiers + */ async updateCommand(name, key, modifiers) { // Firefox-only; uses Promise API const shortcut = this._hotkeyUtil.convertInputToCommand(key, modifiers); - return await chrome.commands.update({name, shortcut}); + await browser.commands.update({name, shortcut}); } + /** + * @returns {boolean} + */ canResetCommands() { - return isObject(chrome.commands) && typeof chrome.commands.reset === 'function'; + return ( + typeof browser === 'object' && browser !== null && + typeof browser.commands === 'object' && browser.commands !== null && + typeof browser.commands.reset === 'function' + ); } + /** + * @returns {boolean} + */ canModifyCommands() { - return isObject(chrome.commands) && typeof chrome.commands.update === 'function'; + return ( + typeof browser === 'object' && browser !== null && + typeof browser.commands === 'object' && browser.commands !== null && + typeof browser.commands.update === 'function' + ); } // Add + /** + * @param {MouseEvent} e + */ _onResetClick(e) { e.preventDefault(); this._resetAllCommands(); } + /** + * @param {MouseEvent} e + */ _onClearClick(e) { e.preventDefault(); this._clearAllCommands(); } + /** + * @returns {Promise<chrome.commands.Command[]>} + */ _getCommands() { return new Promise((resolve, reject) => { if (!(isObject(chrome.commands) && typeof chrome.commands.getAll === 'function')) { @@ -122,6 +168,9 @@ export class ExtensionKeyboardShortcutController { }); } + /** + * @param {chrome.commands.Command[]} commands + */ _setupCommands(commands) { for (const entry of this._entries) { entry.cleanup(); @@ -131,7 +180,7 @@ export class ExtensionKeyboardShortcutController { const fragment = document.createDocumentFragment(); for (const {name, description, shortcut} of commands) { - if (name.startsWith('_')) { continue; } + if (typeof name !== 'string' || name.startsWith('_')) { continue; } const {key, modifiers} = this._hotkeyUtil.convertCommandToInput(shortcut); @@ -143,10 +192,12 @@ export class ExtensionKeyboardShortcutController { this._entries.push(entry); } - this._listContainer.textContent = ''; - this._listContainer.appendChild(fragment); + const listContainer = /** @type {HTMLElement} */ (this._listContainer); + listContainer.textContent = ''; + listContainer.appendChild(fragment); } + /** */ async _resetAllCommands() { if (!this.canModifyCommands()) { return; } @@ -154,7 +205,7 @@ export class ExtensionKeyboardShortcutController { const promises = []; for (const {name} of commands) { - if (name.startsWith('_')) { continue; } + if (typeof name !== 'string' || name.startsWith('_')) { continue; } promises.push(this._resetCommand(name)); } @@ -164,6 +215,7 @@ export class ExtensionKeyboardShortcutController { this._setupCommands(commands); } + /** */ async _clearAllCommands() { if (!this.canModifyCommands()) { return; } @@ -171,7 +223,7 @@ export class ExtensionKeyboardShortcutController { const promises = []; for (const {name} of commands) { - if (name.startsWith('_')) { continue; } + if (typeof name !== 'string' || name.startsWith('_')) { continue; } promises.push(this.updateCommand(name, null, [])); } @@ -181,31 +233,55 @@ export class ExtensionKeyboardShortcutController { this._setupCommands(commands); } + /** + * @param {string} name + */ async _resetCommand(name) { // Firefox-only; uses Promise API - return await chrome.commands.reset(name); + await browser.commands.reset(name); } } class ExtensionKeyboardShortcutHotkeyEntry { + /** + * @param {ExtensionKeyboardShortcutController} parent + * @param {Element} node + * @param {string} name + * @param {string|undefined} description + * @param {?string} key + * @param {import('input').Modifier[]} modifiers + * @param {?import('environment').OperatingSystem} os + */ constructor(parent, node, name, description, key, modifiers, os) { + /** @type {ExtensionKeyboardShortcutController} */ this._parent = parent; + /** @type {Element} */ this._node = node; + /** @type {string} */ this._name = name; + /** @type {string|undefined} */ this._description = description; + /** @type {?string} */ this._key = key; + /** @type {import('input').Modifier[]} */ this._modifiers = modifiers; + /** @type {?import('environment').OperatingSystem} */ this._os = os; + /** @type {?HTMLInputElement} */ this._input = null; + /** @type {?KeyboardMouseInputField} */ this._inputField = null; + /** @type {EventListenerCollection} */ this._eventListeners = new EventListenerCollection(); } + /** */ prepare() { - this._node.querySelector('.settings-item-label').textContent = this._description || this._name; + const label = /** @type {HTMLElement} */ (this._node.querySelector('.settings-item-label')); + label.textContent = this._description || this._name; - const button = this._node.querySelector('.extension-hotkey-list-item-button'); - const input = this._node.querySelector('input'); + const button = /** @type {HTMLButtonElement} */ (this._node.querySelector('.extension-hotkey-list-item-button')); + const input = /** @type {HTMLInputElement} */ (this._node.querySelector('input')); this._input = input; @@ -222,6 +298,7 @@ class ExtensionKeyboardShortcutHotkeyEntry { } } + /** */ cleanup() { this._eventListeners.removeAllEventListeners(); if (this._node.parentNode !== null) { @@ -235,15 +312,22 @@ class ExtensionKeyboardShortcutHotkeyEntry { // Private + /** + * @param {import('keyboard-mouse-input-field').ChangeEvent} e + */ _onInputFieldChange(e) { const {key, modifiers} = e; this._tryUpdateInput(key, modifiers, false); } + /** */ _onInputFieldBlur() { this._updateInput(); } + /** + * @param {import('popup-menu').MenuCloseEvent} e + */ _onMenuClose(e) { switch (e.detail.action) { case 'clearInput': @@ -255,11 +339,19 @@ class ExtensionKeyboardShortcutHotkeyEntry { } } + /** */ _updateInput() { - this._inputField.setInput(this._key, this._modifiers); - delete this._input.dataset.invalid; + /** @type {KeyboardMouseInputField} */ (this._inputField).setInput(this._key, this._modifiers); + if (this._input !== null) { + delete this._input.dataset.invalid; + } } + /** + * @param {?string} key + * @param {import('input').Modifier[]} modifiers + * @param {boolean} updateInput + */ async _tryUpdateInput(key, modifiers, updateInput) { let okay = (key === null ? (modifiers.length === 0) : (modifiers.length !== 0)); if (okay) { @@ -273,9 +365,13 @@ class ExtensionKeyboardShortcutHotkeyEntry { if (okay) { this._key = key; this._modifiers = modifiers; - delete this._input.dataset.invalid; + if (this._input !== null) { + delete this._input.dataset.invalid; + } } else { - this._input.dataset.invalid = 'true'; + if (this._input !== null) { + this._input.dataset.invalid = 'true'; + } } if (updateInput) { @@ -283,6 +379,7 @@ class ExtensionKeyboardShortcutHotkeyEntry { } } + /** */ async _resetInput() { const {key, modifiers} = await this._parent.resetCommand(this._name); this._key = key; |