summaryrefslogtreecommitdiff
path: root/ext/js/pages/settings/extension-keyboard-shortcuts-controller.js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/js/pages/settings/extension-keyboard-shortcuts-controller.js')
-rw-r--r--ext/js/pages/settings/extension-keyboard-shortcuts-controller.js135
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..d36d965a 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 {import('./settings-controller.js').SettingsController} settingsController
+ */
constructor(settingsController) {
+ /** @type {import('./settings-controller.js').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;