scan decoupling

This commit is contained in:
siikamiika 2019-12-05 22:12:43 +02:00
parent 02a34bb4bc
commit e5be42d3de
2 changed files with 73 additions and 28 deletions

View File

@ -20,7 +20,14 @@
class Frontend { class Frontend {
constructor(popup, ignoreNodes) { constructor(popup, ignoreNodes) {
this.popup = popup; this.popup = popup;
this.textScanner = new TextScanner(window, ignoreNodes, this.popup, this.searchSource.bind(this)); this.textScanner = new TextScanner(
window,
ignoreNodes,
[this.popup.container],
[(x, y) => this.popup.containsPoint(x, y)]
);
this.textScanner.subscribe('textSearch', ({textSource, cause}) => this.searchSource(textSource, cause));
this.textScanner.subscribe('searchClear', () => this.searchClear(true));
this.options = null; this.options = null;
this.optionsContext = { this.optionsContext = {
@ -138,7 +145,6 @@ class Frontend {
let results = null; let results = null;
try { try {
this.textScanner.pendingLookup = true;
if (textSource !== null) { if (textSource !== null) {
results = ( results = (
await this.findTerms(textSource) || await this.findTerms(textSource) ||
@ -165,8 +171,6 @@ class Frontend {
if (results === null && this.options.scanning.autoHideResults) { if (results === null && this.options.scanning.autoHideResults) {
this.searchClear(true); this.searchClear(true);
} }
this.textScanner.pendingLookup = false;
} }
return results; return results;
@ -182,7 +186,6 @@ class Frontend {
{definitions, context: {sentence, url, focus, disableHistory: true}} {definitions, context: {sentence, url, focus, disableHistory: true}}
); );
this.textScanner.setCurrentTextSource(textSource);
if (this.options.scanning.selectText) { if (this.options.scanning.selectText) {
textSource.select(); textSource.select();
} }

View File

@ -18,19 +18,23 @@
class TextScanner { class TextScanner {
constructor(node, ignoreNodes, popup, onTextSearch) { constructor(node, ignoreNodes, ignoreElements, ignorePoints) {
this.node = node; this.node = node;
this.ignoreNodes = (Array.isArray(ignoreNodes) && ignoreNodes.length > 0 ? ignoreNodes.join(',') : null); this.ignoreNodes = (Array.isArray(ignoreNodes) && ignoreNodes.length > 0 ? ignoreNodes.join(',') : null);
this.popup = popup; this.ignoreElements = ignoreElements;
this.onTextSearch = onTextSearch; this.ignorePoints = ignorePoints;
this.popupTimerPromise = null; this.scanTimerPromise = null;
this.textSourceCurrent = null; this.textSourceCurrent = null;
this.pendingLookup = false; this.pendingLookup = false;
this.options = null; this.options = null;
this.enabled = false; this.enabled = false;
this.eventListeners = []; this.eventListeners = [];
this.subscribers = {
searchClear: [],
textSearch: []
};
this.primaryTouchIdentifier = null; this.primaryTouchIdentifier = null;
this.preventNextContextMenu = false; this.preventNextContextMenu = false;
@ -40,13 +44,13 @@ class TextScanner {
} }
onMouseOver(e) { onMouseOver(e) {
if (this.popup && e.target === this.popup.container) { if (this.ignoreElements.includes(e.target)) {
this.popupTimerClear(); this.scanTimerClear();
} }
} }
onMouseMove(e) { onMouseMove(e) {
this.popupTimerClear(); this.scanTimerClear();
if (this.pendingLookup || DOM.isMouseButtonDown(e, 'primary')) { if (this.pendingLookup || DOM.isMouseButtonDown(e, 'primary')) {
return; return;
@ -63,7 +67,7 @@ class TextScanner {
const search = async () => { const search = async () => {
if (scanningModifier === 'none') { if (scanningModifier === 'none') {
if (!await this.popupTimerWait()) { if (!await this.scanTimerWait()) {
// Aborted // Aborted
return; return;
} }
@ -84,14 +88,14 @@ class TextScanner {
return false; return false;
} }
if (DOM.isMouseButtonPressed(e, 'primary')) { if (DOM.isMouseButtonDown(e, 'primary')) {
this.popupTimerClear(); this.scanTimerClear();
this.searchClear(); this.onSearchClear();
} }
} }
onMouseOut() { onMouseOut() {
this.popupTimerClear(); this.scanTimerClear();
} }
onClick(e) { onClick(e) {
@ -192,23 +196,55 @@ class TextScanner {
e.preventDefault(); // Disable scroll e.preventDefault(); // Disable scroll
} }
async popupTimerWait() { async onSearchClear() {
this.searchClear();
await this.publish('searchClear', {});
}
async onTextSearch(textSource, cause) {
this.pendingLookup = true;
const results = await this.publish('textSearch', {textSource, cause});
if (results.some((r) => r)) {
this.textSourceCurrent = textSource;
}
this.pendingLookup = false;
}
onError(error) {
logError(error, false);
}
subscribe(eventName, subscriber) {
if (this.subscribers[eventName].includes(subscriber)) { return; }
this.subscribers[eventName].push(subscriber);
}
async publish(eventName, data) {
const results = [];
for (const subscriber of this.subscribers[eventName]) {
const result = await subscriber(data);
results.push(result);
}
return results;
}
async scanTimerWait() {
const delay = this.options.scanning.delay; const delay = this.options.scanning.delay;
const promise = promiseTimeout(delay, true); const promise = promiseTimeout(delay, true);
this.popupTimerPromise = promise; this.scanTimerPromise = promise;
try { try {
return await promise; return await promise;
} finally { } finally {
if (this.popupTimerPromise === promise) { if (this.scanTimerPromise === promise) {
this.popupTimerPromise = null; this.scanTimerPromise = null;
} }
} }
} }
popupTimerClear() { scanTimerClear() {
if (this.popupTimerPromise !== null) { if (this.scanTimerPromise !== null) {
this.popupTimerPromise.resolve(false); this.scanTimerPromise.resolve(false);
this.popupTimerPromise = null; this.scanTimerPromise = null;
} }
} }
@ -223,7 +259,7 @@ class TextScanner {
this.clearEventListeners(); this.clearEventListeners();
this.enabled = false; this.enabled = false;
} }
this.searchClear(); this.onSearchClear();
} }
} }
@ -262,12 +298,18 @@ class TextScanner {
async searchAt(x, y, cause) { async searchAt(x, y, cause) {
try { try {
this.popupTimerClear(); this.scanTimerClear();
if (this.pendingLookup || (this.popup && await this.popup.containsPoint(x, y))) { if (this.pendingLookup) {
return; return;
} }
for (const ignorePointFn of this.ignorePoints) {
if (await ignorePointFn(x, y)) {
return;
}
}
const textSource = docRangeFromPoint(x, y, this.options); const textSource = docRangeFromPoint(x, y, this.options);
if (this.textSourceCurrent !== null && this.textSourceCurrent.equals(textSource)) { if (this.textSourceCurrent !== null && this.textSourceCurrent.equals(textSource)) {
return; return;