diff options
Diffstat (limited to 'ext/bg/js/settings2')
-rw-r--r-- | ext/bg/js/settings2/extension-keyboard-shortcuts-controller.js | 292 | ||||
-rw-r--r-- | ext/bg/js/settings2/keyboard-shortcuts-controller.js | 368 | ||||
-rw-r--r-- | ext/bg/js/settings2/mecab-controller.js | 67 | ||||
-rw-r--r-- | ext/bg/js/settings2/nested-popups-controller.js | 71 | ||||
-rw-r--r-- | ext/bg/js/settings2/popup-window-controller.js | 38 | ||||
-rw-r--r-- | ext/bg/js/settings2/secondary-search-dictionary-controller.js | 73 | ||||
-rw-r--r-- | ext/bg/js/settings2/sentence-termination-characters-controller.js | 243 | ||||
-rw-r--r-- | ext/bg/js/settings2/settings-display-controller.js | 400 | ||||
-rw-r--r-- | ext/bg/js/settings2/settings-main.js | 156 | ||||
-rw-r--r-- | ext/bg/js/settings2/translation-text-replacements-controller.js | 242 |
10 files changed, 0 insertions, 1950 deletions
diff --git a/ext/bg/js/settings2/extension-keyboard-shortcuts-controller.js b/ext/bg/js/settings2/extension-keyboard-shortcuts-controller.js deleted file mode 100644 index 9c930703..00000000 --- a/ext/bg/js/settings2/extension-keyboard-shortcuts-controller.js +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (C) 2021 Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -/* global - * HotkeyUtil - * KeyboardMouseInputField - * api - */ - -class ExtensionKeyboardShortcutController { - constructor(settingsController) { - this._settingsController = settingsController; - this._resetButton = null; - this._clearButton = null; - this._listContainer = null; - this._hotkeyUtil = new HotkeyUtil(); - this._os = null; - this._entries = []; - } - - 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'); - - const canResetCommands = this.canResetCommands(); - const canModifyCommands = this.canModifyCommands(); - this._resetButton.hidden = !canResetCommands; - this._clearButton.hidden = !canModifyCommands; - - if (canResetCommands) { - this._resetButton.addEventListener('click', this._onResetClick.bind(this)); - } - if (canModifyCommands) { - this._clearButton.addEventListener('click', this._onClearClick.bind(this)); - } - - const {platform: {os}} = await api.getEnvironmentInfo(); - this._os = os; - this._hotkeyUtil.os = os; - - const commands = await this._getCommands(); - this._setupCommands(commands); - } - - async resetCommand(name) { - await this._resetCommand(name); - - let key = null; - let modifiers = []; - - const commands = await this._getCommands(); - for (const {name: name2, shortcut} of commands) { - if (name === name2) { - ({key, modifiers} = this._hotkeyUtil.convertCommandToInput(shortcut)); - break; - } - } - - return {key, 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}); - } - - canResetCommands() { - return isObject(chrome.commands) && typeof chrome.commands.reset === 'function'; - } - - canModifyCommands() { - return isObject(chrome.commands) && typeof chrome.commands.update === 'function'; - } - - // Add - - _onResetClick(e) { - e.preventDefault(); - this._resetAllCommands(); - } - - _onClearClick(e) { - e.preventDefault(); - this._clearAllCommands(); - } - - _getCommands() { - return new Promise((resolve, reject) => { - if (!(isObject(chrome.commands) && typeof chrome.commands.getAll === 'function')) { - resolve([]); - return; - } - - chrome.commands.getAll((result) => { - const e = chrome.runtime.lastError; - if (e) { - reject(new Error(e.message)); - } else { - resolve(result); - } - }); - }); - } - - _setupCommands(commands) { - for (const entry of this._entries) { - entry.cleanup(); - } - this._entries = []; - - const fragment = document.createDocumentFragment(); - - for (const {name, description, shortcut} of commands) { - if (name.startsWith('_')) { continue; } - - const {key, modifiers} = this._hotkeyUtil.convertCommandToInput(shortcut); - - const node = this._settingsController.instantiateTemplate('extension-hotkey-list-item'); - fragment.appendChild(node); - - const entry = new ExtensionKeyboardShortcutHotkeyEntry(this, node, name, description, key, modifiers, this._os); - entry.prepare(); - this._entries.push(entry); - } - - this._listContainer.textContent = ''; - this._listContainer.appendChild(fragment); - } - - async _resetAllCommands() { - if (!this.canModifyCommands()) { return; } - - let commands = await this._getCommands(); - const promises = []; - - for (const {name} of commands) { - if (name.startsWith('_')) { continue; } - promises.push(this._resetCommand(name)); - } - - await Promise.all(promises); - - commands = await this._getCommands(); - this._setupCommands(commands); - } - - async _clearAllCommands() { - if (!this.canModifyCommands()) { return; } - - let commands = await this._getCommands(); - const promises = []; - - for (const {name} of commands) { - if (name.startsWith('_')) { continue; } - promises.push(this.updateCommand(name, null, [])); - } - - await Promise.all(promises); - - commands = await this._getCommands(); - this._setupCommands(commands); - } - - async _resetCommand(name) { - // Firefox-only; uses Promise API - return await chrome.commands.reset(name); - } -} - -class ExtensionKeyboardShortcutHotkeyEntry { - constructor(parent, node, name, description, key, modifiers, os) { - this._parent = parent; - this._node = node; - this._name = name; - this._description = description; - this._key = key; - this._modifiers = modifiers; - this._os = os; - this._input = null; - this._inputField = null; - this._eventListeners = new EventListenerCollection(); - } - - prepare() { - this._node.querySelector('.settings-item-label').textContent = this._description || this._name; - - const button = this._node.querySelector('.extension-hotkey-list-item-button'); - const input = this._node.querySelector('input'); - - this._input = input; - - if (this._parent.canModifyCommands()) { - this._inputField = new KeyboardMouseInputField(input, null, this._os); - this._inputField.prepare(this._key, this._modifiers, false, true); - this._eventListeners.on(this._inputField, 'change', this._onInputFieldChange.bind(this)); - this._eventListeners.addEventListener(button, 'menuClose', this._onMenuClose.bind(this)); - this._eventListeners.addEventListener(input, 'blur', this._onInputFieldBlur.bind(this)); - } else { - input.readOnly = true; - input.value = this._parent.hotkeyUtil.getInputDisplayValue(this._key, this._modifiers); - button.hidden = true; - } - } - - cleanup() { - this._eventListeners.removeAllEventListeners(); - if (this._node.parentNode !== null) { - this._node.parentNode.removeChild(this._node); - } - if (this._inputField !== null) { - this._inputField.cleanup(); - this._inputField = null; - } - } - - // Private - - _onInputFieldChange(e) { - const {key, modifiers} = e; - this._tryUpdateInput(key, modifiers, false); - } - - _onInputFieldBlur() { - this._updateInput(); - } - - _onMenuClose(e) { - switch (e.detail.action) { - case 'clearInput': - this._tryUpdateInput(null, [], true); - break; - case 'resetInput': - this._resetInput(); - break; - } - } - - _updateInput() { - this._inputField.setInput(this._key, this._modifiers); - delete this._input.dataset.invalid; - } - - async _tryUpdateInput(key, modifiers, updateInput) { - let okay = (key === null ? (modifiers.length === 0) : (modifiers.length !== 0)); - if (okay) { - try { - await this._parent.updateCommand(this._name, key, modifiers); - } catch (e) { - okay = false; - } - } - - if (okay) { - this._key = key; - this._modifiers = modifiers; - delete this._input.dataset.invalid; - } else { - this._input.dataset.invalid = 'true'; - } - - if (updateInput) { - this._updateInput(); - } - } - - async _resetInput() { - const {key, modifiers} = await this._parent.resetCommand(this._name); - this._key = key; - this._modifiers = modifiers; - this._updateInput(); - } -} diff --git a/ext/bg/js/settings2/keyboard-shortcuts-controller.js b/ext/bg/js/settings2/keyboard-shortcuts-controller.js deleted file mode 100644 index 0dcfa2ee..00000000 --- a/ext/bg/js/settings2/keyboard-shortcuts-controller.js +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright (C) 2021 Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -/* global - * KeyboardMouseInputField - * api - */ - -class KeyboardShortcutController { - constructor(settingsController) { - this._settingsController = settingsController; - this._entries = []; - this._os = null; - this._addButton = null; - this._resetButton = null; - this._listContainer = null; - this._emptyIndicator = null; - this._stringComparer = new Intl.Collator('en-US'); // Invariant locale - this._scrollContainer = null; - } - - get settingsController() { - return this._settingsController; - } - - async prepare() { - const {platform: {os}} = await api.getEnvironmentInfo(); - this._os = os; - - this._addButton = document.querySelector('#hotkey-list-add'); - this._resetButton = document.querySelector('#hotkey-list-reset'); - this._listContainer = document.querySelector('#hotkey-list'); - this._emptyIndicator = document.querySelector('#hotkey-list-empty'); - this._scrollContainer = document.querySelector('#keyboard-shortcuts-modal .modal-body'); - - this._addButton.addEventListener('click', this._onAddClick.bind(this)); - this._resetButton.addEventListener('click', this._onResetClick.bind(this)); - this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this)); - - await this._updateOptions(); - } - - async addEntry(terminationCharacterEntry) { - const options = await this._settingsController.getOptions(); - const {inputs: {hotkeys}} = options; - - await this._settingsController.modifyProfileSettings([{ - action: 'splice', - path: 'inputs.hotkeys', - start: hotkeys.length, - deleteCount: 0, - items: [terminationCharacterEntry] - }]); - - await this._updateOptions(); - this._scrollContainer.scrollTop = this._scrollContainer.scrollHeight; - } - - async deleteEntry(index) { - const options = await this._settingsController.getOptions(); - const {inputs: {hotkeys}} = options; - - if (index < 0 || index >= hotkeys.length) { return false; } - - await this._settingsController.modifyProfileSettings([{ - action: 'splice', - path: 'inputs.hotkeys', - start: index, - deleteCount: 1, - items: [] - }]); - - await this._updateOptions(); - return true; - } - - async modifyProfileSettings(targets) { - return await this._settingsController.modifyProfileSettings(targets); - } - - async getDefaultHotkeys() { - const defaultOptions = await this._settingsController.getDefaultOptions(); - return defaultOptions.profiles[0].options.inputs.hotkeys; - } - - // Private - - _onOptionsChanged({options}) { - for (const entry of this._entries) { - entry.cleanup(); - } - - this._entries = []; - const {inputs: {hotkeys}} = options; - const fragment = document.createDocumentFragment(); - - for (let i = 0, ii = hotkeys.length; i < ii; ++i) { - const hotkeyEntry = hotkeys[i]; - const node = this._settingsController.instantiateTemplate('hotkey-list-item'); - fragment.appendChild(node); - const entry = new KeyboardShortcutHotkeyEntry(this, hotkeyEntry, i, node, this._os, this._stringComparer); - this._entries.push(entry); - entry.prepare(); - } - - this._listContainer.appendChild(fragment); - this._listContainer.hidden = (hotkeys.length === 0); - this._emptyIndicator.hidden = (hotkeys.length !== 0); - } - - _onAddClick(e) { - e.preventDefault(); - this._addNewEntry(); - } - - _onResetClick(e) { - e.preventDefault(); - this._reset(); - } - - async _addNewEntry() { - const newEntry = { - action: '', - key: null, - modifiers: [], - scopes: ['popup', 'search'], - enabled: true - }; - return await this.addEntry(newEntry); - } - - async _updateOptions() { - const options = await this._settingsController.getOptions(); - this._onOptionsChanged({options}); - } - - async _reset() { - const value = await this.getDefaultHotkeys(); - await this._settingsController.setProfileSetting('inputs.hotkeys', value); - await this._updateOptions(); - } -} - -class KeyboardShortcutHotkeyEntry { - constructor(parent, data, index, node, os, stringComparer) { - this._parent = parent; - this._data = data; - this._index = index; - this._node = node; - this._os = os; - this._eventListeners = new EventListenerCollection(); - this._inputField = null; - this._actionSelect = null; - this._scopeCheckboxes = null; - this._scopeCheckboxContainers = null; - this._basePath = `inputs.hotkeys[${this._index}]`; - this._stringComparer = stringComparer; - } - - prepare() { - const node = this._node; - - const menuButton = node.querySelector('.hotkey-list-item-button'); - const input = node.querySelector('.hotkey-list-item-input'); - const action = node.querySelector('.hotkey-list-item-action'); - const scopeCheckboxes = node.querySelectorAll('.hotkey-scope-checkbox'); - const scopeCheckboxContainers = node.querySelectorAll('.hotkey-scope-checkbox-container'); - const enabledToggle = node.querySelector('.hotkey-list-item-enabled'); - - this._actionSelect = action; - this._scopeCheckboxes = scopeCheckboxes; - this._scopeCheckboxContainers = scopeCheckboxContainers; - - this._inputField = new KeyboardMouseInputField(input, null, this._os); - this._inputField.prepare(this._data.key, this._data.modifiers, false, true); - - action.value = this._data.action; - - enabledToggle.checked = this._data.enabled; - enabledToggle.dataset.setting = `${this._basePath}.enabled`; - - this._updateCheckboxVisibility(); - this._updateCheckboxStates(); - - for (const scopeCheckbox of scopeCheckboxes) { - this._eventListeners.addEventListener(scopeCheckbox, 'change', this._onScopeCheckboxChange.bind(this), false); - } - this._eventListeners.addEventListener(menuButton, 'menuClose', this._onMenuClose.bind(this), false); - this._eventListeners.addEventListener(this._actionSelect, 'change', this._onActionSelectChange.bind(this), false); - this._eventListeners.on(this._inputField, 'change', this._onInputFieldChange.bind(this)); - } - - cleanup() { - this._eventListeners.removeAllEventListeners(); - this._inputField.cleanup(); - if (this._node.parentNode !== null) { - this._node.parentNode.removeChild(this._node); - } - } - - // Private - - _onMenuClose(e) { - switch (e.detail.action) { - case 'delete': - this._delete(); - break; - case 'clearInputs': - this._inputField.clearInputs(); - break; - case 'resetInput': - this._resetInput(); - break; - } - } - - _onInputFieldChange({key, modifiers}) { - this._setKeyAndModifiers(key, modifiers); - } - - _onScopeCheckboxChange(e) { - const node = e.currentTarget; - const {scope} = node.dataset; - if (typeof scope !== 'string') { return; } - this._setScopeEnabled(scope, node.checked); - } - - _onActionSelectChange(e) { - const value = e.currentTarget.value; - this._setAction(value); - } - - async _delete() { - this._parent.deleteEntry(this._index); - } - - async _setKeyAndModifiers(key, modifiers) { - this._data.key = key; - this._data.modifiers = modifiers; - await this._modifyProfileSettings([ - { - action: 'set', - path: `${this._basePath}.key`, - value: key - }, - { - action: 'set', - path: `${this._basePath}.modifiers`, - value: modifiers - } - ]); - } - - async _setScopeEnabled(scope, enabled) { - const scopes = this._data.scopes; - const index = scopes.indexOf(scope); - if ((index >= 0) === enabled) { return; } - - if (enabled) { - scopes.push(scope); - const stringComparer = this._stringComparer; - scopes.sort((scope1, scope2) => stringComparer.compare(scope1, scope2)); - } else { - scopes.splice(index, 1); - } - - await this._modifyProfileSettings([{ - action: 'set', - path: `${this._basePath}.scopes`, - value: scopes - }]); - } - - async _modifyProfileSettings(targets) { - return await this._parent.settingsController.modifyProfileSettings(targets); - } - - async _resetInput() { - const defaultHotkeys = await this._parent.getDefaultHotkeys(); - const defaultValue = this._getDefaultKeyAndModifiers(defaultHotkeys, this._data.action); - if (defaultValue === null) { return; } - - const {key, modifiers} = defaultValue; - await this._setKeyAndModifiers(key, modifiers); - this._inputField.setInput(key, modifiers); - } - - _getDefaultKeyAndModifiers(defaultHotkeys, action) { - for (const {action: action2, key, modifiers} of defaultHotkeys) { - if (action2 !== action) { continue; } - return {modifiers, key}; - } - return null; - } - - async _setAction(value) { - const targets = [{ - action: 'set', - path: `${this._basePath}.action`, - value - }]; - - this._data.action = value; - - const scopes = this._data.scopes; - const validScopes = this._getValidScopesForAction(value); - if (validScopes !== null) { - let changed = false; - for (let i = 0, ii = scopes.length; i < ii; ++i) { - if (!validScopes.has(scopes[i])) { - scopes.splice(i, 1); - --i; - --ii; - changed = true; - } - } - if (changed) { - if (scopes.length === 0) { - scopes.push(...validScopes); - } - targets.push({ - action: 'set', - path: `${this._basePath}.scopes`, - value: scopes - }); - this._updateCheckboxStates(); - } - } - - await this._modifyProfileSettings(targets); - - this._updateCheckboxVisibility(); - } - - _updateCheckboxStates() { - const scopes = this._data.scopes; - for (const scopeCheckbox of this._scopeCheckboxes) { - scopeCheckbox.checked = scopes.includes(scopeCheckbox.dataset.scope); - } - } - - _updateCheckboxVisibility() { - const validScopes = this._getValidScopesForAction(this._data.action); - for (const node of this._scopeCheckboxContainers) { - node.hidden = !(validScopes === null || validScopes.has(node.dataset.scope)); - } - } - - _getValidScopesForAction(action) { - const optionNode = this._actionSelect.querySelector(`option[value="${action}"]`); - const scopesString = (optionNode !== null ? optionNode.dataset.scopes : void 0); - return (typeof scopesString === 'string' ? new Set(scopesString.split(' ')) : null); - } -} diff --git a/ext/bg/js/settings2/mecab-controller.js b/ext/bg/js/settings2/mecab-controller.js deleted file mode 100644 index ff2a4a66..00000000 --- a/ext/bg/js/settings2/mecab-controller.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2021 Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -/* global - * api - */ - -class MecabController { - constructor(settingsController) { - this._settingsController = settingsController; - this._testButton = null; - this._resultsContainer = null; - this._testActive = false; - } - - prepare() { - this._testButton = document.querySelector('#test-mecab-button'); - this._resultsContainer = document.querySelector('#test-mecab-results'); - - this._testButton.addEventListener('click', this._onTestButtonClick.bind(this), false); - } - - // Private - - _onTestButtonClick(e) { - e.preventDefault(); - this._testMecab(); - } - - async _testMecab() { - if (this._testActive) { return; } - - try { - this._testActive = true; - this._testButton.disabled = true; - this._resultsContainer.textContent = ''; - this._resultsContainer.hidden = true; - await api.testMecab(); - this._setStatus('Connection was successful', false); - } catch (e) { - this._setStatus(e.message, true); - } finally { - this._testActive = false; - this._testButton.disabled = false; - } - } - - _setStatus(message, isError) { - this._resultsContainer.textContent = message; - this._resultsContainer.hidden = false; - this._resultsContainer.classList.toggle('danger-text', isError); - } -} diff --git a/ext/bg/js/settings2/nested-popups-controller.js b/ext/bg/js/settings2/nested-popups-controller.js deleted file mode 100644 index 1ebc7389..00000000 --- a/ext/bg/js/settings2/nested-popups-controller.js +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2020-2021 Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -/* global - * DOMDataBinder - */ - -class NestedPopupsController { - constructor(settingsController) { - this._settingsController = settingsController; - this._popupNestingMaxDepth = 0; - } - - async prepare() { - this._nestedPopupsEnabled = document.querySelector('#nested-popups-enabled'); - this._nestedPopupsCount = document.querySelector('#nested-popups-count'); - this._nestedPopupsEnabledMoreOptions = document.querySelector('#nested-popups-enabled-more-options'); - - const options = await this._settingsController.getOptions(); - - this._nestedPopupsEnabled.addEventListener('change', this._onNestedPopupsEnabledChange.bind(this), false); - this._nestedPopupsCount.addEventListener('change', this._onNestedPopupsCountChange.bind(this), false); - this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this)); - this._onOptionsChanged({options}); - } - - // Private - - _onOptionsChanged({options}) { - this._updatePopupNestingMaxDepth(options.scanning.popupNestingMaxDepth); - } - - _onNestedPopupsEnabledChange(e) { - const value = e.currentTarget.checked; - if (value && this._popupNestingMaxDepth > 0) { return; } - this._setPopupNestingMaxDepth(value ? 1 : 0); - } - - _onNestedPopupsCountChange(e) { - const node = e.currentTarget; - const value = Math.max(1, DOMDataBinder.convertToNumber(node.value, node)); - this._setPopupNestingMaxDepth(value); - } - - _updatePopupNestingMaxDepth(value) { - const enabled = (value > 0); - this._popupNestingMaxDepth = value; - this._nestedPopupsEnabled.checked = enabled; - this._nestedPopupsCount.value = `${value}`; - this._nestedPopupsEnabledMoreOptions.hidden = !enabled; - } - - async _setPopupNestingMaxDepth(value) { - this._updatePopupNestingMaxDepth(value); - await this._settingsController.setProfileSetting('scanning.popupNestingMaxDepth', value); - } -} diff --git a/ext/bg/js/settings2/popup-window-controller.js b/ext/bg/js/settings2/popup-window-controller.js deleted file mode 100644 index cc83db68..00000000 --- a/ext/bg/js/settings2/popup-window-controller.js +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2021 Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -/* global - * api - */ - -class PopupWindowController { - prepare() { - const testLink = document.querySelector('#test-window-open-link'); - testLink.addEventListener('click', this._onTestWindowOpenLinkClick.bind(this), false); - } - - // Private - - _onTestWindowOpenLinkClick(e) { - e.preventDefault(); - this._testWindowOpen(); - } - - async _testWindowOpen() { - await api.getOrCreateSearchPopup({focus: true}); - } -} diff --git a/ext/bg/js/settings2/secondary-search-dictionary-controller.js b/ext/bg/js/settings2/secondary-search-dictionary-controller.js deleted file mode 100644 index 2fb3de67..00000000 --- a/ext/bg/js/settings2/secondary-search-dictionary-controller.js +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2020-2021 Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -/* global - * ObjectPropertyAccessor - */ - -class SecondarySearchDictionaryController { - constructor(settingsController) { - this._settingsController = settingsController; - this._getDictionaryInfoToken = null; - this._container = null; - this._eventListeners = new EventListenerCollection(); - } - - async prepare() { - this._container = document.querySelector('#secondary-search-dictionary-list'); - - yomichan.on('databaseUpdated', this._onDatabaseUpdated.bind(this)); - - await this._onDatabaseUpdated(); - } - - // Private - - async _onDatabaseUpdated() { - this._eventListeners.removeAllEventListeners(); - - const token = {}; - this._getDictionaryInfoToken = token; - const dictionaries = await this._settingsController.getDictionaryInfo(); - if (this._getDictionaryInfoToken !== token) { return; } - this._getDictionaryInfoToken = null; - - const fragment = document.createDocumentFragment(); - for (const {title, revision} of dictionaries) { - const node = this._settingsController.instantiateTemplate('secondary-search-dictionary'); - fragment.appendChild(node); - - const nameNode = node.querySelector('.dictionary-title'); - nameNode.textContent = title; - - const versionNode = node.querySelector('.dictionary-version'); - versionNode.textContent = `rev.${revision}`; - - const toggle = node.querySelector('.dictionary-allow-secondary-searches'); - toggle.dataset.setting = ObjectPropertyAccessor.getPathString(['dictionaries', title, 'allowSecondarySearches']); - this._eventListeners.addEventListener(toggle, 'settingChanged', this._onEnabledChanged.bind(this, node), false); - } - - this._container.textContent = ''; - this._container.appendChild(fragment); - } - - _onEnabledChanged(node, e) { - const {detail: {value}} = e; - node.dataset.enabled = `${value}`; - } -}
\ No newline at end of file diff --git a/ext/bg/js/settings2/sentence-termination-characters-controller.js b/ext/bg/js/settings2/sentence-termination-characters-controller.js deleted file mode 100644 index d62771ec..00000000 --- a/ext/bg/js/settings2/sentence-termination-characters-controller.js +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright (C) 2021 Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -class SentenceTerminationCharactersController { - constructor(settingsController) { - this._settingsController = settingsController; - this._entries = []; - this._addButton = null; - this._resetButton = null; - this._listTable = null; - this._listContainer = null; - this._emptyIndicator = null; - } - - get settingsController() { - return this._settingsController; - } - - async prepare() { - this._addButton = document.querySelector('#sentence-termination-character-list-add'); - this._resetButton = document.querySelector('#sentence-termination-character-list-reset'); - this._listTable = document.querySelector('#sentence-termination-character-list-table'); - this._listContainer = document.querySelector('#sentence-termination-character-list'); - this._emptyIndicator = document.querySelector('#sentence-termination-character-list-empty'); - - this._addButton.addEventListener('click', this._onAddClick.bind(this)); - this._resetButton.addEventListener('click', this._onResetClick.bind(this)); - this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this)); - - await this._updateOptions(); - } - - async addEntry(terminationCharacterEntry) { - const options = await this._settingsController.getOptions(); - const {sentenceParsing: {terminationCharacters}} = options; - - await this._settingsController.modifyProfileSettings([{ - action: 'splice', - path: 'sentenceParsing.terminationCharacters', - start: terminationCharacters.length, - deleteCount: 0, - items: [terminationCharacterEntry] - }]); - - await this._updateOptions(); - } - - async deleteEntry(index) { - const options = await this._settingsController.getOptions(); - const {sentenceParsing: {terminationCharacters}} = options; - - if (index < 0 || index >= terminationCharacters.length) { return false; } - - await this._settingsController.modifyProfileSettings([{ - action: 'splice', - path: 'sentenceParsing.terminationCharacters', - start: index, - deleteCount: 1, - items: [] - }]); - - await this._updateOptions(); - return true; - } - - async modifyProfileSettings(targets) { - return await this._settingsController.modifyProfileSettings(targets); - } - - // Private - - _onOptionsChanged({options}) { - for (const entry of this._entries) { - entry.cleanup(); - } - - this._entries = []; - const {sentenceParsing: {terminationCharacters}} = options; - - for (let i = 0, ii = terminationCharacters.length; i < ii; ++i) { - const terminationCharacterEntry = terminationCharacters[i]; - const node = this._settingsController.instantiateTemplate('sentence-termination-character-entry'); - this._listContainer.appendChild(node); - const entry = new SentenceTerminationCharacterEntry(this, terminationCharacterEntry, i, node); - this._entries.push(entry); - entry.prepare(); - } - - this._listTable.hidden = (terminationCharacters.length === 0); - this._emptyIndicator.hidden = (terminationCharacters.length !== 0); - } - - _onAddClick(e) { - e.preventDefault(); - this._addNewEntry(); - } - - _onResetClick(e) { - e.preventDefault(); - this._reset(); - } - - async _addNewEntry() { - const newEntry = { - enabled: true, - character1: '"', - character2: '"', - includeCharacterAtStart: false, - includeCharacterAtEnd: false - }; - return await this.addEntry(newEntry); - } - - async _updateOptions() { - const options = await this._settingsController.getOptions(); - this._onOptionsChanged({options}); - } - - async _reset() { - const defaultOptions = await this._settingsController.getDefaultOptions(); - const value = defaultOptions.profiles[0].options.sentenceParsing.terminationCharacters; - await this._settingsController.setProfileSetting('sentenceParsing.terminationCharacters', value); - await this._updateOptions(); - } -} - -class SentenceTerminationCharacterEntry { - constructor(parent, data, index, node) { - this._parent = parent; - this._data = data; - this._index = index; - this._node = node; - this._eventListeners = new EventListenerCollection(); - this._character1Input = null; - this._character2Input = null; - this._basePath = `sentenceParsing.terminationCharacters[${this._index}]`; - } - - prepare() { - const {enabled, character1, character2, includeCharacterAtStart, includeCharacterAtEnd} = this._data; - const node = this._node; - - const enabledToggle = node.querySelector('.sentence-termination-character-enabled'); - const typeSelect = node.querySelector('.sentence-termination-character-type'); - const character1Input = node.querySelector('.sentence-termination-character-input1'); - const character2Input = node.querySelector('.sentence-termination-character-input2'); - const includeAtStartCheckbox = node.querySelector('.sentence-termination-character-include-at-start'); - const includeAtEndheckbox = node.querySelector('.sentence-termination-character-include-at-end'); - const menuButton = node.querySelector('.sentence-termination-character-entry-button'); - - this._character1Input = character1Input; - this._character2Input = character2Input; - - const type = (character2 === null ? 'terminator' : 'quote'); - node.dataset.type = type; - - enabledToggle.checked = enabled; - typeSelect.value = type; - character1Input.value = character1; - character2Input.value = (character2 !== null ? character2 : ''); - includeAtStartCheckbox.checked = includeCharacterAtStart; - includeAtEndheckbox.checked = includeCharacterAtEnd; - - enabledToggle.dataset.setting = `${this._basePath}.enabled`; - includeAtStartCheckbox.dataset.setting = `${this._basePath}.includeCharacterAtStart`; - includeAtEndheckbox.dataset.setting = `${this._basePath}.includeCharacterAtEnd`; - - this._eventListeners.addEventListener(typeSelect, 'change', this._onTypeSelectChange.bind(this), false); - this._eventListeners.addEventListener(character1Input, 'change', this._onCharacterChange.bind(this, 1), false); - this._eventListeners.addEventListener(character2Input, 'change', this._onCharacterChange.bind(this, 2), false); - this._eventListeners.addEventListener(menuButton, 'menuClose', this._onMenuClose.bind(this), false); - } - - cleanup() { - this._eventListeners.removeAllEventListeners(); - if (this._node.parentNode !== null) { - this._node.parentNode.removeChild(this._node); - } - } - - // Private - - _onTypeSelectChange(e) { - this._setHasCharacter2(e.currentTarget.value === 'quote'); - } - - _onCharacterChange(characterNumber, e) { - const node = e.currentTarget; - if (characterNumber === 2 && this._data.character2 === null) { - node.value = ''; - } - - const value = node.value.substring(0, 1); - this._setCharacterValue(node, characterNumber, value); - } - - _onMenuClose(e) { - switch (e.detail.action) { - case 'delete': - this._delete(); - break; - } - } - - async _delete() { - this._parent.deleteEntry(this._index); - } - - async _setHasCharacter2(has) { - const okay = await this._setCharacterValue(this._character2Input, 2, has ? this._data.character1 : null); - if (okay) { - const type = (!has ? 'terminator' : 'quote'); - this._node.dataset.type = type; - } - } - - async _setCharacterValue(inputNode, characterNumber, value) { - const pathEnd = `character${characterNumber}`; - const r = await this._parent.settingsController.setProfileSetting(`${this._basePath}.${pathEnd}`, value); - const okay = !r[0].error; - if (okay) { - this._data[pathEnd] = value; - } else { - value = this._data[pathEnd]; - } - inputNode.value = (value !== null ? value : ''); - return okay; - } -} diff --git a/ext/bg/js/settings2/settings-display-controller.js b/ext/bg/js/settings2/settings-display-controller.js deleted file mode 100644 index 9d3e5459..00000000 --- a/ext/bg/js/settings2/settings-display-controller.js +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Copyright (C) 2020-2021 Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -/* global - * PopupMenu - * SelectorObserver - */ - -class SettingsDisplayController { - constructor(settingsController, modalController) { - this._settingsController = settingsController; - this._modalController = modalController; - this._contentNode = null; - this._menuContainer = null; - this._onMoreToggleClickBind = null; - this._onMenuButtonClickBind = null; - } - - prepare() { - this._contentNode = document.querySelector('.content'); - this._menuContainer = document.querySelector('#popup-menus'); - - const onFabButtonClick = this._onFabButtonClick.bind(this); - for (const fabButton of document.querySelectorAll('.fab-button')) { - fabButton.addEventListener('click', onFabButtonClick, false); - } - - const onModalAction = this._onModalAction.bind(this); - for (const node of document.querySelectorAll('[data-modal-action]')) { - node.addEventListener('click', onModalAction, false); - } - - const onSelectOnClickElementClick = this._onSelectOnClickElementClick.bind(this); - for (const node of document.querySelectorAll('[data-select-on-click]')) { - node.addEventListener('click', onSelectOnClickElementClick, false); - } - - const onInputTabActionKeyDown = this._onInputTabActionKeyDown.bind(this); - for (const node of document.querySelectorAll('[data-tab-action]')) { - node.addEventListener('keydown', onInputTabActionKeyDown, false); - } - - const onSpecialUrlLinkClick = this._onSpecialUrlLinkClick.bind(this); - const onSpecialUrlLinkMouseDown = this._onSpecialUrlLinkMouseDown.bind(this); - for (const node of document.querySelectorAll('[data-special-url]')) { - node.addEventListener('click', onSpecialUrlLinkClick, false); - node.addEventListener('auxclick', onSpecialUrlLinkClick, false); - node.addEventListener('mousedown', onSpecialUrlLinkMouseDown, false); - } - - for (const node of document.querySelectorAll('.defer-load-iframe')) { - this._setupDeferLoadIframe(node); - } - - this._onMoreToggleClickBind = this._onMoreToggleClick.bind(this); - const moreSelectorObserver = new SelectorObserver({ - selector: '.more-toggle', - onAdded: this._onMoreSetup.bind(this), - onRemoved: this._onMoreCleanup.bind(this) - }); - moreSelectorObserver.observe(document.documentElement, false); - - this._onMenuButtonClickBind = this._onMenuButtonClick.bind(this); - const menuSelectorObserver = new SelectorObserver({ - selector: '[data-menu]', - onAdded: this._onMenuSetup.bind(this), - onRemoved: this._onMenuCleanup.bind(this) - }); - menuSelectorObserver.observe(document.documentElement, false); - - window.addEventListener('keydown', this._onKeyDown.bind(this), false); - window.addEventListener('popstate', this._onPopState.bind(this), false); - this._updateScrollTarget(); - } - - // Private - - _onMoreSetup(element) { - element.addEventListener('click', this._onMoreToggleClickBind, false); - return null; - } - - _onMoreCleanup(element) { - element.removeEventListener('click', this._onMoreToggleClickBind, false); - } - - _onMenuSetup(element) { - element.addEventListener('click', this._onMenuButtonClickBind, false); - return null; - } - - _onMenuCleanup(element) { - element.removeEventListener('click', this._onMenuButtonClickBind, false); - } - - _onMenuButtonClick(e) { - const element = e.currentTarget; - const {menu} = element.dataset; - this._showMenu(element, menu); - } - - _onFabButtonClick(e) { - const action = e.currentTarget.dataset.action; - switch (action) { - case 'toggle-sidebar': - document.body.classList.toggle('sidebar-visible'); - break; - case 'toggle-preview-sidebar': - document.body.classList.toggle('preview-sidebar-visible'); - break; - } - } - - _onMoreToggleClick(e) { - const container = this._getMoreContainer(e.currentTarget); - if (container === null) { return; } - - const more = container.querySelector('.more'); - if (more === null) { return; } - - const moreVisible = more.hidden; - more.hidden = !moreVisible; - for (const moreToggle of container.querySelectorAll('.more-toggle')) { - const container2 = this._getMoreContainer(moreToggle); - if (container2 === null) { continue; } - - const more2 = container2.querySelector('.more'); - if (more2 === null || more2 !== more) { continue; } - - moreToggle.dataset.expanded = `${moreVisible}`; - } - - e.preventDefault(); - return false; - } - - _onPopState() { - this._updateScrollTarget(); - } - - _onKeyDown(e) { - switch (e.code) { - case 'Escape': - if (!this._isElementAnInput(document.activeElement)) { - this._closeTopMenuOrModal(); - e.preventDefault(); - } - break; - } - } - - _onModalAction(e) { - const node = e.currentTarget; - const {modalAction} = node.dataset; - if (typeof modalAction !== 'string') { return; } - - let [action, target] = modalAction.split(','); - if (typeof target === 'undefined') { - const currentModal = node.closest('.modal'); - if (currentModal === null) { return; } - target = currentModal; - } - - const modal = this._modalController.getModal(target); - if (modal === null) { return; } - - switch (action) { - case 'show': - modal.setVisible(true); - break; - case 'hide': - modal.setVisible(false); - break; - case 'toggle': - modal.setVisible(!modal.isVisible()); - break; - } - - e.preventDefault(); - } - - _onSelectOnClickElementClick(e) { - if (e.button !== 0) { return; } - - const node = e.currentTarget; - const range = document.createRange(); - range.selectNode(node); - - const selection = window.getSelection(); - selection.removeAllRanges(); - selection.addRange(range); - - e.preventDefault(); - e.stopPropagation(); - return false; - } - - _onInputTabActionKeyDown(e) { - if (e.key !== 'Tab' || e.ctrlKey) { return; } - - const node = e.currentTarget; - const {tabAction} = node.dataset; - if (typeof tabAction !== 'string') { return; } - - const args = tabAction.split(','); - switch (args[0]) { - case 'ignore': - e.preventDefault(); - break; - case 'indent': - e.preventDefault(); - this._indentInput(e, node, args); - break; - } - } - - _onSpecialUrlLinkClick(e) { - switch (e.button) { - case 0: - case 1: - e.preventDefault(); - this._createTab(e.currentTarget.dataset.specialUrl, true); - break; - } - } - - _onSpecialUrlLinkMouseDown(e) { - switch (e.button) { - case 0: - case 1: - e.preventDefault(); - break; - } - } - - async _createTab(url, useOpener) { - let openerTabId; - if (useOpener) { - try { - const tab = await new Promise((resolve, reject) => { - chrome.tabs.getCurrent((result) => { - const e = chrome.runtime.lastError; - if (e) { - reject(new Error(e.message)); - } else { - resolve(result); - } - }); - }); - openerTabId = tab.id; - } catch (e) { - // NOP - } - } - - return await new Promise((resolve, reject) => { - chrome.tabs.create({url, openerTabId}, (tab2) => { - const e = chrome.runtime.lastError; - if (e) { - reject(new Error(e.message)); - } else { - resolve(tab2); - } - }); - }); - } - - _updateScrollTarget() { - const hash = window.location.hash; - if (!hash.startsWith('#!')) { return; } - - const content = this._contentNode; - const target = document.getElementById(hash.substring(2)); - if (content === null || target === null) { return; } - - const rect1 = content.getBoundingClientRect(); - const rect2 = target.getBoundingClientRect(); - content.scrollTop += rect2.top - rect1.top; - } - - _getMoreContainer(link) { - const v = link.dataset.parentDistance; - const distance = v ? parseInt(v, 10) : 1; - if (Number.isNaN(distance)) { return null; } - - for (let i = 0; i < distance; ++i) { - link = link.parentNode; - if (link === null) { break; } - } - return link; - } - - _closeTopMenuOrModal() { - for (const popupMenu of PopupMenu.openMenus) { - popupMenu.close(); - return; - } - - const modal = this._modalController.getTopVisibleModal(); - if (modal !== null) { - modal.setVisible(false); - } - } - - _showMenu(element, menuName) { - const menu = this._settingsController.instantiateTemplate(menuName); - if (menu === null) { return; } - - this._menuContainer.appendChild(menu); - - const popupMenu = new PopupMenu(element, menu); - popupMenu.prepare(); - } - - _indentInput(e, node, args) { - let indent = '\t'; - if (args.length > 1) { - const count = parseInt(args[1], 10); - indent = (Number.isFinite(count) && count >= 0 ? ' '.repeat(count) : args[1]); - } - - const {selectionStart: start, selectionEnd: end, value} = node; - const lineStart = value.substring(0, start).lastIndexOf('\n') + 1; - const lineWhitespace = /^[ \t]*/.exec(value.substring(lineStart))[0]; - - if (e.shiftKey) { - const whitespaceLength = Math.max(0, Math.floor((lineWhitespace.length - 1) / 4) * 4); - const selectionStartNew = lineStart + whitespaceLength; - const selectionEndNew = lineStart + lineWhitespace.length; - const removeCount = selectionEndNew - selectionStartNew; - if (removeCount > 0) { - node.selectionStart = selectionStartNew; - node.selectionEnd = selectionEndNew; - document.execCommand('delete', false); - node.selectionStart = Math.max(lineStart, start - removeCount); - node.selectionEnd = Math.max(lineStart, end - removeCount); - } - } else { - if (indent.length > 0) { - const indentLength = (Math.ceil((start - lineStart + 1) / indent.length) * indent.length - (start - lineStart)); - document.execCommand('insertText', false, indent.substring(0, indentLength)); - } - } - } - - _isElementAnInput(element) { - const type = element !== null ? element.nodeName.toUpperCase() : null; - switch (type) { - case 'INPUT': - case 'TEXTAREA': - case 'SELECT': - return true; - default: - return false; - } - } - - _setupDeferLoadIframe(element) { - const parent = this._getMoreContainer(element); - if (parent === null) { return; } - - let mutationObserver = null; - const callback = () => { - if (!this._isElementVisible(element)) { return false; } - - const src = element.dataset.src; - delete element.dataset.src; - element.src = src; - - if (mutationObserver === null) { return true; } - - mutationObserver.disconnect(); - mutationObserver = null; - return true; - }; - - if (callback()) { return; } - - mutationObserver = new MutationObserver(callback); - mutationObserver.observe(parent, {attributes: true}); - } - - _isElementVisible(element) { - return (element.offsetParent !== null); - } -} diff --git a/ext/bg/js/settings2/settings-main.js b/ext/bg/js/settings2/settings-main.js deleted file mode 100644 index 24248110..00000000 --- a/ext/bg/js/settings2/settings-main.js +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2020-2021 Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -/* global - * AnkiController - * AnkiTemplatesController - * AudioController - * BackupController - * DictionaryController - * DictionaryImportController - * DocumentFocusController - * ExtensionKeyboardShortcutController - * GenericSettingController - * KeyboardShortcutController - * MecabController - * ModalController - * NestedPopupsController - * PermissionsToggleController - * PopupPreviewController - * PopupWindowController - * ProfileController - * ScanInputsController - * ScanInputsSimpleController - * SecondarySearchDictionaryController - * SentenceTerminationCharactersController - * SettingsController - * SettingsDisplayController - * StatusFooter - * StorageController - * TranslationTextReplacementsController - * api - */ - -async function setupEnvironmentInfo() { - const {manifest_version: manifestVersion} = chrome.runtime.getManifest(); - const {browser, platform} = await api.getEnvironmentInfo(); - document.documentElement.dataset.browser = browser; - document.documentElement.dataset.os = platform.os; - document.documentElement.dataset.manifestVersion = `${manifestVersion}`; -} - -async function setupGenericSettingsController(genericSettingController) { - await genericSettingController.prepare(); - await genericSettingController.refresh(); -} - -(async () => { - try { - const documentFocusController = new DocumentFocusController(); - documentFocusController.prepare(); - - const statusFooter = new StatusFooter(document.querySelector('.status-footer-container')); - statusFooter.prepare(); - - api.forwardLogsToBackend(); - await yomichan.prepare(); - - setupEnvironmentInfo(); - - const optionsFull = await api.optionsGetFull(); - - const preparePromises = []; - - const modalController = new ModalController(); - modalController.prepare(); - - const settingsController = new SettingsController(optionsFull.profileCurrent); - settingsController.prepare(); - - const storageController = new StorageController(); - storageController.prepare(); - - const dictionaryController = new DictionaryController(settingsController, modalController, storageController, statusFooter); - dictionaryController.prepare(); - - const dictionaryImportController = new DictionaryImportController(settingsController, modalController, storageController, statusFooter); - dictionaryImportController.prepare(); - - const genericSettingController = new GenericSettingController(settingsController); - preparePromises.push(setupGenericSettingsController(genericSettingController)); - - const audioController = new AudioController(settingsController); - audioController.prepare(); - - const profileController = new ProfileController(settingsController, modalController); - profileController.prepare(); - - const settingsBackup = new BackupController(settingsController, modalController); - settingsBackup.prepare(); - - const ankiController = new AnkiController(settingsController); - ankiController.prepare(); - - const ankiTemplatesController = new AnkiTemplatesController(settingsController, modalController, ankiController); - ankiTemplatesController.prepare(); - - const popupPreviewController = new PopupPreviewController(settingsController); - popupPreviewController.prepare(); - - const scanInputsController = new ScanInputsController(settingsController); - scanInputsController.prepare(); - - const simpleScanningInputController = new ScanInputsSimpleController(settingsController); - simpleScanningInputController.prepare(); - - const nestedPopupsController = new NestedPopupsController(settingsController); - nestedPopupsController.prepare(); - - const permissionsToggleController = new PermissionsToggleController(settingsController); - permissionsToggleController.prepare(); - - const secondarySearchDictionaryController = new SecondarySearchDictionaryController(settingsController); - secondarySearchDictionaryController.prepare(); - - const translationTextReplacementsController = new TranslationTextReplacementsController(settingsController); - translationTextReplacementsController.prepare(); - - const sentenceTerminationCharactersController = new SentenceTerminationCharactersController(settingsController); - sentenceTerminationCharactersController.prepare(); - - const keyboardShortcutController = new KeyboardShortcutController(settingsController); - keyboardShortcutController.prepare(); - - const extensionKeyboardShortcutController = new ExtensionKeyboardShortcutController(settingsController); - extensionKeyboardShortcutController.prepare(); - - const popupWindowController = new PopupWindowController(); - popupWindowController.prepare(); - - const mecabController = new MecabController(); - mecabController.prepare(); - - await Promise.all(preparePromises); - - document.documentElement.dataset.loaded = 'true'; - - const settingsDisplayController = new SettingsDisplayController(settingsController, modalController); - settingsDisplayController.prepare(); - } catch (e) { - yomichan.logError(e); - } -})(); diff --git a/ext/bg/js/settings2/translation-text-replacements-controller.js b/ext/bg/js/settings2/translation-text-replacements-controller.js deleted file mode 100644 index 8d13f7e9..00000000 --- a/ext/bg/js/settings2/translation-text-replacements-controller.js +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (C) 2021 Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -class TranslationTextReplacementsController { - constructor(settingsController) { - this._settingsController = settingsController; - this._entryContainer = null; - this._entries = []; - } - - async prepare() { - this._entryContainer = document.querySelector('#translation-text-replacement-list'); - const addButton = document.querySelector('#translation-text-replacement-add'); - - addButton.addEventListener('click', this._onAdd.bind(this), false); - this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this)); - - await this._updateOptions(); - } - - - async addGroup() { - const options = await this._settingsController.getOptions(); - const {groups} = options.translation.textReplacements; - const newEntry = this._createNewEntry(); - const target = ( - (groups.length === 0) ? - { - action: 'splice', - path: 'translation.textReplacements.groups', - start: 0, - deleteCount: 0, - items: [[newEntry]] - } : - { - action: 'splice', - path: 'translation.textReplacements.groups[0]', - start: groups[0].length, - deleteCount: 0, - items: [newEntry] - } - ); - - await this._settingsController.modifyProfileSettings([target]); - await this._updateOptions(); - } - - async deleteGroup(index) { - const options = await this._settingsController.getOptions(); - const {groups} = options.translation.textReplacements; - if (groups.length === 0) { return false; } - - const group0 = groups[0]; - if (index < 0 || index >= group0.length) { return false; } - - const target = ( - (group0.length > 1) ? - { - action: 'splice', - path: 'translation.textReplacements.groups[0]', - start: index, - deleteCount: 1, - items: [] - } : - { - action: 'splice', - path: 'translation.textReplacements.groups', - start: 0, - deleteCount: group0.length, - items: [] - } - ); - - await this._settingsController.modifyProfileSettings([target]); - await this._updateOptions(); - return true; - } - - // Private - - _onOptionsChanged({options}) { - for (const entry of this._entries) { - entry.cleanup(); - } - this._entries = []; - - const {groups} = options.translation.textReplacements; - if (groups.length > 0) { - const group0 = groups[0]; - for (let i = 0, ii = group0.length; i < ii; ++i) { - const data = group0[i]; - const node = this._settingsController.instantiateTemplate('translation-text-replacement-entry'); - this._entryContainer.appendChild(node); - const entry = new TranslationTextReplacementsEntry(this, node, i, data); - this._entries.push(entry); - entry.prepare(); - } - } - } - - _onAdd() { - this.addGroup(); - } - - async _updateOptions() { - const options = await this._settingsController.getOptions(); - this._onOptionsChanged({options}); - } - - _createNewEntry() { - return {pattern: '', ignoreCase: false, replacement: ''}; - } -} - -class TranslationTextReplacementsEntry { - constructor(parent, node, index) { - this._parent = parent; - this._node = node; - this._index = index; - this._eventListeners = new EventListenerCollection(); - this._patternInput = null; - this._replacementInput = null; - this._ignoreCaseToggle = null; - this._testInput = null; - this._testOutput = null; - } - - prepare() { - const patternInput = this._node.querySelector('.translation-text-replacement-pattern'); - const replacementInput = this._node.querySelector('.translation-text-replacement-replacement'); - const ignoreCaseToggle = this._node.querySelector('.translation-text-replacement-pattern-ignore-case'); - const menuButton = this._node.querySelector('.translation-text-replacement-button'); - const testInput = this._node.querySelector('.translation-text-replacement-test-input'); - const testOutput = this._node.querySelector('.translation-text-replacement-test-output'); - - this._patternInput = patternInput; - this._replacementInput = replacementInput; - this._ignoreCaseToggle = ignoreCaseToggle; - this._testInput = testInput; - this._testOutput = testOutput; - - const pathBase = `translation.textReplacements.groups[0][${this._index}]`; - patternInput.dataset.setting = `${pathBase}.pattern`; - replacementInput.dataset.setting = `${pathBase}.replacement`; - ignoreCaseToggle.dataset.setting = `${pathBase}.ignoreCase`; - - this._eventListeners.addEventListener(menuButton, 'menuOpen', this._onMenuOpen.bind(this), false); - this._eventListeners.addEventListener(menuButton, 'menuClose', this._onMenuClose.bind(this), false); - this._eventListeners.addEventListener(patternInput, 'settingChanged', this._onPatternChanged.bind(this), false); - this._eventListeners.addEventListener(ignoreCaseToggle, 'settingChanged', this._updateTestInput.bind(this), false); - this._eventListeners.addEventListener(replacementInput, 'settingChanged', this._updateTestInput.bind(this), false); - this._eventListeners.addEventListener(testInput, 'input', this._updateTestInput.bind(this), false); - } - - cleanup() { - this._eventListeners.removeAllEventListeners(); - if (this._node.parentNode !== null) { - this._node.parentNode.removeChild(this._node); - } - } - - // Private - - _onMenuOpen(e) { - const bodyNode = e.detail.menu.bodyNode; - const testVisible = this._isTestVisible(); - bodyNode.querySelector('[data-menu-action=showTest]').hidden = testVisible; - bodyNode.querySelector('[data-menu-action=hideTest]').hidden = !testVisible; - } - - _onMenuClose(e) { - switch (e.detail.action) { - case 'remove': - this._parent.deleteGroup(this._index); - break; - case 'showTest': - this._setTestVisible(true); - break; - case 'hideTest': - this._setTestVisible(false); - break; - } - } - - _onPatternChanged({detail: {value}}) { - this._validatePattern(value); - this._updateTestInput(); - } - - _validatePattern(value) { - let okay = false; - try { - new RegExp(value, 'g'); - okay = true; - } catch (e) { - // NOP - } - - this._patternInput.dataset.invalid = `${!okay}`; - } - - _isTestVisible() { - return this._node.dataset.testVisible === 'true'; - } - - _setTestVisible(visible) { - this._node.dataset.testVisible = `${visible}`; - this._updateTestInput(); - } - - _updateTestInput() { - if (!this._isTestVisible()) { return; } - - const ignoreCase = this._ignoreCaseToggle.checked; - const pattern = this._patternInput.value; - let regex; - try { - regex = new RegExp(pattern, ignoreCase ? 'gi' : 'g'); - } catch (e) { - return; - } - - const replacement = this._replacementInput.value; - const input = this._testInput.value; - const output = input.replace(regex, replacement); - this._testOutput.value = output; - } -} |