aboutsummaryrefslogtreecommitdiff
path: root/ext/bg/js/settings2
diff options
context:
space:
mode:
Diffstat (limited to 'ext/bg/js/settings2')
-rw-r--r--ext/bg/js/settings2/extension-keyboard-shortcuts-controller.js292
-rw-r--r--ext/bg/js/settings2/keyboard-shortcuts-controller.js368
-rw-r--r--ext/bg/js/settings2/mecab-controller.js67
-rw-r--r--ext/bg/js/settings2/nested-popups-controller.js71
-rw-r--r--ext/bg/js/settings2/popup-window-controller.js38
-rw-r--r--ext/bg/js/settings2/secondary-search-dictionary-controller.js73
-rw-r--r--ext/bg/js/settings2/sentence-termination-characters-controller.js243
-rw-r--r--ext/bg/js/settings2/settings-display-controller.js400
-rw-r--r--ext/bg/js/settings2/settings-main.js156
-rw-r--r--ext/bg/js/settings2/translation-text-replacements-controller.js242
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;
- }
-}