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
This commit is contained in:
parent
429e3a5b74
commit
51904761ce
@ -23,6 +23,7 @@
|
|||||||
html:root:not([data-options-anki-enable=true]) #anki-general,
|
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-debug-info=true]) .debug,
|
||||||
html:root:not([data-options-general-show-advanced=true]) .options-advanced,
|
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]) #dictionary-main-group {
|
html:root:not([data-options-general-result-output-mode=merge]) #dictionary-main-group {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
* PopupPreviewController
|
* PopupPreviewController
|
||||||
* ProfileController
|
* ProfileController
|
||||||
* ScanInputsController
|
* ScanInputsController
|
||||||
|
* ScanInputsSimpleController
|
||||||
* SettingsController
|
* SettingsController
|
||||||
* StorageController
|
* StorageController
|
||||||
* api
|
* api
|
||||||
@ -100,6 +101,9 @@ async function setupEnvironmentInfo() {
|
|||||||
const scanInputsController = new ScanInputsController(settingsController);
|
const scanInputsController = new ScanInputsController(settingsController);
|
||||||
scanInputsController.prepare();
|
scanInputsController.prepare();
|
||||||
|
|
||||||
|
const simpleScanningInputController = new ScanInputsSimpleController(settingsController);
|
||||||
|
simpleScanningInputController.prepare();
|
||||||
|
|
||||||
yomichan.ready();
|
yomichan.ready();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
yomichan.logError(e);
|
yomichan.logError(e);
|
||||||
|
@ -37,10 +37,10 @@ class ScanInputsController {
|
|||||||
this._addButton = document.querySelector('#scan-input-add');
|
this._addButton = document.querySelector('#scan-input-add');
|
||||||
|
|
||||||
this._addButton.addEventListener('click', this._onAddButtonClick.bind(this), false);
|
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));
|
this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this));
|
||||||
|
|
||||||
const options = await this._settingsController.getOptions();
|
this.refresh();
|
||||||
this._onOptionsChanged({options});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removeInput(index) {
|
removeInput(index) {
|
||||||
@ -51,13 +51,14 @@ class ScanInputsController {
|
|||||||
for (let i = index, ii = this._entries.length; i < ii; ++i) {
|
for (let i = index, ii = this._entries.length; i < ii; ++i) {
|
||||||
this._entries[i].index = i;
|
this._entries[i].index = i;
|
||||||
}
|
}
|
||||||
this._settingsController.modifyProfileSettings([{
|
this._modifyProfileSettings([{
|
||||||
action: 'splice',
|
action: 'splice',
|
||||||
path: 'scanning.inputs',
|
path: 'scanning.inputs',
|
||||||
start: index,
|
start: index,
|
||||||
deleteCount: 1,
|
deleteCount: 1,
|
||||||
items: []
|
items: []
|
||||||
}]);
|
}]);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
setProperty(index, property, value) {
|
setProperty(index, property, value) {
|
||||||
@ -69,8 +70,18 @@ class ScanInputsController {
|
|||||||
return this._settingsController.instantiateTemplate(name);
|
return this._settingsController.instantiateTemplate(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async refresh() {
|
||||||
|
const options = await this._settingsController.getOptions();
|
||||||
|
this._onOptionsChanged({options});
|
||||||
|
}
|
||||||
|
|
||||||
// Private
|
// Private
|
||||||
|
|
||||||
|
_onScanInputsChanged({source}) {
|
||||||
|
if (source === this) { return; }
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
_onOptionsChanged({options}) {
|
_onOptionsChanged({options}) {
|
||||||
const {inputs} = options.scanning;
|
const {inputs} = options.scanning;
|
||||||
|
|
||||||
@ -92,26 +103,12 @@ class ScanInputsController {
|
|||||||
const include = '';
|
const include = '';
|
||||||
const exclude = '';
|
const exclude = '';
|
||||||
this._addOption(index, include, exclude);
|
this._addOption(index, include, exclude);
|
||||||
this._settingsController.modifyProfileSettings([{
|
this._modifyProfileSettings([{
|
||||||
action: 'splice',
|
action: 'splice',
|
||||||
path: 'scanning.inputs',
|
path: 'scanning.inputs',
|
||||||
start: index,
|
start: index,
|
||||||
deleteCount: 0,
|
deleteCount: 0,
|
||||||
items: [{
|
items: [ScanInputsController.createDefaultMouseInput(include, exclude)]
|
||||||
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
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,6 +117,29 @@ class ScanInputsController {
|
|||||||
this._entries.push(field);
|
this._entries.push(field);
|
||||||
field.prepare(this._container, include, exclude);
|
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 {
|
class ScanInputField {
|
||||||
|
221
ext/bg/js/settings/scan-inputs-simple-controller.js
Normal file
221
ext/bg/js/settings/scan-inputs-simple-controller.js
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -387,6 +387,10 @@
|
|||||||
<div>
|
<div>
|
||||||
<h3>Scanning Options</h3>
|
<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">
|
<div class="checkbox">
|
||||||
<label><input type="checkbox" id="select-matched-text" data-setting="scanning.selectText"> Select matched text</label>
|
<label><input type="checkbox" id="select-matched-text" data-setting="scanning.selectText"> Select matched text</label>
|
||||||
</div>
|
</div>
|
||||||
@ -443,7 +447,12 @@
|
|||||||
<input type="number" min="1" step="1" id="scan-length" class="form-control" data-setting="scanning.length">
|
<input type="number" min="1" step="1" id="scan-length" class="form-control" data-setting="scanning.length">
|
||||||
</div>
|
</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>
|
<label>Scan inputs</label>
|
||||||
<div class="scan-input-list" id="scan-input-list"></div>
|
<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>
|
<button class="btn btn-default" id="scan-input-add" title="Add scan input"><span class="glyphicon glyphicon-plus"></span></button>
|
||||||
@ -1255,6 +1264,7 @@
|
|||||||
<script src="/bg/js/settings/popup-preview-controller.js"></script>
|
<script src="/bg/js/settings/popup-preview-controller.js"></script>
|
||||||
<script src="/bg/js/settings/profile-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-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/settings-controller.js"></script>
|
||||||
<script src="/bg/js/settings/storage-controller.js"></script>
|
<script src="/bg/js/settings/storage-controller.js"></script>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user