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:
parent
ce861ce079
commit
08ada6844a
@ -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}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user