summaryrefslogtreecommitdiff
path: root/ext/mixed
diff options
context:
space:
mode:
Diffstat (limited to 'ext/mixed')
-rw-r--r--ext/mixed/js/display.js3
-rw-r--r--ext/mixed/js/document-util.js25
-rw-r--r--ext/mixed/js/text-scanner.js88
3 files changed, 79 insertions, 37 deletions
diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js
index 70b3895a..ea6b52c0 100644
--- a/ext/mixed/js/display.js
+++ b/ext/mixed/js/display.js
@@ -239,10 +239,9 @@ class Display extends EventDispatcher {
selectedParser: options.parsing.selectedParser,
termSpacing: options.parsing.termSpacing,
scanning: {
+ inputs: scanning.inputs,
deepContentScan: scanning.deepDomScan,
selectText: scanning.selectText,
- modifier: scanning.modifier,
- useMiddleMouse: scanning.middleMouse,
delay: scanning.delay,
touchInputEnabled: scanning.touchInputEnabled,
scanLength: scanning.length,
diff --git a/ext/mixed/js/document-util.js b/ext/mixed/js/document-util.js
index 0b72ff9a..58b0c759 100644
--- a/ext/mixed/js/document-util.js
+++ b/ext/mixed/js/document-util.js
@@ -188,6 +188,18 @@ class DocumentUtil {
return modifiers;
}
+ static getActiveModifiersAndButtons(event) {
+ const modifiers = this.getActiveModifiers(event);
+ this._getActiveButtons(event, modifiers);
+ return modifiers;
+ }
+
+ static getActiveButtons(event) {
+ const buttons = new Set();
+ this._getActiveButtons(event, buttons);
+ return buttons;
+ }
+
static getKeyFromEvent(event) {
const key = event.key;
return (typeof key === 'string' ? (key.length === 1 ? key.toUpperCase() : key) : '');
@@ -299,6 +311,19 @@ class DocumentUtil {
return !(browser === 'firefox' || browser === 'firefox-mobile') || os === 'mac';
}
+ static _getActiveButtons(event, set) {
+ const {buttons} = event;
+ if (typeof buttons === 'number') {
+ for (let i = 0; i < 6; ++i) {
+ const buttonFlag = (1 << i);
+ if ((buttons & buttonFlag) !== 0) {
+ set.add(`mouse${i}`);
+ }
+ }
+ }
+ return set;
+ }
+
// Private
_setImposterStyle(style, propertyName, value) {
diff --git a/ext/mixed/js/text-scanner.js b/ext/mixed/js/text-scanner.js
index f3e99577..6eafc82c 100644
--- a/ext/mixed/js/text-scanner.js
+++ b/ext/mixed/js/text-scanner.js
@@ -43,13 +43,12 @@ class TextScanner extends EventDispatcher {
this._deepContentScan = false;
this._selectText = false;
- this._modifier = 'none';
- this._useMiddleMouse = false;
this._delay = 0;
this._touchInputEnabled = false;
this._scanLength = 1;
this._sentenceExtent = 1;
this._layoutAwareScan = false;
+ this._inputs = [];
this._enabled = false;
this._eventListeners = new EventListenerCollection();
@@ -94,19 +93,19 @@ class TextScanner extends EventDispatcher {
}
}
- setOptions({deepContentScan, selectText, modifier, useMiddleMouse, delay, touchInputEnabled, scanLength, sentenceExtent, layoutAwareScan}) {
+ setOptions({inputs, deepContentScan, selectText, delay, touchInputEnabled, scanLength, sentenceExtent, layoutAwareScan}) {
+ if (Array.isArray(inputs)) {
+ this._inputs = inputs.map(({include, exclude}) => ({
+ include: this._getInputArray(include),
+ exclude: this._getInputArray(exclude)
+ }));
+ }
if (typeof deepContentScan === 'boolean') {
this._deepContentScan = deepContentScan;
}
if (typeof selectText === 'boolean') {
this._selectText = selectText;
}
- if (typeof modifier === 'string') {
- this._modifier = modifier;
- }
- if (typeof useMiddleMouse === 'boolean') {
- this._useMiddleMouse = useMiddleMouse;
- }
if (typeof delay === 'number') {
this._delay = delay;
}
@@ -184,7 +183,7 @@ class TextScanner extends EventDispatcher {
}
async search(textSource) {
- return await this._search(textSource, {cause: 'script'});
+ return await this._search(textSource, {cause: 'script', index: -1, empty: false});
}
// Private
@@ -242,17 +241,14 @@ class TextScanner extends EventDispatcher {
return;
}
- const modifiers = DocumentUtil.getActiveModifiers(e);
+ const modifiers = DocumentUtil.getActiveModifiersAndButtons(e);
this.trigger('activeModifiersChanged', {modifiers});
- if (!(
- this._isScanningModifierPressed(this._modifier, e) ||
- (this._useMiddleMouse && DocumentUtil.isMouseButtonDown(e, 'auxiliary'))
- )) {
- return;
- }
+ const inputInfo = this._getMatchingInputGroup(modifiers);
+ if (inputInfo === null) { return; }
- this._searchAtFromMouse(e.clientX, e.clientY);
+ const {index, empty} = inputInfo;
+ this._searchAtFromMouse(e.clientX, e.clientY, index, empty);
}
_onMouseDown(e) {
@@ -276,7 +272,7 @@ class TextScanner extends EventDispatcher {
_onClick(e) {
if (this._searchOnClick) {
- this._searchAt(e.clientX, e.clientY, {cause: 'click'});
+ this._searchAt(e.clientX, e.clientY, {cause: 'click', index: -1, empty: false});
}
if (this._preventNextClick) {
@@ -349,7 +345,7 @@ class TextScanner extends EventDispatcher {
return;
}
- this._searchAt(primaryTouch.clientX, primaryTouch.clientY, {cause: 'touchMove'});
+ this._searchAt(primaryTouch.clientX, primaryTouch.clientY, {cause: 'touchMove', index: -1, empty: false});
e.preventDefault(); // Disable scroll
}
@@ -406,17 +402,6 @@ class TextScanner extends EventDispatcher {
];
}
- _isScanningModifierPressed(scanningModifier, mouseEvent) {
- switch (scanningModifier) {
- case 'alt': return mouseEvent.altKey;
- case 'ctrl': return mouseEvent.ctrlKey;
- case 'shift': return mouseEvent.shiftKey;
- case 'meta': return mouseEvent.metaKey;
- case 'none': return true;
- default: return false;
- }
- }
-
_getTouch(touchList, identifier) {
for (const touch of touchList) {
if (touch.identifier === identifier) {
@@ -498,17 +483,17 @@ class TextScanner extends EventDispatcher {
}
}
- async _searchAtFromMouse(x, y) {
+ async _searchAtFromMouse(x, y, inputIndex, inputEmpty) {
if (this._pendingLookup) { return; }
- if (this._modifier === 'none') {
+ if (inputEmpty) {
if (!await this._scanTimerWait()) {
// Aborted
return;
}
}
- await this._searchAt(x, y, {cause: 'mouse'});
+ await this._searchAt(x, y, {cause: 'mouse', index: inputIndex, empty: inputEmpty});
}
async _searchAtFromTouchStart(x, y) {
@@ -516,7 +501,7 @@ class TextScanner extends EventDispatcher {
const textSourceCurrentPrevious = this._textSourceCurrent !== null ? this._textSourceCurrent.clone() : null;
- await this._searchAt(x, y, {cause: 'touchStart'});
+ await this._searchAt(x, y, {cause: 'touchStart', index: -1, empty: false});
if (
this._textSourceCurrent !== null &&
@@ -527,4 +512,37 @@ class TextScanner extends EventDispatcher {
this._preventNextMouseDown = true;
}
}
+
+ _getMatchingInputGroup(modifiers) {
+ let fallback = null;
+ for (let i = 0, ii = this._inputs.length; i < ii; ++i) {
+ const input = this._inputs[i];
+ const {include, exclude} = input;
+ if (this._setHasAll(modifiers, include) && (exclude.length === 0 || !this._setHasAll(modifiers, exclude))) {
+ if (include.length > 0) {
+ return {index: i, empty: false, input};
+ } else if (fallback === null) {
+ fallback = {index: i, empty: true, input};
+ }
+ }
+ }
+ return fallback;
+ }
+
+ _setHasAll(set, values) {
+ for (const value of values) {
+ if (!set.has(value)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ _getInputArray(value) {
+ return (
+ typeof value === 'string' ?
+ value.split(/[,;\s]+/).map((v) => v.trim().toLowerCase()).filter((v) => v.length > 0) :
+ []
+ );
+ }
}