Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Application refactor #591

Merged
merged 5 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -658,9 +658,8 @@
},
{
"files": [
"ext/js/core.js",
"ext/js/core/extension-error.js",
"ext/js/yomitan.js",
"ext/js/application.js",
"ext/js/accessibility/accessibility-controller.js",
"ext/js/background/backend.js",
"ext/js/background/offscreen.js",
Expand Down
14 changes: 8 additions & 6 deletions ext/js/app/content-script-main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -54,7 +56,7 @@ async function main() {
});
await frontend.prepare();

yomitan.ready();
application.ready();
} catch (e) {
log.error(e);
}
Expand Down
35 changes: 19 additions & 16 deletions ext/js/app/frontend.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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,
Expand All @@ -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} */
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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)
Expand All @@ -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)],
Expand Down Expand Up @@ -230,7 +233,7 @@ export class Frontend {
try {
await this._updateOptionsInternal();
} catch (e) {
if (!yomitan.webExtension.unloaded) {
if (!this._application.webExtension.unloaded) {
throw e;
}
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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}});
});
}

Expand Down Expand Up @@ -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
}
Expand Down
15 changes: 10 additions & 5 deletions ext/js/app/popup-factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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}[]>} */
Expand All @@ -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)],
Expand Down Expand Up @@ -119,6 +121,7 @@ export class PopupFactory {
id = generateId(16);
}
const popup = new PopupWindow({
application: this._application,
id,
depth,
frameId: this._frameId
Expand All @@ -131,6 +134,7 @@ export class PopupFactory {
id = generateId(16);
}
const popup = new Popup({
application: this._application,
id,
depth,
frameId: this._frameId,
Expand All @@ -152,14 +156,15 @@ 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,
childrenSupported
}));
id = info.id;
const popup = new PopupProxy({
application: this._application,
id,
depth: info.depth,
frameId: info.frameId,
Expand Down
8 changes: 5 additions & 3 deletions ext/js/app/popup-proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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} */
Expand Down Expand Up @@ -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);
}

/**
Expand All @@ -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;
}
}
Expand Down
16 changes: 9 additions & 7 deletions ext/js/app/popup-window.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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} */
Expand Down Expand Up @@ -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));
}

/**
Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
}
}
Expand All @@ -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',
Expand Down
Loading
Loading