summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2020-10-14 19:37:46 -0400
committertoasted-nutbread <toasted-nutbread@users.noreply.github.com>2020-10-14 19:43:48 -0400
commitcb566f015aa280499da94126a3f6336c4d8ce0df (patch)
tree91e57b9b1b055c682ab95bafede1b1288885ea5f /ext
parentfd945a2119a0bba22c84b77dae1ec829e7495a83 (diff)
Add simple scan input UI (#921)
* Add simple scan input UI * Create helper function * Add controller for old scanning input UI * Add refresh functions * Add abstraction function * Fix incomplete middle mouse support detection * Make scanning inputs update eachother * Fix global declaration order
Diffstat (limited to 'ext')
-rw-r--r--ext/bg/css/settings.css1
-rw-r--r--ext/bg/js/settings/main.js4
-rw-r--r--ext/bg/js/settings/scan-inputs-controller.js58
-rw-r--r--ext/bg/js/settings/scan-inputs-simple-controller.js221
-rw-r--r--ext/bg/settings.html12
5 files changed, 276 insertions, 20 deletions
diff --git a/ext/bg/css/settings.css b/ext/bg/css/settings.css
index 4a49b98d..8d6a3911 100644
--- a/ext/bg/css/settings.css
+++ b/ext/bg/css/settings.css
@@ -23,6 +23,7 @@
html:root:not([data-options-anki-enable=true]) #anki-general,
html:root:not([data-options-general-debug-info=true]) .debug,
html:root:not([data-options-general-show-advanced=true]) .options-advanced,
+html:root[data-options-general-show-advanced=true] .options-non-advanced,
html:root:not([data-options-general-result-output-mode=merge]) #dict-main-group {
display: none;
}
diff --git a/ext/bg/js/settings/main.js b/ext/bg/js/settings/main.js
index 37c6375d..382487eb 100644
--- a/ext/bg/js/settings/main.js
+++ b/ext/bg/js/settings/main.js
@@ -27,6 +27,7 @@
* PopupPreviewController
* ProfileController
* ScanInputsController
+ * ScanInputsSimpleController
* SettingsController
* StorageController
* api
@@ -96,6 +97,9 @@ async function setupEnvironmentInfo() {
const scanInputsController = new ScanInputsController(settingsController);
scanInputsController.prepare();
+ const simpleScanningInputController = new ScanInputsSimpleController(settingsController);
+ simpleScanningInputController.prepare();
+
yomichan.ready();
} catch (e) {
yomichan.logError(e);
diff --git a/ext/bg/js/settings/scan-inputs-controller.js b/ext/bg/js/settings/scan-inputs-controller.js
index ec2758cb..fe994aed 100644
--- a/ext/bg/js/settings/scan-inputs-controller.js
+++ b/ext/bg/js/settings/scan-inputs-controller.js
@@ -37,10 +37,10 @@ class ScanInputsController {
this._addButton = document.querySelector('#scan-input-add');
this._addButton.addEventListener('click', this._onAddButtonClick.bind(this), false);
+ this._settingsController.on('scanInputsChanged', this._onScanInputsChanged.bind(this));
this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this));
- const options = await this._settingsController.getOptions();
- this._onOptionsChanged({options});
+ this.refresh();
}
removeInput(index) {
@@ -51,13 +51,14 @@ class ScanInputsController {
for (let i = index, ii = this._entries.length; i < ii; ++i) {
this._entries[i].index = i;
}
- this._settingsController.modifyProfileSettings([{
+ this._modifyProfileSettings([{
action: 'splice',
path: 'scanning.inputs',
start: index,
deleteCount: 1,
items: []
}]);
+ return true;
}
setProperty(index, property, value) {
@@ -65,8 +66,18 @@ class ScanInputsController {
this._settingsController.setProfileSetting(path, value);
}
+ async refresh() {
+ const options = await this._settingsController.getOptions();
+ this._onOptionsChanged({options});
+ }
+
// Private
+ _onScanInputsChanged({source}) {
+ if (source === this) { return; }
+ this.refresh();
+ }
+
_onOptionsChanged({options}) {
const {inputs} = options.scanning;
@@ -88,26 +99,12 @@ class ScanInputsController {
const include = '';
const exclude = '';
this._addOption(index, include, exclude);
- this._settingsController.modifyProfileSettings([{
+ this._modifyProfileSettings([{
action: 'splice',
path: 'scanning.inputs',
start: index,
deleteCount: 0,
- items: [{
- include,
- exclude,
- types: {mouse: true, touch: false, pen: false},
- options: {
- showAdvanced: false,
- searchTerms: true,
- searchKanji: true,
- scanOnTouchMove: true,
- scanOnPenHover: true,
- scanOnPenPress: true,
- scanOnPenRelease: false,
- preventTouchScrolling: true
- }
- }]
+ items: [ScanInputsController.createDefaultMouseInput(include, exclude)]
}]);
}
@@ -116,6 +113,29 @@ class ScanInputsController {
this._entries.push(field);
field.prepare(this._container, include, exclude);
}
+
+ async _modifyProfileSettings(targets) {
+ await this._settingsController.modifyProfileSettings(targets);
+ this._settingsController.trigger('scanInputsChanged', {source: this});
+ }
+
+ static createDefaultMouseInput(include, exclude) {
+ return {
+ include,
+ exclude,
+ types: {mouse: true, touch: false, pen: false},
+ options: {
+ showAdvanced: false,
+ searchTerms: true,
+ searchKanji: true,
+ scanOnTouchMove: true,
+ scanOnPenHover: true,
+ scanOnPenPress: true,
+ scanOnPenRelease: false,
+ preventTouchScrolling: true
+ }
+ };
+ }
}
class ScanInputField {
diff --git a/ext/bg/js/settings/scan-inputs-simple-controller.js b/ext/bg/js/settings/scan-inputs-simple-controller.js
new file mode 100644
index 00000000..636fd102
--- /dev/null
+++ b/ext/bg/js/settings/scan-inputs-simple-controller.js
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2020 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
+ * DocumentUtil
+ * ScanInputsController
+ * api
+ */
+
+class ScanInputsSimpleController {
+ constructor(settingsController) {
+ this._settingsController = settingsController;
+ this._middleMouseButtonScan = null;
+ this._mainScanModifierKeyInput = null;
+ }
+
+ async prepare() {
+ this._middleMouseButtonScan = document.querySelector('#middle-mouse-button-scan');
+ this._mainScanModifierKeyInput = document.querySelector('#main-scan-modifier-key');
+
+ const {platform: {os}} = await api.getEnvironmentInfo();
+ this._populateSelect(this._mainScanModifierKeyInput, os);
+
+ const options = await this._settingsController.getOptions();
+
+ this._middleMouseButtonScan.addEventListener('change', this.onMiddleMouseButtonScanChange.bind(this), false);
+ this._mainScanModifierKeyInput.addEventListener('change', this._onMainScanModifierKeyInputChange.bind(this), false);
+
+ this._settingsController.on('scanInputsChanged', this._onScanInputsChanged.bind(this));
+ this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this));
+ this._onOptionsChanged({options});
+ }
+
+ async refresh() {
+ const options = await this._settingsController.getOptions();
+ this._onOptionsChanged({options});
+ }
+
+ // Private
+
+ _onScanInputsChanged({source}) {
+ if (source === this) { return; }
+ this.refresh();
+ }
+
+ _onOptionsChanged({options}) {
+ const {scanning: {inputs}} = options;
+ const middleMouseSupportedIndex = this._getIndexOfMiddleMouseButtonScanInput(inputs);
+ const mainScanInputIndex = this._getIndexOfMainScanInput(inputs);
+
+ let middleMouseSupported = false;
+ if (middleMouseSupportedIndex >= 0) {
+ const includeValues = this._splitValue(inputs[middleMouseSupportedIndex].include);
+ if (includeValues.includes('mouse2')) {
+ middleMouseSupported = true;
+ }
+ }
+
+ let mainScanInput = 'none';
+ if (mainScanInputIndex >= 0) {
+ const includeValues = this._splitValue(inputs[mainScanInputIndex].include);
+ if (includeValues.length > 0) {
+ mainScanInput = includeValues[0];
+ }
+ }
+
+ this._middleMouseButtonScan.checked = middleMouseSupported;
+ this._mainScanModifierKeyInput.value = mainScanInput;
+ }
+
+ onMiddleMouseButtonScanChange(e) {
+ const middleMouseSupported = e.currentTarget.checked;
+ this._setMiddleMouseSuppported(middleMouseSupported);
+ }
+
+ _onMainScanModifierKeyInputChange(e) {
+ const mainScanKey = e.currentTarget.value;
+ const mainScanInputs = (mainScanKey === 'none' ? [] : [mainScanKey]);
+ this._setMainScanInputs(mainScanInputs);
+ }
+
+ _populateSelect(select, os) {
+ const modifierKeys = [
+ {value: 'none', name: 'None'},
+ ...DocumentUtil.getModifierKeys(os).map(([value, name]) => ({value, name}))
+ ];
+
+ const fragment = document.createDocumentFragment();
+ for (const {value, name} of modifierKeys) {
+ const option = document.createElement('option');
+ option.value = value;
+ option.textContent = name;
+ fragment.appendChild(option);
+ }
+ select.textContent = '';
+ select.appendChild(fragment);
+ }
+
+ _splitValue(value) {
+ return value.split(/[,;\s]+/).map((v) => v.trim().toLowerCase()).filter((v) => v.length > 0);
+ }
+
+ async _setMiddleMouseSuppported(value) {
+ // Find target index
+ const options = await this._settingsController.getOptions();
+ const {scanning: {inputs}} = options;
+ const index = this._getIndexOfMiddleMouseButtonScanInput(inputs);
+
+ if (value) {
+ // Add new
+ if (index >= 0) { return; }
+ let insertionPosition = this._getIndexOfMainScanInput(inputs);
+ insertionPosition = (insertionPosition >= 0 ? insertionPosition + 1 : inputs.length);
+ const input = ScanInputsController.createDefaultMouseInput('mouse2', '');
+ await this._modifyProfileSettings([{
+ action: 'splice',
+ path: 'scanning.inputs',
+ start: insertionPosition,
+ deleteCount: 0,
+ items: [input]
+ }]);
+ } else {
+ // Modify existing
+ if (index < 0) { return; }
+ await this._modifyProfileSettings([{
+ action: 'splice',
+ path: 'scanning.inputs',
+ start: index,
+ deleteCount: 1,
+ items: []
+ }]);
+ }
+ }
+
+ async _setMainScanInputs(value) {
+ value = value.join(', ');
+
+ // Find target index
+ const options = await this._settingsController.getOptions();
+ const {scanning: {inputs}} = options;
+ const index = this._getIndexOfMainScanInput(inputs);
+
+ if (index < 0) {
+ // Add new
+ const input = ScanInputsController.createDefaultMouseInput(value, 'mouse0');
+ await this._modifyProfileSettings([{
+ action: 'splice',
+ path: 'scanning.inputs',
+ start: inputs.length,
+ deleteCount: 0,
+ items: [input]
+ }]);
+ } else {
+ // Modify existing
+ await this._modifyProfileSettings([{
+ action: 'set',
+ path: `scanning.inputs[${index}].include`,
+ value
+ }]);
+ }
+ }
+
+ async _modifyProfileSettings(targets) {
+ await this._settingsController.modifyProfileSettings(targets);
+ this._settingsController.trigger('scanInputsChanged', {source: this});
+ }
+
+ _getIndexOfMainScanInput(inputs) {
+ for (let i = 0, ii = inputs.length; i < ii; ++i) {
+ const {include, exclude, types: {mouse}} = inputs[i];
+ if (!mouse) { continue; }
+ const includeValues = this._splitValue(include);
+ const excludeValues = this._splitValue(exclude);
+ if (
+ (
+ includeValues.length === 0 ||
+ (includeValues.length === 1 && !this._isMouseInput(includeValues[0]))
+ ) &&
+ excludeValues.length === 1 &&
+ excludeValues[0] === 'mouse0'
+ ) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ _getIndexOfMiddleMouseButtonScanInput(inputs) {
+ for (let i = 0, ii = inputs.length; i < ii; ++i) {
+ const {include, exclude, types: {mouse}} = inputs[i];
+ if (!mouse) { continue; }
+ const includeValues = this._splitValue(include);
+ const excludeValues = this._splitValue(exclude);
+ if (
+ (includeValues.length === 0 || (includeValues.length === 1 && includeValues.includes('mouse2'))) &&
+ excludeValues.length === 0
+ ) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ _isMouseInput(input) {
+ return /^mouse\d+$/.test(input);
+ }
+} \ No newline at end of file
diff --git a/ext/bg/settings.html b/ext/bg/settings.html
index 86535af4..4b7bd086 100644
--- a/ext/bg/settings.html
+++ b/ext/bg/settings.html
@@ -386,6 +386,10 @@
<div>
<h3>Scanning Options</h3>
+ <div class="checkbox options-non-advanced">
+ <label><input type="checkbox" id="middle-mouse-button-scan"> Middle mouse button scans</label>
+ </div>
+
<div class="checkbox">
<label><input type="checkbox" id="select-matched-text" data-setting="scanning.selectText"> Select matched text</label>
</div>
@@ -442,7 +446,12 @@
<input type="number" min="1" step="1" id="scan-length" class="form-control" data-setting="scanning.length">
</div>
- <div class="form-group">
+ <div class="form-group options-non-advanced">
+ <label for="main-scan-modifier-key">Scan modifier key</label>
+ <select class="form-control" id="main-scan-modifier-key"></select>
+ </div>
+
+ <div class="form-group options-advanced">
<label>Scan inputs</label>
<div class="scan-input-list" id="scan-input-list"></div>
<button class="btn btn-default" id="scan-input-add" title="Add scan input"><span class="glyphicon glyphicon-plus"></span></button>
@@ -1242,6 +1251,7 @@
<script src="/bg/js/settings/popup-preview-controller.js"></script>
<script src="/bg/js/settings/profile-controller.js"></script>
<script src="/bg/js/settings/scan-inputs-controller.js"></script>
+ <script src="/bg/js/settings/scan-inputs-simple-controller.js"></script>
<script src="/bg/js/settings/settings-controller.js"></script>
<script src="/bg/js/settings/storage-controller.js"></script>