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 {
constructor(popup, ignoreNodes) {
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.optionsContext = {
@ -138,7 +145,6 @@ class Frontend {
let results = null;
try {
this.textScanner.pendingLookup = true;
if (textSource !== null) {
results = (
await this.findTerms(textSource) ||
@ -165,8 +171,6 @@ class Frontend {
if (results === null && this.options.scanning.autoHideResults) {
this.searchClear(true);
}
this.textScanner.pendingLookup = false;
}
return results;
@ -182,7 +186,6 @@ class Frontend {
{definitions, context: {sentence, url, focus, disableHistory: true}}
);
this.textScanner.setCurrentTextSource(textSource);
if (this.options.scanning.selectText) {
textSource.select();
}

View File

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