aboutsummaryrefslogtreecommitdiff
path: root/ext/js/app/popup-proxy.js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/js/app/popup-proxy.js')
-rw-r--r--ext/js/app/popup-proxy.js108
1 files changed, 67 insertions, 41 deletions
diff --git a/ext/js/app/popup-proxy.js b/ext/js/app/popup-proxy.js
index 3d8b55ba..924175e2 100644
--- a/ext/js/app/popup-proxy.js
+++ b/ext/js/app/popup-proxy.js
@@ -16,23 +16,18 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import {FrameOffsetForwarder} from '../comm/frame-offset-forwarder.js';
import {EventDispatcher, log} from '../core.js';
import {yomitan} from '../yomitan.js';
-import {Popup} from './popup.js';
/**
* This class is a proxy for a Popup that is hosted in a different frame.
* It effectively forwards all API calls to the underlying Popup.
+ * @augments EventDispatcher<import('popup').PopupAnyEventType>
*/
export class PopupProxy extends EventDispatcher {
/**
* Creates a new instance.
- * @param {object} details Details about how to set up the instance.
- * @param {string} details.id The ID of the popup.
- * @param {number} details.depth The depth of the popup.
- * @param {number} details.frameId The ID of the host frame.
- * @param {FrameOffsetForwarder} details.frameOffsetForwarder A `FrameOffsetForwarder` instance which is used to determine frame positioning.
+ * @param {import('popup').PopupProxyConstructorDetails} details Details about how to set up the instance.
*/
constructor({
id,
@@ -41,15 +36,24 @@ export class PopupProxy extends EventDispatcher {
frameOffsetForwarder
}) {
super();
+ /** @type {string} */
this._id = id;
+ /** @type {number} */
this._depth = depth;
+ /** @type {number} */
this._frameId = frameId;
+ /** @type {?import('../comm/frame-offset-forwarder.js').FrameOffsetForwarder} */
this._frameOffsetForwarder = frameOffsetForwarder;
+ /** @type {number} */
this._frameOffsetX = 0;
+ /** @type {number} */
this._frameOffsetY = 0;
+ /** @type {?Promise<?[x: number, y: number]>} */
this._frameOffsetPromise = null;
+ /** @type {?number} */
this._frameOffsetUpdatedAt = null;
+ /** @type {number} */
this._frameOffsetExpireTimeout = 1000;
}
@@ -64,7 +68,7 @@ export class PopupProxy extends EventDispatcher {
/**
* The parent of the popup, which is always `null` for `PopupProxy` instances,
* since any potential parent popups are in a different frame.
- * @type {Popup}
+ * @type {?import('./popup.js').Popup}
*/
get parent() {
return null;
@@ -72,7 +76,7 @@ export class PopupProxy extends EventDispatcher {
/**
* Attempts to set the parent popup.
- * @param {Popup} _value The parent to assign.
+ * @param {import('./popup.js').Popup} _value The parent to assign.
* @throws {Error} Throws an error, since this class doesn't support a direct parent.
*/
set parent(_value) {
@@ -82,7 +86,7 @@ export class PopupProxy extends EventDispatcher {
/**
* The popup child popup, which is always null for `PopupProxy` instances,
* since any potential child popups are in a different frame.
- * @type {Popup}
+ * @type {?import('./popup.js').Popup}
*/
get child() {
return null;
@@ -90,7 +94,7 @@ export class PopupProxy extends EventDispatcher {
/**
* Attempts to set the child popup.
- * @param {Popup} _child The child to assign.
+ * @param {import('./popup.js').Popup} _child The child to assign.
* @throws {Error} Throws an error, since this class doesn't support children.
*/
set child(_child) {
@@ -99,7 +103,7 @@ export class PopupProxy extends EventDispatcher {
/**
* The depth of the popup.
- * @type {numer}
+ * @type {number}
*/
get depth() {
return this._depth;
@@ -108,7 +112,7 @@ export class PopupProxy extends EventDispatcher {
/**
* Gets the content window of the frame. This value is null,
* since the window is hosted in a different frame.
- * @type {Window}
+ * @type {?Window}
*/
get frameContentWindow() {
return null;
@@ -116,7 +120,7 @@ export class PopupProxy extends EventDispatcher {
/**
* Gets the DOM node that contains the frame.
- * @type {Element}
+ * @type {?Element}
*/
get container() {
return null;
@@ -132,11 +136,11 @@ export class PopupProxy extends EventDispatcher {
/**
* Sets the options context for the popup.
- * @param {object} optionsContext The options context object.
+ * @param {import('settings').OptionsContext} optionsContext The options context object.
* @returns {Promise<void>}
*/
- setOptionsContext(optionsContext) {
- return this._invokeSafe('PopupFactory.setOptionsContext', {id: this._id, optionsContext});
+ async setOptionsContext(optionsContext) {
+ await this._invokeSafe('PopupFactory.setOptionsContext', {id: this._id, optionsContext}, void 0);
}
/**
@@ -144,8 +148,8 @@ export class PopupProxy extends EventDispatcher {
* @param {boolean} changeFocus Whether or not the parent popup or host frame should be focused.
* @returns {Promise<void>}
*/
- hide(changeFocus) {
- return this._invokeSafe('PopupFactory.hide', {id: this._id, changeFocus});
+ async hide(changeFocus) {
+ await this._invokeSafe('PopupFactory.hide', {id: this._id, changeFocus}, void 0);
}
/**
@@ -160,7 +164,7 @@ export class PopupProxy extends EventDispatcher {
* Force assigns the visibility of the popup.
* @param {boolean} value Whether or not the popup should be visible.
* @param {number} priority The priority of the override.
- * @returns {Promise<string?>} A token used which can be passed to `clearVisibleOverride`,
+ * @returns {Promise<?import('core').TokenString>} A token used which can be passed to `clearVisibleOverride`,
* or null if the override wasn't assigned.
*/
setVisibleOverride(value, priority) {
@@ -169,7 +173,7 @@ export class PopupProxy extends EventDispatcher {
/**
* Clears a visibility override that was generated by `setVisibleOverride`.
- * @param {string} token The token returned from `setVisibleOverride`.
+ * @param {import('core').TokenString} token The token returned from `setVisibleOverride`.
* @returns {Promise<boolean>} `true` if the override existed and was removed, `false` otherwise.
*/
clearVisibleOverride(token) {
@@ -193,8 +197,8 @@ export class PopupProxy extends EventDispatcher {
/**
* Shows and updates the positioning and content of the popup.
- * @param {Popup.ContentDetails} details Settings for the outer popup.
- * @param {Display.ContentDetails} displayDetails The details parameter passed to `Display.setContent`.
+ * @param {import('popup').ContentDetails} details Settings for the outer popup.
+ * @param {?import('display').ContentDetails} displayDetails The details parameter passed to `Display.setContent`.
* @returns {Promise<void>}
*/
async showContent(details, displayDetails) {
@@ -208,7 +212,7 @@ export class PopupProxy extends EventDispatcher {
sourceRect.bottom += this._frameOffsetY;
}
}
- return await this._invokeSafe('PopupFactory.showContent', {id: this._id, details, displayDetails});
+ await this._invokeSafe('PopupFactory.showContent', {id: this._id, details, displayDetails}, void 0);
}
/**
@@ -216,16 +220,16 @@ export class PopupProxy extends EventDispatcher {
* @param {string} css The CSS rules.
* @returns {Promise<void>}
*/
- setCustomCss(css) {
- return this._invokeSafe('PopupFactory.setCustomCss', {id: this._id, css});
+ async setCustomCss(css) {
+ await this._invokeSafe('PopupFactory.setCustomCss', {id: this._id, css}, void 0);
}
/**
* Stops the audio auto-play timer, if one has started.
* @returns {Promise<void>}
*/
- clearAutoPlayTimer() {
- return this._invokeSafe('PopupFactory.clearAutoPlayTimer', {id: this._id});
+ async clearAutoPlayTimer() {
+ await this._invokeSafe('PopupFactory.clearAutoPlayTimer', {id: this._id}, void 0);
}
/**
@@ -233,8 +237,8 @@ export class PopupProxy extends EventDispatcher {
* @param {number} scale The scaling factor.
* @returns {Promise<void>}
*/
- setContentScale(scale) {
- return this._invokeSafe('PopupFactory.setContentScale', {id: this._id, scale});
+ async setContentScale(scale) {
+ await this._invokeSafe('PopupFactory.setContentScale', {id: this._id, scale}, void 0);
}
/**
@@ -249,8 +253,8 @@ export class PopupProxy extends EventDispatcher {
* Updates the outer theme of the popup.
* @returns {Promise<void>}
*/
- updateTheme() {
- return this._invokeSafe('PopupFactory.updateTheme', {id: this._id});
+ async updateTheme() {
+ await this._invokeSafe('PopupFactory.updateTheme', {id: this._id}, void 0);
}
/**
@@ -260,13 +264,13 @@ export class PopupProxy extends EventDispatcher {
* When web extension APIs are used, a DOM node is not generated, making it harder to detect the changes.
* @returns {Promise<void>}
*/
- setCustomOuterCss(css, useWebExtensionApi) {
- return this._invokeSafe('PopupFactory.setCustomOuterCss', {id: this._id, css, useWebExtensionApi});
+ async setCustomOuterCss(css, useWebExtensionApi) {
+ await this._invokeSafe('PopupFactory.setCustomOuterCss', {id: this._id, css, useWebExtensionApi}, void 0);
}
/**
* Gets the rectangle of the DOM frame, synchronously.
- * @returns {Popup.ValidRect} The rect.
+ * @returns {import('popup').ValidRect} The rect.
* `valid` is `false` for `PopupProxy`, since the DOM node is hosted in a different frame.
*/
getFrameRect() {
@@ -275,7 +279,7 @@ export class PopupProxy extends EventDispatcher {
/**
* Gets the size of the DOM frame.
- * @returns {Promise<{width: number, height: number, valid: boolean}>} The size and whether or not it is valid.
+ * @returns {Promise<import('popup').ValidSize>} The size and whether or not it is valid.
*/
getFrameSize() {
return this._invokeSafe('PopupFactory.getFrameSize', {id: this._id}, {width: 0, height: 0, valid: false});
@@ -288,16 +292,32 @@ export class PopupProxy extends EventDispatcher {
* @returns {Promise<boolean>} `true` if the size assignment was successful, `false` otherwise.
*/
setFrameSize(width, height) {
- return this._invokeSafe('PopupFactory.setFrameSize', {id: this._id, width, height});
+ return this._invokeSafe('PopupFactory.setFrameSize', {id: this._id, width, height}, false);
}
// Private
- _invoke(action, params={}) {
+ /**
+ * @template {import('core').SerializableObject} TParams
+ * @template [TReturn=unknown]
+ * @param {string} action
+ * @param {TParams} params
+ * @returns {Promise<TReturn>}
+ */
+ _invoke(action, params) {
return yomitan.crossFrame.invoke(this._frameId, action, params);
}
- async _invokeSafe(action, params={}, defaultReturnValue) {
+ /**
+ * @template {import('core').SerializableObject} TParams
+ * @template [TReturn=unknown]
+ * @template [TReturnDefault=unknown]
+ * @param {string} action
+ * @param {TParams} params
+ * @param {TReturnDefault} defaultReturnValue
+ * @returns {Promise<TReturn|TReturnDefault>}
+ */
+ async _invokeSafe(action, params, defaultReturnValue) {
try {
return await this._invoke(action, params);
} catch (e) {
@@ -306,10 +326,13 @@ export class PopupProxy extends EventDispatcher {
}
}
+ /**
+ * @returns {Promise<void>}
+ */
async _updateFrameOffset() {
const now = Date.now();
const firstRun = this._frameOffsetUpdatedAt === null;
- const expired = firstRun || this._frameOffsetUpdatedAt < now - this._frameOffsetExpireTimeout;
+ const expired = firstRun || /** @type {number} */ (this._frameOffsetUpdatedAt) < now - this._frameOffsetExpireTimeout;
if (this._frameOffsetPromise === null && !expired) { return; }
if (this._frameOffsetPromise !== null) {
@@ -325,8 +348,11 @@ export class PopupProxy extends EventDispatcher {
}
}
+ /**
+ * @param {number} now
+ */
async _updateFrameOffsetInner(now) {
- this._frameOffsetPromise = this._frameOffsetForwarder.getOffset();
+ this._frameOffsetPromise = /** @type {import('../comm/frame-offset-forwarder.js').FrameOffsetForwarder} */ (this._frameOffsetForwarder).getOffset();
try {
const offset = await this._frameOffsetPromise;
if (offset !== null) {