From dfd42bad0b46845ad88d1fdc5fa82b4f03bab0f3 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Thu, 1 Feb 2024 10:00:59 -0500 Subject: Application refactor (#591) * Rename Yomitan class to Application, change initialization style * Rename file * Update init * Update config * Remove dead code --- ext/js/app/content-script-main.js | 14 ++++++++------ ext/js/app/frontend.js | 35 +++++++++++++++++++---------------- ext/js/app/popup-factory.js | 15 ++++++++++----- ext/js/app/popup-proxy.js | 8 +++++--- ext/js/app/popup-window.js | 16 +++++++++------- ext/js/app/popup.js | 16 +++++++++------- 6 files changed, 60 insertions(+), 44 deletions(-) (limited to 'ext/js/app') diff --git a/ext/js/app/content-script-main.js b/ext/js/app/content-script-main.js index c0bea73c..d77f1fa0 100644 --- a/ext/js/app/content-script-main.js +++ b/ext/js/app/content-script-main.js @@ -16,29 +16,31 @@ * along with this program. If not, see . */ +import {Application} from '../application.js'; import {log} from '../core/logger.js'; import {HotkeyHandler} from '../input/hotkey-handler.js'; -import {yomitan} from '../yomitan.js'; import {Frontend} from './frontend.js'; import {PopupFactory} from './popup-factory.js'; /** Entry point. */ async function main() { try { - await yomitan.prepare(); + const application = new Application(); + await application.prepare(); - const {tabId, frameId} = await yomitan.api.frameInformationGet(); + const {tabId, frameId} = await application.api.frameInformationGet(); if (typeof frameId !== 'number') { throw new Error('Failed to get frameId'); } const hotkeyHandler = new HotkeyHandler(); - hotkeyHandler.prepare(); + hotkeyHandler.prepare(application.crossFrame); - const popupFactory = new PopupFactory(frameId); + const popupFactory = new PopupFactory(application, frameId); popupFactory.prepare(); const frontend = new Frontend({ + application, tabId, frameId, popupFactory, @@ -54,7 +56,7 @@ async function main() { }); await frontend.prepare(); - yomitan.ready(); + application.ready(); } catch (e) { log.error(e); } diff --git a/ext/js/app/frontend.js b/ext/js/app/frontend.js index d1c32b03..de1c5a46 100644 --- a/ext/js/app/frontend.js +++ b/ext/js/app/frontend.js @@ -25,7 +25,6 @@ import {TextSourceElement} from '../dom/text-source-element.js'; import {TextSourceGenerator} from '../dom/text-source-generator.js'; import {TextSourceRange} from '../dom/text-source-range.js'; import {TextScanner} from '../language/text-scanner.js'; -import {yomitan} from '../yomitan.js'; /** * This is the main class responsible for scanning and handling webpage content. @@ -36,6 +35,7 @@ export class Frontend { * @param {import('frontend').ConstructorDetails} details Details about how to set up the instance. */ constructor({ + application, pageType, popupFactory, depth, @@ -49,6 +49,8 @@ export class Frontend { childrenSupported = true, hotkeyHandler }) { + /** @type {import('../application.js').Application} */ + this._application = application; /** @type {import('frontend').PageType} */ this._pageType = pageType; /** @type {import('./popup-factory.js').PopupFactory} */ @@ -89,6 +91,7 @@ export class Frontend { this._textSourceGenerator = new TextSourceGenerator(); /** @type {TextScanner} */ this._textScanner = new TextScanner({ + api: application.api, node: window, ignoreElements: this._ignoreElements.bind(this), ignorePoint: this._ignorePoint.bind(this), @@ -157,7 +160,7 @@ export class Frontend { async prepare() { await this.updateOptions(); try { - const {zoomFactor} = await yomitan.api.getZoom(); + const {zoomFactor} = await this._application.api.getZoom(); this._pageZoomFactor = zoomFactor; } catch (e) { // Ignore exceptions which may occur due to being on an unsupported page (e.g. about:blank) @@ -174,16 +177,16 @@ export class Frontend { visualViewport.addEventListener('resize', this._onVisualViewportResize.bind(this)); } - yomitan.on('optionsUpdated', this.updateOptions.bind(this)); - yomitan.on('zoomChanged', this._onZoomChanged.bind(this)); - yomitan.on('closePopups', this._onClosePopups.bind(this)); + this._application.on('optionsUpdated', this.updateOptions.bind(this)); + this._application.on('zoomChanged', this._onZoomChanged.bind(this)); + this._application.on('closePopups', this._onClosePopups.bind(this)); chrome.runtime.onMessage.addListener(this._onRuntimeMessage.bind(this)); this._textScanner.on('clear', this._onTextScannerClear.bind(this)); this._textScanner.on('searched', this._onSearched.bind(this)); /* eslint-disable no-multi-spaces */ - yomitan.crossFrame.registerHandlers([ + this._application.crossFrame.registerHandlers([ ['frontendClosePopup', this._onApiClosePopup.bind(this)], ['frontendCopySelection', this._onApiCopySelection.bind(this)], ['frontendGetSelectionText', this._onApiGetSelectionText.bind(this)], @@ -230,7 +233,7 @@ export class Frontend { try { await this._updateOptionsInternal(); } catch (e) { - if (!yomitan.webExtension.unloaded) { + if (!this._application.webExtension.unloaded) { throw e; } } @@ -372,7 +375,7 @@ export class Frontend { const scanningOptions = /** @type {import('settings').ProfileOptions} */ (this._options).scanning; if (error !== null) { - if (yomitan.webExtension.unloaded) { + if (this._application.webExtension.unloaded) { if (textSource !== null && !passive) { this._showExtensionUnloaded(textSource); } @@ -461,7 +464,7 @@ export class Frontend { */ async _updateOptionsInternal() { const optionsContext = await this._getOptionsContext(); - const options = await yomitan.api.optionsGet(optionsContext); + const options = await this._application.api.optionsGet(optionsContext); const {scanning: scanningOptions, sentenceParsing: sentenceParsingOptions} = options; this._options = options; @@ -609,7 +612,7 @@ export class Frontend { return await this._getDefaultPopup(); } - const {popupId} = await yomitan.crossFrame.invoke(targetFrameId, 'frontendGetPopupInfo', void 0); + const {popupId} = await this._application.crossFrame.invoke(targetFrameId, 'frontendGetPopupInfo', void 0); if (popupId === null) { return null; } @@ -659,7 +662,7 @@ export class Frontend { try { return this._popup !== null && await this._popup.containsPoint(x, y); } catch (e) { - if (!yomitan.webExtension.unloaded) { + if (!this._application.webExtension.unloaded) { throw e; } return false; @@ -746,7 +749,7 @@ export class Frontend { Promise.resolve() ); this._lastShowPromise.catch((error) => { - if (yomitan.webExtension.unloaded) { return; } + if (this._application.webExtension.unloaded) { return; } log.error(error); }); return this._lastShowPromise; @@ -811,9 +814,9 @@ export class Frontend { /** @type {import('application').ApiMessageNoFrameId<'frontendReady'>} */ const message = {action: 'frontendReady', params: {frameId: this._frameId}}; if (targetFrameId === null) { - yomitan.api.broadcastTab(message); + this._application.api.broadcastTab(message); } else { - yomitan.api.sendMessageToFrame(targetFrameId, message); + this._application.api.sendMessageToFrame(targetFrameId, message); } } @@ -857,7 +860,7 @@ export class Frontend { } chrome.runtime.onMessage.addListener(onMessage); - yomitan.api.broadcastTab({action: 'frontendRequestReadyBroadcast', params: {frameId: this._frameId}}); + this._application.api.broadcastTab({action: 'frontendRequestReadyBroadcast', params: {frameId: this._frameId}}); }); } @@ -892,7 +895,7 @@ export class Frontend { let documentTitle = document.title; if (this._useProxyPopup && this._parentFrameId !== null) { try { - ({url, documentTitle} = await yomitan.crossFrame.invoke(this._parentFrameId, 'frontendGetPageInfo', void 0)); + ({url, documentTitle} = await this._application.crossFrame.invoke(this._parentFrameId, 'frontendGetPageInfo', void 0)); } catch (e) { // NOP } diff --git a/ext/js/app/popup-factory.js b/ext/js/app/popup-factory.js index f9eec913..1b7d21db 100644 --- a/ext/js/app/popup-factory.js +++ b/ext/js/app/popup-factory.js @@ -18,7 +18,6 @@ import {FrameOffsetForwarder} from '../comm/frame-offset-forwarder.js'; import {generateId} from '../core/utilities.js'; -import {yomitan} from '../yomitan.js'; import {PopupProxy} from './popup-proxy.js'; import {PopupWindow} from './popup-window.js'; import {Popup} from './popup.js'; @@ -29,13 +28,16 @@ import {Popup} from './popup.js'; export class PopupFactory { /** * Creates a new instance. + * @param {import('../application.js').Application} application * @param {number} frameId The frame ID of the host frame. */ - constructor(frameId) { + constructor(application, frameId) { + /** @type {import('../application.js').Application} */ + this._application = application; /** @type {number} */ this._frameId = frameId; /** @type {FrameOffsetForwarder} */ - this._frameOffsetForwarder = new FrameOffsetForwarder(frameId); + this._frameOffsetForwarder = new FrameOffsetForwarder(application.crossFrame, frameId); /** @type {Map} */ this._popups = new Map(); /** @type {Map} */ @@ -48,7 +50,7 @@ export class PopupFactory { prepare() { this._frameOffsetForwarder.prepare(); /* eslint-disable no-multi-spaces */ - yomitan.crossFrame.registerHandlers([ + this._application.crossFrame.registerHandlers([ ['popupFactoryGetOrCreatePopup', this._onApiGetOrCreatePopup.bind(this)], ['popupFactorySetOptionsContext', this._onApiSetOptionsContext.bind(this)], ['popupFactoryHide', this._onApiHide.bind(this)], @@ -119,6 +121,7 @@ export class PopupFactory { id = generateId(16); } const popup = new PopupWindow({ + application: this._application, id, depth, frameId: this._frameId @@ -131,6 +134,7 @@ export class PopupFactory { id = generateId(16); } const popup = new Popup({ + application: this._application, id, depth, frameId: this._frameId, @@ -152,7 +156,7 @@ export class PopupFactory { } const useFrameOffsetForwarder = (parentPopupId === null); /** @type {{id: string, depth: number, frameId: number}} */ - const info = await yomitan.crossFrame.invoke(frameId, 'popupFactoryGetOrCreatePopup', /** @type {import('popup-factory').GetOrCreatePopupDetails} */ ({ + const info = await this._application.crossFrame.invoke(frameId, 'popupFactoryGetOrCreatePopup', /** @type {import('popup-factory').GetOrCreatePopupDetails} */ ({ id, parentPopupId, frameId, @@ -160,6 +164,7 @@ export class PopupFactory { })); id = info.id; const popup = new PopupProxy({ + application: this._application, id, depth: info.depth, frameId: info.frameId, diff --git a/ext/js/app/popup-proxy.js b/ext/js/app/popup-proxy.js index 856ec086..3632b8cb 100644 --- a/ext/js/app/popup-proxy.js +++ b/ext/js/app/popup-proxy.js @@ -18,7 +18,6 @@ import {EventDispatcher} from '../core/event-dispatcher.js'; import {log} from '../core/logger.js'; -import {yomitan} from '../yomitan.js'; /** * This class is a proxy for a Popup that is hosted in a different frame. @@ -31,12 +30,15 @@ export class PopupProxy extends EventDispatcher { * @param {import('popup').PopupProxyConstructorDetails} details Details about how to set up the instance. */ constructor({ + application, id, depth, frameId, frameOffsetForwarder }) { super(); + /** @type {import('../application.js').Application} */ + this._application = application; /** @type {string} */ this._id = id; /** @type {number} */ @@ -305,7 +307,7 @@ export class PopupProxy extends EventDispatcher { * @returns {Promise>} */ _invoke(action, params) { - return yomitan.crossFrame.invoke(this._frameId, action, params); + return this._application.crossFrame.invoke(this._frameId, action, params); } /** @@ -320,7 +322,7 @@ export class PopupProxy extends EventDispatcher { try { return await this._invoke(action, params); } catch (e) { - if (!yomitan.webExtension.unloaded) { throw e; } + if (!this._application.webExtension.unloaded) { throw e; } return defaultReturnValue; } } diff --git a/ext/js/app/popup-window.js b/ext/js/app/popup-window.js index 7a0b6af4..32c4d67b 100644 --- a/ext/js/app/popup-window.js +++ b/ext/js/app/popup-window.js @@ -17,7 +17,6 @@ */ import {EventDispatcher} from '../core/event-dispatcher.js'; -import {yomitan} from '../yomitan.js'; /** * This class represents a popup that is hosted in a new native window. @@ -29,11 +28,14 @@ export class PopupWindow extends EventDispatcher { * @param {import('popup').PopupWindowConstructorDetails} details Details about how to set up the instance. */ constructor({ + application, id, depth, frameId }) { super(); + /** @type {import('../application.js').Application} */ + this._application = application; /** @type {string} */ this._id = id; /** @type {number} */ @@ -142,7 +144,7 @@ export class PopupWindow extends EventDispatcher { * @returns {Promise} `true` if the popup is visible, `false` otherwise. */ async isVisible() { - return (this._popupTabId !== null && await yomitan.api.isTabSearchPopup(this._popupTabId)); + return (this._popupTabId !== null && await this._application.api.isTabSearchPopup(this._popupTabId)); } /** @@ -274,7 +276,7 @@ export class PopupWindow extends EventDispatcher { * @returns {Promise|undefined>} */ async _invoke(open, action, params) { - if (yomitan.webExtension.unloaded) { + if (this._application.webExtension.unloaded) { return void 0; } @@ -283,14 +285,14 @@ export class PopupWindow extends EventDispatcher { const frameId = 0; if (this._popupTabId !== null) { try { - return /** @type {import('display').DirectApiReturn} */ (await yomitan.crossFrame.invokeTab( + return /** @type {import('display').DirectApiReturn} */ (await this._application.crossFrame.invokeTab( this._popupTabId, frameId, 'displayPopupMessage2', message )); } catch (e) { - if (yomitan.webExtension.unloaded) { + if (this._application.webExtension.unloaded) { open = false; } } @@ -301,10 +303,10 @@ export class PopupWindow extends EventDispatcher { return void 0; } - const {tabId} = await yomitan.api.getOrCreateSearchPopup({focus: 'ifCreated'}); + const {tabId} = await this._application.api.getOrCreateSearchPopup({focus: 'ifCreated'}); this._popupTabId = tabId; - return /** @type {import('display').DirectApiReturn} */ (await yomitan.crossFrame.invokeTab( + return /** @type {import('display').DirectApiReturn} */ (await this._application.crossFrame.invokeTab( this._popupTabId, frameId, 'displayPopupMessage2', diff --git a/ext/js/app/popup.js b/ext/js/app/popup.js index c741e8f1..08ff0661 100644 --- a/ext/js/app/popup.js +++ b/ext/js/app/popup.js @@ -24,7 +24,6 @@ import {ExtensionError} from '../core/extension-error.js'; import {deepEqual} from '../core/utilities.js'; import {DocumentUtil} from '../dom/document-util.js'; import {loadStyle} from '../dom/style-util.js'; -import {yomitan} from '../yomitan.js'; import {ThemeController} from './theme-controller.js'; /** @@ -37,12 +36,15 @@ export class Popup extends EventDispatcher { * @param {import('popup').PopupConstructorDetails} details The details used to construct the new instance. */ constructor({ + application, id, depth, frameId, childrenSupported }) { super(); + /** @type {import('../application.js').Application} */ + this._application = application; /** @type {string} */ this._id = id; /** @type {number} */ @@ -206,7 +208,7 @@ export class Popup extends EventDispatcher { this._frame.addEventListener('scroll', (e) => e.stopPropagation()); this._frame.addEventListener('load', this._onFrameLoad.bind(this)); this._visible.on('change', this._onVisibleChange.bind(this)); - yomitan.on('extensionUnloaded', this._onExtensionUnloaded.bind(this)); + this._application.on('extensionUnloaded', this._onExtensionUnloaded.bind(this)); this._onVisibleChange({value: this.isVisibleSync()}); this._themeController.prepare(); } @@ -362,7 +364,7 @@ export class Popup extends EventDispatcher { useWebExtensionApi = false; parentNode = this._shadow; } - const node = await loadStyle('yomitan-popup-outer-user-stylesheet', 'code', css, useWebExtensionApi, parentNode); + const node = await loadStyle(this._application, 'yomitan-popup-outer-user-stylesheet', 'code', css, useWebExtensionApi, parentNode); this.trigger('customOuterCssChanged', {node, useWebExtensionApi, inShadow}); } @@ -575,7 +577,7 @@ export class Popup extends EventDispatcher { useWebExtensionApi = false; parentNode = this._shadow; } - await loadStyle('yomitan-popup-outer-stylesheet', fileType, '/css/popup-outer.css', useWebExtensionApi, parentNode); + await loadStyle(this._application, 'yomitan-popup-outer-stylesheet', fileType, '/css/popup-outer.css', useWebExtensionApi, parentNode); } /** @@ -697,7 +699,7 @@ export class Popup extends EventDispatcher { /** @type {import('display').DirectApiMessage} */ const message = {action, params}; const wrappedMessage = this._frameClient.createMessage(message); - return /** @type {import('display').DirectApiReturn} */ (await yomitan.crossFrame.invoke( + return /** @type {import('display').DirectApiReturn} */ (await this._application.crossFrame.invoke( this._frameClient.frameId, 'displayPopupMessage1', /** @type {import('display').DirectApiFrameClientMessageAny} */ (wrappedMessage) @@ -714,7 +716,7 @@ export class Popup extends EventDispatcher { try { return await this._invoke(action, params); } catch (e) { - if (!yomitan.webExtension.unloaded) { throw e; } + if (!this._application.webExtension.unloaded) { throw e; } return void 0; } } @@ -1008,7 +1010,7 @@ export class Popup extends EventDispatcher { */ async _setOptionsContext(optionsContext) { this._optionsContext = optionsContext; - const options = await yomitan.api.optionsGet(optionsContext); + const options = await this._application.api.optionsGet(optionsContext); const {general} = options; this._themeController.theme = general.popupTheme; this._themeController.outerTheme = general.popupOuterTheme; -- cgit v1.2.3