From 3949db26d778bc3f593438211b148e8309921542 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Fri, 8 May 2020 19:05:50 -0400 Subject: Text scanner refactor (#517) * Fix return type * Pass search function as a constructor argument * Pass constructor as a details object For consistency with other complex constructors and improved semantics. * Convert _ignorePoints to a single optional function * Organize functions * Rename ignorePoints to ignorePoint --- ext/mixed/js/text-scanner.js | 203 +++++++++++++++++++++---------------------- 1 file changed, 100 insertions(+), 103 deletions(-) (limited to 'ext/mixed/js') diff --git a/ext/mixed/js/text-scanner.js b/ext/mixed/js/text-scanner.js index 2ed6c3b9..b8688b08 100644 --- a/ext/mixed/js/text-scanner.js +++ b/ext/mixed/js/text-scanner.js @@ -22,11 +22,12 @@ */ class TextScanner extends EventDispatcher { - constructor(node, ignoreElements, ignorePoints) { + constructor({node, ignoreElements, ignorePoint, search}) { super(); this._node = node; this._ignoreElements = ignoreElements; - this._ignorePoints = ignorePoints; + this._ignorePoint = ignorePoint; + this._search = search; this._ignoreNodes = null; @@ -69,6 +70,103 @@ class TextScanner extends EventDispatcher { return this._causeCurrent; } + setEnabled(enabled) { + this._eventListeners.removeAllEventListeners(); + this._enabled = enabled; + if (this._enabled) { + this._hookEvents(); + } else { + this.clearSelection(true); + } + } + + setOptions(options) { + this._options = options; + } + + async searchAt(x, y, cause) { + try { + this._scanTimerClear(); + + if (this._pendingLookup) { + return; + } + + if (typeof this._ignorePoint === 'function' && await this._ignorePoint(x, y)) { + return; + } + + const textSource = docRangeFromPoint(x, y, this._options.scanning.deepDomScan); + try { + if (this._textSourceCurrent !== null && this._textSourceCurrent.equals(textSource)) { + return; + } + + this._pendingLookup = true; + const result = await this._search(textSource, cause); + if (result !== null) { + this._causeCurrent = cause; + this.setCurrentTextSource(textSource); + } + this._pendingLookup = false; + } finally { + if (textSource !== null) { + textSource.cleanup(); + } + } + } catch (e) { + yomichan.logError(e); + } + } + + getTextSourceContent(textSource, length) { + const clonedTextSource = textSource.clone(); + + clonedTextSource.setEndOffset(length); + + if (this._ignoreNodes !== null && clonedTextSource.range) { + length = clonedTextSource.text().length; + while (clonedTextSource.range && length > 0) { + const nodes = TextSourceRange.getNodesInRange(clonedTextSource.range); + if (!TextSourceRange.anyNodeMatchesSelector(nodes, this._ignoreNodes)) { + break; + } + --length; + clonedTextSource.setEndOffset(length); + } + } + + return clonedTextSource.text(); + } + + clearSelection(passive) { + if (!this._canClearSelection) { return; } + if (this._textSourceCurrent !== null) { + if (this._textSourceCurrentSelected) { + this._textSourceCurrent.deselect(); + } + this._textSourceCurrent = null; + this._textSourceCurrentSelected = false; + } + this.trigger('clearSelection', {passive}); + } + + getCurrentTextSource() { + return this._textSourceCurrent; + } + + setCurrentTextSource(textSource) { + this._textSourceCurrent = textSource; + if (this._options.scanning.selectText) { + this._textSourceCurrent.select(); + this._textSourceCurrentSelected = true; + } else { + this._textSourceCurrentSelected = false; + } + } + + // Private + _onMouseOver(e) { if (this._ignoreElements().includes(e.target)) { this._scanTimerClear(); @@ -221,10 +319,6 @@ class TextScanner extends EventDispatcher { e.preventDefault(); // Disable scroll } - async onSearchSource(_textSource, _cause) { - throw new Error('Override me'); - } - async _scanTimerWait() { const delay = this._options.scanning.delay; const promise = promiseTimeout(delay, true); @@ -245,16 +339,6 @@ class TextScanner extends EventDispatcher { } } - setEnabled(enabled) { - this._eventListeners.removeAllEventListeners(); - this._enabled = enabled; - if (this._enabled) { - this._hookEvents(); - } else { - this.clearSelection(true); - } - } - _hookEvents() { const eventListenerInfos = this._getMouseEventListeners(); if (this._options.scanning.touchInputEnabled) { @@ -287,93 +371,6 @@ class TextScanner extends EventDispatcher { ]; } - setOptions(options) { - this._options = options; - } - - async searchAt(x, y, cause) { - try { - this._scanTimerClear(); - - if (this._pendingLookup) { - return; - } - - for (const ignorePointFn of this._ignorePoints) { - if (await ignorePointFn(x, y)) { - return; - } - } - - const textSource = docRangeFromPoint(x, y, this._options.scanning.deepDomScan); - try { - if (this._textSourceCurrent !== null && this._textSourceCurrent.equals(textSource)) { - return; - } - - this._pendingLookup = true; - const result = await this.onSearchSource(textSource, cause); - if (result !== null) { - this._causeCurrent = cause; - this.setCurrentTextSource(textSource); - } - this._pendingLookup = false; - } finally { - if (textSource !== null) { - textSource.cleanup(); - } - } - } catch (e) { - yomichan.logError(e); - } - } - - getTextSourceContent(textSource, length) { - const clonedTextSource = textSource.clone(); - - clonedTextSource.setEndOffset(length); - - if (this._ignoreNodes !== null && clonedTextSource.range) { - length = clonedTextSource.text().length; - while (clonedTextSource.range && length > 0) { - const nodes = TextSourceRange.getNodesInRange(clonedTextSource.range); - if (!TextSourceRange.anyNodeMatchesSelector(nodes, this._ignoreNodes)) { - break; - } - --length; - clonedTextSource.setEndOffset(length); - } - } - - return clonedTextSource.text(); - } - - clearSelection(passive) { - if (!this._canClearSelection) { return; } - if (this._textSourceCurrent !== null) { - if (this._textSourceCurrentSelected) { - this._textSourceCurrent.deselect(); - } - this._textSourceCurrent = null; - this._textSourceCurrentSelected = false; - } - this.trigger('clearSelection', {passive}); - } - - getCurrentTextSource() { - return this._textSourceCurrent; - } - - setCurrentTextSource(textSource) { - this._textSourceCurrent = textSource; - if (this._options.scanning.selectText) { - this._textSourceCurrent.select(); - this._textSourceCurrentSelected = true; - } else { - this._textSourceCurrentSelected = false; - } - } - _isScanningModifierPressed(scanningModifier, mouseEvent) { switch (scanningModifier) { case 'alt': return mouseEvent.altKey; -- cgit v1.2.3