Remove Frontend inheritance (#486)

* Make Frontend use composition instead of inheritance for TextScanner

* Use push instead of concat

* Update setOptions and setEnabled APIs

* Update how onWindowMessage event listener is added/removed

* Rename options to _options

* Use bind instead of arrow function

* Fix selection being cleared due to settings changes
This commit is contained in:
toasted-nutbread 2020-05-02 12:47:15 -04:00 committed by GitHub
parent ce861ce079
commit 08ada6844a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 77 additions and 49 deletions

View File

@ -86,6 +86,7 @@ class QueryParser extends TextScanner {
setOptions(options) { setOptions(options) {
super.setOptions(options); super.setOptions(options);
super.setEnabled(true);
this.queryParser.dataset.termSpacing = `${options.parsing.termSpacing}`; this.queryParser.dataset.termSpacing = `${options.parsing.termSpacing}`;
} }

View File

@ -66,12 +66,10 @@ class SettingsPopupPreview {
this.popup.setCustomOuterCss = this.popupSetCustomOuterCss.bind(this); this.popup.setCustomOuterCss = this.popupSetCustomOuterCss.bind(this);
this.frontend = new Frontend(this.popup); this.frontend = new Frontend(this.popup);
this.frontend.getOptionsContext = async () => this.optionsContext; this.frontend.getOptionsContext = async () => this.optionsContext;
this.frontend.setEnabled = () => {};
this.frontend.clearSelection = () => {};
await this.frontend.prepare(); await this.frontend.prepare();
this.frontend.setDisabledOverride(true);
this.frontend.canClearSelection = false;
// Update search // Update search
this.updateSearch(); this.updateSearch();
@ -169,8 +167,7 @@ class SettingsPopupPreview {
const source = new TextSourceRange(range, range.toString(), null, null); const source = new TextSourceRange(range, range.toString(), null, null);
try { try {
await this.frontend.onSearchSource(source, 'script'); await this.frontend.setTextSource(source);
this.frontend.setCurrentTextSource(source);
} finally { } finally {
source.cleanup(); source.cleanup();
} }

View File

@ -25,14 +25,8 @@
* docSentenceExtract * docSentenceExtract
*/ */
class Frontend extends TextScanner { class Frontend {
constructor(popup, getUrl=null) { constructor(popup, getUrl=null) {
super(
window,
() => this.popup.isProxy() ? [] : [this.popup.getContainer()],
[(x, y) => this.popup.containsPoint(x, y)]
);
this._id = yomichan.generateId(16); this._id = yomichan.generateId(16);
this.popup = popup; this.popup = popup;
@ -41,15 +35,23 @@ class Frontend extends TextScanner {
this._disabledOverride = false; this._disabledOverride = false;
this.options = null; this._options = null;
this._pageZoomFactor = 1.0; this._pageZoomFactor = 1.0;
this._contentScale = 1.0; this._contentScale = 1.0;
this._orphaned = false; this._orphaned = false;
this._lastShowPromise = Promise.resolve(); this._lastShowPromise = Promise.resolve();
this._enabledEventListeners = new EventListenerCollection();
this._textScanner = new TextScanner(
window,
() => this.popup.isProxy() ? [] : [this.popup.getContainer()],
[(x, y) => this.popup.containsPoint(x, y)]
);
this._textScanner.onSearchSource = this.onSearchSource.bind(this);
this._windowMessageHandlers = new Map([ this._windowMessageHandlers = new Map([
['popupClose', () => this.clearSelection(false)], ['popupClose', () => this._textScanner.clearSelection(false)],
['selectionCopy', () => document.execCommand('copy')] ['selectionCopy', () => document.execCommand('copy')]
]); ]);
@ -60,6 +62,14 @@ class Frontend extends TextScanner {
]); ]);
} }
get canClearSelection() {
return this._textScanner.canClearSelection;
}
set canClearSelection(value) {
this._textScanner.canClearSelection = value;
}
async prepare() { async prepare() {
try { try {
await this.updateOptions(); await this.updateOptions();
@ -79,7 +89,7 @@ class Frontend extends TextScanner {
yomichan.on('zoomChanged', this.onZoomChanged.bind(this)); yomichan.on('zoomChanged', this.onZoomChanged.bind(this));
chrome.runtime.onMessage.addListener(this.onRuntimeMessage.bind(this)); chrome.runtime.onMessage.addListener(this.onRuntimeMessage.bind(this));
this.on('clearSelection', this.onClearSelection.bind(this)); this._textScanner.on('clearSelection', this.onClearSelection.bind(this));
this._updateContentScale(); this._updateContentScale();
this._broadcastRootPopupInformation(); this._broadcastRootPopupInformation();
@ -129,44 +139,45 @@ class Frontend extends TextScanner {
this._updateContentScale(); this._updateContentScale();
} }
getMouseEventListeners() {
return [
...super.getMouseEventListeners(),
[window, 'message', this.onWindowMessage.bind(this)]
];
}
setDisabledOverride(disabled) { setDisabledOverride(disabled) {
this._disabledOverride = disabled; this._disabledOverride = disabled;
this.setEnabled(this.options.general.enable, this._canEnable()); this._updateTextScannerEnabled();
} }
async setPopup(popup) { async setPopup(popup) {
this.clearSelection(true); this._textScanner.clearSelection(true);
this.popup = popup; this.popup = popup;
await popup.setOptionsContext(await this.getOptionsContext(), this._id); await popup.setOptionsContext(await this.getOptionsContext(), this._id);
} }
async updateOptions() { async updateOptions() {
const optionsContext = await this.getOptionsContext(); const optionsContext = await this.getOptionsContext();
this.options = await apiOptionsGet(optionsContext); this._options = await apiOptionsGet(optionsContext);
this.setOptions(this.options, this._canEnable()); this._textScanner.setOptions(this._options);
this._updateTextScannerEnabled();
const ignoreNodes = ['.scan-disable', '.scan-disable *']; const ignoreNodes = ['.scan-disable', '.scan-disable *'];
if (!this.options.scanning.enableOnPopupExpressions) { if (!this._options.scanning.enableOnPopupExpressions) {
ignoreNodes.push('.source-text', '.source-text *'); ignoreNodes.push('.source-text', '.source-text *');
} }
this.ignoreNodes = ignoreNodes.join(','); this._textScanner.ignoreNodes = ignoreNodes.join(',');
await this.popup.setOptionsContext(optionsContext, this._id); await this.popup.setOptionsContext(optionsContext, this._id);
this._updateContentScale(); this._updateContentScale();
if (this.textSourceCurrent !== null && this.causeCurrent !== null) { const textSourceCurrent = this._textScanner.getCurrentTextSource();
await this.onSearchSource(this.textSourceCurrent, this.causeCurrent); const causeCurrent = this._textScanner.causeCurrent;
if (textSourceCurrent !== null && causeCurrent !== null) {
await this.onSearchSource(textSourceCurrent, causeCurrent);
} }
} }
async setTextSource(textSource) {
await this.onSearchSource(textSource, 'script');
this._textScanner.setCurrentTextSource(textSource);
}
async onSearchSource(textSource, cause) { async onSearchSource(textSource, cause) {
let results = null; let results = null;
@ -184,15 +195,15 @@ class Frontend extends TextScanner {
} }
} catch (e) { } catch (e) {
if (this._orphaned) { if (this._orphaned) {
if (textSource !== null && this.options.scanning.modifier !== 'none') { if (textSource !== null && this._options.scanning.modifier !== 'none') {
this._showPopupContent(textSource, await this.getOptionsContext(), 'orphaned'); this._showPopupContent(textSource, await this.getOptionsContext(), 'orphaned');
} }
} else { } else {
yomichan.logError(e); yomichan.logError(e);
} }
} finally { } finally {
if (results === null && this.options.scanning.autoHideResults) { if (results === null && this._options.scanning.autoHideResults) {
this.clearSelection(false); this._textScanner.clearSelection(false);
} }
} }
@ -201,7 +212,7 @@ class Frontend extends TextScanner {
showContent(textSource, focus, definitions, type, optionsContext) { showContent(textSource, focus, definitions, type, optionsContext) {
const {url} = optionsContext; const {url} = optionsContext;
const sentence = docSentenceExtract(textSource, this.options.anki.sentenceExt); const sentence = docSentenceExtract(textSource, this._options.anki.sentenceExt);
this._showPopupContent( this._showPopupContent(
textSource, textSource,
optionsContext, optionsContext,
@ -215,7 +226,7 @@ class Frontend extends TextScanner {
} }
async findTerms(textSource, optionsContext) { async findTerms(textSource, optionsContext) {
this.setTextSourceScanLength(textSource, this.options.scanning.length); this._textScanner.setTextSourceScanLength(textSource, this._options.scanning.length);
const searchText = textSource.text(); const searchText = textSource.text();
if (searchText.length === 0) { return null; } if (searchText.length === 0) { return null; }
@ -229,7 +240,7 @@ class Frontend extends TextScanner {
} }
async findKanji(textSource, optionsContext) { async findKanji(textSource, optionsContext) {
this.setTextSourceScanLength(textSource, 1); this._textScanner.setTextSourceScanLength(textSource, 1);
const searchText = textSource.text(); const searchText = textSource.text();
if (searchText.length === 0) { return null; } if (searchText.length === 0) { return null; }
@ -263,8 +274,21 @@ class Frontend extends TextScanner {
return this._lastShowPromise; return this._lastShowPromise;
} }
_updateTextScannerEnabled() {
const enabled = (
this._options.general.enable &&
this.popup.depth <= this._options.scanning.popupNestingMaxDepth &&
!this._disabledOverride
);
this._enabledEventListeners.removeAllEventListeners();
this._textScanner.setEnabled(enabled);
if (enabled) {
this._enabledEventListeners.addEventListener(window, 'message', this.onWindowMessage.bind(this));
}
}
_updateContentScale() { _updateContentScale() {
const {popupScalingFactor, popupScaleRelativeToPageZoom, popupScaleRelativeToVisualViewport} = this.options.general; const {popupScalingFactor, popupScaleRelativeToPageZoom, popupScaleRelativeToVisualViewport} = this._options.general;
let contentScale = popupScalingFactor; let contentScale = popupScalingFactor;
if (popupScaleRelativeToPageZoom) { if (popupScaleRelativeToPageZoom) {
contentScale /= this._pageZoomFactor; contentScale /= this._pageZoomFactor;
@ -295,12 +319,8 @@ class Frontend extends TextScanner {
}); });
} }
_canEnable() {
return this.popup.depth <= this.options.scanning.popupNestingMaxDepth && !this._disabledOverride;
}
async _updatePopupPosition() { async _updatePopupPosition() {
const textSource = this.getCurrentTextSource(); const textSource = this._textScanner.getCurrentTextSource();
if (textSource !== null && await this.popup.isVisible()) { if (textSource !== null && await this.popup.isVisible()) {
this._showPopupContent(textSource, await this.getOptionsContext()); this._showPopupContent(textSource, await this.getOptionsContext());
} }

View File

@ -45,6 +45,16 @@ class TextScanner extends EventDispatcher {
this.preventNextMouseDown = false; this.preventNextMouseDown = false;
this.preventNextClick = false; this.preventNextClick = false;
this.preventScroll = false; this.preventScroll = false;
this._canClearSelection = true;
}
get canClearSelection() {
return this._canClearSelection;
}
set canClearSelection(value) {
this._canClearSelection = value;
} }
onMouseOver(e) { onMouseOver(e) {
@ -222,9 +232,9 @@ class TextScanner extends EventDispatcher {
} }
} }
setEnabled(enabled, canEnable) { setEnabled(enabled) {
this.eventListeners.removeAllEventListeners(); this.eventListeners.removeAllEventListeners();
this.enabled = enabled && canEnable; this.enabled = enabled;
if (this.enabled) { if (this.enabled) {
this.hookEvents(); this.hookEvents();
} else { } else {
@ -233,9 +243,9 @@ class TextScanner extends EventDispatcher {
} }
hookEvents() { hookEvents() {
let eventListenerInfos = this.getMouseEventListeners(); const eventListenerInfos = this.getMouseEventListeners();
if (this.options.scanning.touchInputEnabled) { if (this.options.scanning.touchInputEnabled) {
eventListenerInfos = eventListenerInfos.concat(this.getTouchEventListeners()); eventListenerInfos.push(...this.getTouchEventListeners());
} }
for (const [node, type, listener, options] of eventListenerInfos) { for (const [node, type, listener, options] of eventListenerInfos) {
@ -264,9 +274,8 @@ class TextScanner extends EventDispatcher {
]; ];
} }
setOptions(options, canEnable=true) { setOptions(options) {
this.options = options; this.options = options;
this.setEnabled(this.options.general.enable, canEnable);
} }
async searchAt(x, y, cause) { async searchAt(x, y, cause) {
@ -324,6 +333,7 @@ class TextScanner extends EventDispatcher {
} }
clearSelection(passive) { clearSelection(passive) {
if (!this._canClearSelection) { return; }
if (this.textSourceCurrent !== null) { if (this.textSourceCurrent !== null) {
if (this.textSourceCurrentSelected) { if (this.textSourceCurrentSelected) {
this.textSourceCurrent.deselect(); this.textSourceCurrent.deselect();