diff options
author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2020-07-10 22:13:59 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-10 22:13:59 -0400 |
commit | 8389cd8ba27f328123fb73e72b24e69a4a6de2c1 (patch) | |
tree | 3d697dd1599415678dd708746cb2bdbcc43fd9cd | |
parent | 964f011409e824da52510c7de16a1c64ebae1787 (diff) |
Popup crossFrame communication (#658)
* Add support for dynamic message handlers
* Pass messages using crossFrame.invoke instead of contentWindow.postMessage
* Set up async handlers
* Simplify configure call and response
-rw-r--r-- | ext/fg/js/float.js | 50 | ||||
-rw-r--r-- | ext/fg/js/popup.js | 23 | ||||
-rw-r--r-- | ext/mixed/js/comm.js | 33 |
3 files changed, 34 insertions, 72 deletions
diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js index 2debdeff..61d42fb3 100644 --- a/ext/fg/js/float.js +++ b/ext/fg/js/float.js @@ -32,12 +32,12 @@ class DisplayFloat extends Display { this._ownerFrameId = null; this._frameEndpoint = new FrameEndpoint(); this._windowMessageHandlers = new Map([ - ['configure', {handler: this._onMessageConfigure.bind(this)}], - ['setOptionsContext', {handler: this._onMessageSetOptionsContext.bind(this)}], - ['setContent', {handler: this._onMessageSetContent.bind(this)}], - ['clearAutoPlayTimer', {handler: this._onMessageClearAutoPlayTimer.bind(this)}], - ['setCustomCss', {handler: this._onMessageSetCustomCss.bind(this)}], - ['setContentScale', {handler: this._onMessageSetContentScale.bind(this)}] + ['configure', {async: true, handler: this._onMessageConfigure.bind(this)}], + ['setOptionsContext', {async: false, handler: this._onMessageSetOptionsContext.bind(this)}], + ['setContent', {async: false, handler: this._onMessageSetContent.bind(this)}], + ['clearAutoPlayTimer', {async: false, handler: this._onMessageClearAutoPlayTimer.bind(this)}], + ['setCustomCss', {async: false, handler: this._onMessageSetCustomCss.bind(this)}], + ['setContentScale', {async: false, handler: this._onMessageSetContentScale.bind(this)}] ]); this.registerActions([ @@ -51,7 +51,9 @@ class DisplayFloat extends Display { async prepare() { await super.prepare(); - window.addEventListener('message', this._onMessage.bind(this), false); + api.crossFrame.registerHandlers([ + ['popupMessage', {async: 'dynamic', handler: this._onMessage.bind(this)}] + ]); this._frameEndpoint.signal(); } @@ -99,33 +101,23 @@ class DisplayFloat extends Display { // Message handling - _onMessage(e) { - let data = e.data; - if (!this._frameEndpoint.authenticate(data)) { return; } - data = data.data; - - if (typeof data !== 'object' || data === null) { - this._logMessageError(e, 'Invalid data'); - return; - } - - const action = data.action; - if (typeof action !== 'string') { - this._logMessageError(e, 'Invalid data'); - return; + _onMessage(data) { + if (!this._frameEndpoint.authenticate(data)) { + throw new Error('Invalid authentication'); } + const {action, params} = data.data; const handlerInfo = this._windowMessageHandlers.get(action); if (typeof handlerInfo === 'undefined') { - this._logMessageError(e, `Invalid action: ${JSON.stringify(action)}`); - return; + throw new Error(`Invalid action: ${action}`); } - const handler = handlerInfo.handler; - handler(data.params); + const {async, handler} = handlerInfo; + const result = handler(params); + return {async, result}; } - async _onMessageConfigure({messageId, frameId, ownerFrameId, popupId, optionsContext, childrenSupported, scale}) { + async _onMessageConfigure({frameId, ownerFrameId, popupId, optionsContext, childrenSupported, scale}) { this._ownerFrameId = ownerFrameId; this.setOptionsContext(optionsContext); @@ -138,8 +130,6 @@ class DisplayFloat extends Display { } this._setContentScale(scale); - - api.sendMessageToFrame(frameId, 'popupConfigured', {messageId}); } _onMessageSetOptionsContext({optionsContext}) { @@ -183,10 +173,6 @@ class DisplayFloat extends Display { body.style.fontSize = `${scale}em`; } - _logMessageError(event, type) { - yomichan.logWarning(new Error(`Popup received invalid message from origin ${JSON.stringify(event.origin)}: ${type}`)); - } - async _prepareNestedPopups(id, depth, parentFrameId, url) { let complete = false; diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js index 78561de3..4f2de4f2 100644 --- a/ext/fg/js/popup.js +++ b/ext/fg/js/popup.js @@ -257,22 +257,7 @@ class Popup { await frameClient.connect(this._frame, this._targetOrigin, this._frameId, setupFrame); // Configure - const messageId = yomichan.generateId(16); - const popupPreparedPromise = yomichan.getTemporaryListenerResult( - chrome.runtime.onMessage, - (message, {resolve}) => { - if ( - isObject(message) && - message.action === 'popupConfigured' && - isObject(message.params) && - message.params.messageId === messageId - ) { - resolve(); - } - } - ); - this._invokeApi('configure', { - messageId, + await this._invokeApi('configure', { frameId: this._frameId, ownerFrameId: this._ownerFrameId, popupId: this._id, @@ -280,8 +265,6 @@ class Popup { childrenSupported: this._childrenSupported, scale: this._contentScale }); - - return popupPreparedPromise; } _onFrameLoad() { @@ -456,12 +439,12 @@ class Popup { return dark ? 'dark' : 'light'; } - _invokeApi(action, params={}) { + async _invokeApi(action, params={}) { const contentWindow = this._frame.contentWindow; if (this._frameClient === null || !this._frameClient.isConnected() || contentWindow === null) { return; } const message = this._frameClient.createMessage({action, params}); - contentWindow.postMessage(message, this._targetOrigin); + return await api.crossFrame.invoke(this._frameClient.frameId, 'popupMessage', message); } _getFrameParentElement() { diff --git a/ext/mixed/js/comm.js b/ext/mixed/js/comm.js index 0d6b8695..182400e3 100644 --- a/ext/mixed/js/comm.js +++ b/ext/mixed/js/comm.js @@ -172,29 +172,22 @@ class CrossFrameAPIPort extends EventDispatcher { return; } - const {handler, async} = messageHandler; + let {handler, async} = messageHandler; this._sendAck(id); - if (async) { - this._invokeHandlerAsync(id, handler, params); - } else { - this._invokeHandler(id, handler, params); - } - } - - _invokeHandler(id, handler, params) { - try { - const result = handler(params); - this._sendResult(id, result); - } catch (error) { - this._sendError(id, error); - } - } - - async _invokeHandlerAsync(id, handler, params) { try { - const result = await handler(params); - this._sendResult(id, result); + let result = handler(params); + if (async === 'dynamic') { + ({async, result} = result); + } + if (async) { + result.then( + (result2) => this._sendResult(id, result2), + (error2) => this._sendError(id, error2) + ); + } else { + this._sendResult(id, result); + } } catch (error) { this._sendError(id, error); } |