diff options
Diffstat (limited to 'ext/js/app/popup-proxy.js')
-rw-r--r-- | ext/js/app/popup-proxy.js | 108 |
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) { |