From b972f8cbf671c0e09603d54153a6344b105f41d9 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Thu, 7 May 2020 19:45:08 -0400 Subject: Text scanner refactor (#515) * Mark functions as private * Mark fields as private * Add getter/setters for publicly used fields * Replace public static functions with private non-static functions * Update comment --- ext/mixed/js/text-scanner.js | 260 ++++++++++++++++++++++--------------------- 1 file changed, 135 insertions(+), 125 deletions(-) diff --git a/ext/mixed/js/text-scanner.js b/ext/mixed/js/text-scanner.js index cc81f758..2ed6c3b9 100644 --- a/ext/mixed/js/text-scanner.js +++ b/ext/mixed/js/text-scanner.js @@ -24,27 +24,27 @@ class TextScanner extends EventDispatcher { constructor(node, ignoreElements, ignorePoints) { super(); - this.node = node; - this.ignoreElements = ignoreElements; - this.ignorePoints = ignorePoints; + this._node = node; + this._ignoreElements = ignoreElements; + this._ignorePoints = ignorePoints; - this.ignoreNodes = null; + this._ignoreNodes = null; - this.scanTimerPromise = null; - this.causeCurrent = null; - this.textSourceCurrent = null; - this.textSourceCurrentSelected = false; - this.pendingLookup = false; - this.options = null; + this._causeCurrent = null; + this._scanTimerPromise = null; + this._textSourceCurrent = null; + this._textSourceCurrentSelected = false; + this._pendingLookup = false; + this._options = null; - this.enabled = false; - this.eventListeners = new EventListenerCollection(); + this._enabled = false; + this._eventListeners = new EventListenerCollection(); - this.primaryTouchIdentifier = null; - this.preventNextContextMenu = false; - this.preventNextMouseDown = false; - this.preventNextClick = false; - this.preventScroll = false; + this._primaryTouchIdentifier = null; + this._preventNextContextMenu = false; + this._preventNextMouseDown = false; + this._preventNextClick = false; + this._preventScroll = false; this._canClearSelection = true; } @@ -57,26 +57,38 @@ class TextScanner extends EventDispatcher { this._canClearSelection = value; } - onMouseOver(e) { - if (this.ignoreElements().includes(e.target)) { - this.scanTimerClear(); + get ignoreNodes() { + return this._ignoreNodes; + } + + set ignoreNodes(value) { + this._ignoreNodes = value; + } + + get causeCurrent() { + return this._causeCurrent; + } + + _onMouseOver(e) { + if (this._ignoreElements().includes(e.target)) { + this._scanTimerClear(); } } - onMouseMove(e) { - this.scanTimerClear(); + _onMouseMove(e) { + this._scanTimerClear(); - if (this.pendingLookup || DOM.isMouseButtonDown(e, 'primary')) { + if (this._pendingLookup || DOM.isMouseButtonDown(e, 'primary')) { return; } const modifiers = DOM.getActiveModifiers(e); this.trigger('activeModifiersChanged', {modifiers}); - const scanningOptions = this.options.scanning; + const scanningOptions = this._options.scanning; const scanningModifier = scanningOptions.modifier; if (!( - TextScanner.isScanningModifierPressed(scanningModifier, e) || + this._isScanningModifierPressed(scanningModifier, e) || (scanningOptions.middleMouse && DOM.isMouseButtonDown(e, 'auxiliary')) )) { return; @@ -84,7 +96,7 @@ class TextScanner extends EventDispatcher { const search = async () => { if (scanningModifier === 'none') { - if (!await this.scanTimerWait()) { + if (!await this._scanTimerWait()) { // Aborted return; } @@ -96,112 +108,110 @@ class TextScanner extends EventDispatcher { search(); } - onMouseDown(e) { - if (this.preventNextMouseDown) { - this.preventNextMouseDown = false; - this.preventNextClick = true; + _onMouseDown(e) { + if (this._preventNextMouseDown) { + this._preventNextMouseDown = false; + this._preventNextClick = true; e.preventDefault(); e.stopPropagation(); return false; } if (DOM.isMouseButtonDown(e, 'primary')) { - this.scanTimerClear(); + this._scanTimerClear(); this.clearSelection(false); } } - onMouseOut() { - this.scanTimerClear(); + _onMouseOut() { + this._scanTimerClear(); } - onClick(e) { - if (this.preventNextClick) { - this.preventNextClick = false; + _onClick(e) { + if (this._preventNextClick) { + this._preventNextClick = false; e.preventDefault(); e.stopPropagation(); return false; } } - onAuxClick() { - this.preventNextContextMenu = false; + _onAuxClick() { + this._preventNextContextMenu = false; } - onContextMenu(e) { - if (this.preventNextContextMenu) { - this.preventNextContextMenu = false; + _onContextMenu(e) { + if (this._preventNextContextMenu) { + this._preventNextContextMenu = false; e.preventDefault(); e.stopPropagation(); return false; } } - onTouchStart(e) { - if (this.primaryTouchIdentifier !== null || e.changedTouches.length === 0) { + _onTouchStart(e) { + if (this._primaryTouchIdentifier !== null || e.changedTouches.length === 0) { return; } - this.preventScroll = false; - this.preventNextContextMenu = false; - this.preventNextMouseDown = false; - this.preventNextClick = false; + this._preventScroll = false; + this._preventNextContextMenu = false; + this._preventNextMouseDown = false; + this._preventNextClick = false; const primaryTouch = e.changedTouches[0]; if (DOM.isPointInSelection(primaryTouch.clientX, primaryTouch.clientY, window.getSelection())) { return; } - this.primaryTouchIdentifier = primaryTouch.identifier; + this._primaryTouchIdentifier = primaryTouch.identifier; - if (this.pendingLookup) { + if (this._pendingLookup) { return; } - const textSourceCurrentPrevious = this.textSourceCurrent !== null ? this.textSourceCurrent.clone() : null; + const textSourceCurrentPrevious = this._textSourceCurrent !== null ? this._textSourceCurrent.clone() : null; this.searchAt(primaryTouch.clientX, primaryTouch.clientY, 'touchStart') .then(() => { if ( - this.textSourceCurrent === null || - this.textSourceCurrent.equals(textSourceCurrentPrevious) + this._textSourceCurrent === null || + this._textSourceCurrent.equals(textSourceCurrentPrevious) ) { return; } - this.preventScroll = true; - this.preventNextContextMenu = true; - this.preventNextMouseDown = true; + this._preventScroll = true; + this._preventNextContextMenu = true; + this._preventNextMouseDown = true; }); } - onTouchEnd(e) { + _onTouchEnd(e) { if ( - this.primaryTouchIdentifier === null || - TextScanner.getTouch(e.changedTouches, this.primaryTouchIdentifier) === null + this._primaryTouchIdentifier === null || + this._getTouch(e.changedTouches, this._primaryTouchIdentifier) === null ) { return; } - this.primaryTouchIdentifier = null; - this.preventScroll = false; - this.preventNextClick = false; - // Don't revert context menu and mouse down prevention, - // since these events can occur after the touch has ended. - // this.preventNextContextMenu = false; - // this.preventNextMouseDown = false; + this._primaryTouchIdentifier = null; + this._preventScroll = false; + this._preventNextClick = false; + // Don't revert context menu and mouse down prevention, since these events can occur after the touch has ended. + // I.e. this._preventNextContextMenu and this._preventNextMouseDown should not be assigned to false. } - onTouchCancel(e) { - this.onTouchEnd(e); + _onTouchCancel(e) { + this._onTouchEnd(e); } - onTouchMove(e) { - if (!this.preventScroll || !e.cancelable || this.primaryTouchIdentifier === null) { + _onTouchMove(e) { + if (!this._preventScroll || !e.cancelable || this._primaryTouchIdentifier === null) { return; } - const primaryTouch = TextScanner.getTouch(e.changedTouches, this.primaryTouchIdentifier); + const primaryTouch = this._getTouch(e.changedTouches, this._primaryTouchIdentifier); if (primaryTouch === null) { return; } @@ -215,99 +225,99 @@ class TextScanner extends EventDispatcher { throw new Error('Override me'); } - async scanTimerWait() { - const delay = this.options.scanning.delay; + async _scanTimerWait() { + const delay = this._options.scanning.delay; const promise = promiseTimeout(delay, true); - this.scanTimerPromise = promise; + this._scanTimerPromise = promise; try { return await promise; } finally { - if (this.scanTimerPromise === promise) { - this.scanTimerPromise = null; + if (this._scanTimerPromise === promise) { + this._scanTimerPromise = null; } } } - scanTimerClear() { - if (this.scanTimerPromise !== null) { - this.scanTimerPromise.resolve(false); - this.scanTimerPromise = null; + _scanTimerClear() { + if (this._scanTimerPromise !== null) { + this._scanTimerPromise.resolve(false); + this._scanTimerPromise = null; } } setEnabled(enabled) { - this.eventListeners.removeAllEventListeners(); - this.enabled = enabled; - if (this.enabled) { - this.hookEvents(); + 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) { - eventListenerInfos.push(...this.getTouchEventListeners()); + _hookEvents() { + const eventListenerInfos = this._getMouseEventListeners(); + if (this._options.scanning.touchInputEnabled) { + eventListenerInfos.push(...this._getTouchEventListeners()); } for (const [node, type, listener, options] of eventListenerInfos) { - this.eventListeners.addEventListener(node, type, listener, options); + this._eventListeners.addEventListener(node, type, listener, options); } } - getMouseEventListeners() { + _getMouseEventListeners() { return [ - [this.node, 'mousedown', this.onMouseDown.bind(this)], - [this.node, 'mousemove', this.onMouseMove.bind(this)], - [this.node, 'mouseover', this.onMouseOver.bind(this)], - [this.node, 'mouseout', this.onMouseOut.bind(this)] + [this._node, 'mousedown', this._onMouseDown.bind(this)], + [this._node, 'mousemove', this._onMouseMove.bind(this)], + [this._node, 'mouseover', this._onMouseOver.bind(this)], + [this._node, 'mouseout', this._onMouseOut.bind(this)] ]; } - getTouchEventListeners() { + _getTouchEventListeners() { return [ - [this.node, 'click', this.onClick.bind(this)], - [this.node, 'auxclick', this.onAuxClick.bind(this)], - [this.node, 'touchstart', this.onTouchStart.bind(this)], - [this.node, 'touchend', this.onTouchEnd.bind(this)], - [this.node, 'touchcancel', this.onTouchCancel.bind(this)], - [this.node, 'touchmove', this.onTouchMove.bind(this), {passive: false}], - [this.node, 'contextmenu', this.onContextMenu.bind(this)] + [this._node, 'click', this._onClick.bind(this)], + [this._node, 'auxclick', this._onAuxClick.bind(this)], + [this._node, 'touchstart', this._onTouchStart.bind(this)], + [this._node, 'touchend', this._onTouchEnd.bind(this)], + [this._node, 'touchcancel', this._onTouchCancel.bind(this)], + [this._node, 'touchmove', this._onTouchMove.bind(this), {passive: false}], + [this._node, 'contextmenu', this._onContextMenu.bind(this)] ]; } setOptions(options) { - this.options = options; + this._options = options; } async searchAt(x, y, cause) { try { - this.scanTimerClear(); + this._scanTimerClear(); - if (this.pendingLookup) { + if (this._pendingLookup) { return; } - for (const ignorePointFn of this.ignorePoints) { + for (const ignorePointFn of this._ignorePoints) { if (await ignorePointFn(x, y)) { return; } } - const textSource = docRangeFromPoint(x, y, this.options.scanning.deepDomScan); + const textSource = docRangeFromPoint(x, y, this._options.scanning.deepDomScan); try { - if (this.textSourceCurrent !== null && this.textSourceCurrent.equals(textSource)) { + if (this._textSourceCurrent !== null && this._textSourceCurrent.equals(textSource)) { return; } - this.pendingLookup = true; + this._pendingLookup = true; const result = await this.onSearchSource(textSource, cause); if (result !== null) { - this.causeCurrent = cause; + this._causeCurrent = cause; this.setCurrentTextSource(textSource); } - this.pendingLookup = false; + this._pendingLookup = false; } finally { if (textSource !== null) { textSource.cleanup(); @@ -323,11 +333,11 @@ class TextScanner extends EventDispatcher { clonedTextSource.setEndOffset(length); - if (this.ignoreNodes !== null && clonedTextSource.range) { + 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)) { + if (!TextSourceRange.anyNodeMatchesSelector(nodes, this._ignoreNodes)) { break; } --length; @@ -340,31 +350,31 @@ class TextScanner extends EventDispatcher { clearSelection(passive) { if (!this._canClearSelection) { return; } - if (this.textSourceCurrent !== null) { - if (this.textSourceCurrentSelected) { - this.textSourceCurrent.deselect(); + if (this._textSourceCurrent !== null) { + if (this._textSourceCurrentSelected) { + this._textSourceCurrent.deselect(); } - this.textSourceCurrent = null; - this.textSourceCurrentSelected = false; + this._textSourceCurrent = null; + this._textSourceCurrentSelected = false; } this.trigger('clearSelection', {passive}); } getCurrentTextSource() { - return this.textSourceCurrent; + return this._textSourceCurrent; } setCurrentTextSource(textSource) { - this.textSourceCurrent = textSource; - if (this.options.scanning.selectText) { - this.textSourceCurrent.select(); - this.textSourceCurrentSelected = true; + this._textSourceCurrent = textSource; + if (this._options.scanning.selectText) { + this._textSourceCurrent.select(); + this._textSourceCurrentSelected = true; } else { - this.textSourceCurrentSelected = false; + this._textSourceCurrentSelected = false; } } - static isScanningModifierPressed(scanningModifier, mouseEvent) { + _isScanningModifierPressed(scanningModifier, mouseEvent) { switch (scanningModifier) { case 'alt': return mouseEvent.altKey; case 'ctrl': return mouseEvent.ctrlKey; @@ -375,7 +385,7 @@ class TextScanner extends EventDispatcher { } } - static getTouch(touchList, identifier) { + _getTouch(touchList, identifier) { for (const touch of touchList) { if (touch.identifier === identifier) { return touch; -- cgit v1.2.3