summaryrefslogtreecommitdiff
path: root/ext/js/app
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2024-02-01 10:00:59 -0500
committerGitHub <noreply@github.com>2024-02-01 15:00:59 +0000
commitdfd42bad0b46845ad88d1fdc5fa82b4f03bab0f3 (patch)
tree04686b943b84b33b8927238be17e4bc0dda7eb62 /ext/js/app
parent2356223942a21d1683ac38eed8e7b9485f453d87 (diff)
Application refactor (#591)
* Rename Yomitan class to Application, change initialization style * Rename file * Update init * Update config * Remove dead code
Diffstat (limited to 'ext/js/app')
-rw-r--r--ext/js/app/content-script-main.js14
-rw-r--r--ext/js/app/frontend.js35
-rw-r--r--ext/js/app/popup-factory.js15
-rw-r--r--ext/js/app/popup-proxy.js8
-rw-r--r--ext/js/app/popup-window.js16
-rw-r--r--ext/js/app/popup.js16
6 files changed, 60 insertions, 44 deletions
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 <https://www.gnu.org/licenses/>.
*/
+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<string, import('popup').PopupAny>} */
this._popups = new Map();
/** @type {Map<string, {popup: import('popup').PopupAny, token: string}[]>} */
@@ -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<import('cross-frame-api').ApiReturn<TName>>}
*/
_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<boolean>} `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<import('display').DirectApiReturn<TName>|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<TName>} */ (await yomitan.crossFrame.invokeTab(
+ return /** @type {import('display').DirectApiReturn<TName>} */ (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<TName>} */ (await yomitan.crossFrame.invokeTab(
+ return /** @type {import('display').DirectApiReturn<TName>} */ (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<TName>} */
const message = {action, params};
const wrappedMessage = this._frameClient.createMessage(message);
- return /** @type {import('display').DirectApiReturn<TName>} */ (await yomitan.crossFrame.invoke(
+ return /** @type {import('display').DirectApiReturn<TName>} */ (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;