diff options
| author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2019-08-18 20:51:19 -0400 | 
|---|---|---|
| committer | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2019-09-02 19:33:28 -0400 | 
| commit | 53aad0bef68bf6930b684fda4a25e1a045cd800e (patch) | |
| tree | 4e91dd4f3e6bac8ceefd7ecb321d15c024459f3f | |
| parent | 42ec3e2a43dfd9ac0748ca7c364cef2b44f625a2 (diff) | |
Fix messaging issues when iframes are present in the document
| -rw-r--r-- | ext/bg/js/api.js | 5 | ||||
| -rw-r--r-- | ext/bg/js/backend.js | 4 | ||||
| -rw-r--r-- | ext/bg/js/search-frontend.js | 2 | ||||
| -rw-r--r-- | ext/fg/js/api.js | 4 | ||||
| -rw-r--r-- | ext/fg/js/frontend-api-receiver.js | 16 | ||||
| -rw-r--r-- | ext/fg/js/frontend-api-sender.js | 8 | ||||
| -rw-r--r-- | ext/fg/js/frontend.js | 10 | ||||
| -rw-r--r-- | ext/fg/js/popup-proxy-host.js | 21 | ||||
| -rw-r--r-- | ext/fg/js/popup-proxy.js | 9 | ||||
| -rw-r--r-- | ext/fg/js/popup.js | 55 | ||||
| -rw-r--r-- | ext/manifest.json | 2 | 
11 files changed, 97 insertions, 39 deletions
| diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index 4b2bacd7..b8ef4362 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -205,3 +205,8 @@ function apiForward(action, params, sender) {          chrome.tabs.sendMessage(tabId, {action, params}, (response) => resolve(response));      });  } + +function apiFrameInformationGet(sender) { +    const frameId = sender.frameId; +    return Promise.resolve({frameId}); +} diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 8f99c13a..39fd4288 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -127,6 +127,10 @@ class Backend {              forward: ({action, params}) => {                  forward(apiForward(action, params, sender), callback); +            }, + +            frameInformationGet: () => { +                forward(apiFrameInformationGet(sender), callback);              }          }; diff --git a/ext/bg/js/search-frontend.js b/ext/bg/js/search-frontend.js index 77aa4052..840a1ea8 100644 --- a/ext/bg/js/search-frontend.js +++ b/ext/bg/js/search-frontend.js @@ -25,8 +25,8 @@ async function searchFrontendSetup() {          '/fg/js/api.js',          '/fg/js/frontend-api-receiver.js',          '/fg/js/popup.js', -        '/fg/js/popup-proxy-host.js',          '/fg/js/util.js', +        '/fg/js/popup-proxy-host.js',          '/fg/js/frontend.js'      ];      for (const src of scriptSrcs) { diff --git a/ext/fg/js/api.js b/ext/fg/js/api.js index 99ad307c..6bcb0dbb 100644 --- a/ext/fg/js/api.js +++ b/ext/fg/js/api.js @@ -64,3 +64,7 @@ function apiScreenshotGet(options) {  function apiForward(action, params) {      return utilInvoke('forward', {action, params});  } + +function apiFrameInformationGet() { +    return utilInvoke('frameInformationGet'); +} diff --git a/ext/fg/js/frontend-api-receiver.js b/ext/fg/js/frontend-api-receiver.js index f5d29f67..687e5c3c 100644 --- a/ext/fg/js/frontend-api-receiver.js +++ b/ext/fg/js/frontend-api-receiver.js @@ -31,7 +31,7 @@ class FrontendApiReceiver {          port.onMessage.addListener(this.onMessage.bind(this, port));      } -    onMessage(port, {id, action, params, target}) { +    onMessage(port, {id, action, params, target, senderId}) {          if (              target !== this.source ||              !this.handlers.hasOwnProperty(action) @@ -39,24 +39,24 @@ class FrontendApiReceiver {              return;          } -        this.sendAck(port, id); +        this.sendAck(port, id, senderId);          const handler = this.handlers[action];          handler(params).then(              result => { -                this.sendResult(port, id, {result}); +                this.sendResult(port, id, senderId, {result});              },              e => {                  const error = typeof e.toString === 'function' ? e.toString() : e; -                this.sendResult(port, id, {error}); +                this.sendResult(port, id, senderId, {error});              });      } -    sendAck(port, id) { -        port.postMessage({type: 'ack', id}); +    sendAck(port, id, senderId) { +        port.postMessage({type: 'ack', id, senderId});      } -    sendResult(port, id, data) { -        port.postMessage({type: 'result', id, data}); +    sendResult(port, id, senderId, data) { +        port.postMessage({type: 'result', id, senderId, data});      }  } diff --git a/ext/fg/js/frontend-api-sender.js b/ext/fg/js/frontend-api-sender.js index e2becb90..a1cb02c4 100644 --- a/ext/fg/js/frontend-api-sender.js +++ b/ext/fg/js/frontend-api-sender.js @@ -19,6 +19,7 @@  class FrontendApiSender {      constructor() { +        this.senderId = FrontendApiSender.generateId(16);          this.ackTimeout = 3000; // 3 seconds          this.responseTimeout = 10000; // 10 seconds          this.callbacks = {}; @@ -43,11 +44,12 @@ class FrontendApiSender {              this.callbacks[id] = info;              info.timer = setTimeout(() => this.onError(id, 'Timeout (ack)'), this.ackTimeout); -            this.port.postMessage({id, action, params, target}); +            this.port.postMessage({id, action, params, target, senderId: this.senderId});          });      } -    onMessage({type, id, data}) { +    onMessage({type, id, data, senderId}) { +        if (senderId !== this.senderId) { return; }          switch (type) {              case 'ack':                  this.onAck(id); @@ -69,7 +71,7 @@ class FrontendApiSender {      onAck(id) {          if (!this.callbacks.hasOwnProperty(id)) { -            console.warn(`ID ${id} not found`); +            console.warn(`ID ${id} not found for ack`);              return;          } diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js index d378dd61..9c511d8a 100644 --- a/ext/fg/js/frontend.js +++ b/ext/fg/js/frontend.js @@ -42,14 +42,20 @@ class Frontend {          const isNested = (currentUrl === floatUrl);          let id = null; +        let parentFrameId = null;          if (isNested) { -            const match = /[&?]id=([^&]*?)(?:&|$)/.exec(location.href); +            let match = /[&?]id=([^&]*?)(?:&|$)/.exec(location.href);              if (match !== null) {                  id = match[1];              } + +            match = /[&?]parent=(\d+)(?:&|$)/.exec(location.href); +            if (match !== null) { +                parentFrameId = parseInt(match[1], 10); +            }          } -        const popup = isNested ? new PopupProxy(id) : PopupProxyHost.instance.createPopup(); +        const popup = isNested ? new PopupProxy(id, parentFrameId) : PopupProxyHost.instance.createPopup(null);          const frontend = new Frontend(popup);          frontend.prepare();          return frontend; diff --git a/ext/fg/js/popup-proxy-host.js b/ext/fg/js/popup-proxy-host.js index ba3db832..cdd1d02c 100644 --- a/ext/fg/js/popup-proxy-host.js +++ b/ext/fg/js/popup-proxy-host.js @@ -21,7 +21,22 @@ class PopupProxyHost {      constructor() {          this.popups = {};          this.nextId = 0; -        this.apiReceiver = new FrontendApiReceiver('popup-proxy-host', { +        this.apiReceiver = null; +        this.frameIdPromise = null; +    } + +    static create() { +        const popupProxyHost = new PopupProxyHost(); +        popupProxyHost.prepare(); +        return popupProxyHost; +    } + +    async prepare() { +        this.frameIdPromise = apiFrameInformationGet(); +        const {frameId} = await this.frameIdPromise; +        if (typeof frameId !== 'number') { return; } + +        this.apiReceiver = new FrontendApiReceiver(`popup-proxy-host#${frameId}`, {              createNestedPopup: ({parentId}) => this.createNestedPopup(parentId),              show: ({id, elementRect, options}) => this.show(id, elementRect, options),              showOrphaned: ({id, elementRect, options}) => this.show(id, elementRect, options), @@ -39,7 +54,7 @@ class PopupProxyHost {          const depth = (parent !== null ? parent.depth + 1 : 0);          const id = `${this.nextId}`;          ++this.nextId; -        const popup = new Popup(id, depth); +        const popup = new Popup(id, depth, this.frameIdPromise);          if (parent !== null) {              popup.parent = parent;              parent.children.push(popup); @@ -116,4 +131,4 @@ class PopupProxyHost {      }  } -PopupProxyHost.instance = new PopupProxyHost(); +PopupProxyHost.instance = PopupProxyHost.create(); diff --git a/ext/fg/js/popup-proxy.js b/ext/fg/js/popup-proxy.js index 3a15be7d..bbf6a2cf 100644 --- a/ext/fg/js/popup-proxy.js +++ b/ext/fg/js/popup-proxy.js @@ -18,12 +18,14 @@  class PopupProxy { -    constructor(parentId) { +    constructor(parentId, parentFrameId) {          this.parentId = parentId; +        this.parentFrameId = parentFrameId;          this.id = null;          this.idPromise = null;          this.parent = null;          this.children = []; +        this.depth = 0;          this.container = null; @@ -102,7 +104,10 @@ class PopupProxy {      }      invokeHostApi(action, params={}) { -        return this.apiSender.invoke(action, params, 'popup-proxy-host'); +        if (typeof this.parentFrameId !== 'number') { +            return Promise.reject('Invalid frame'); +        } +        return this.apiSender.invoke(action, params, `popup-proxy-host#${this.parentFrameId}`);      }      static DOMRectToJson(domRect) { diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js index 00dfeb89..24b5684d 100644 --- a/ext/fg/js/popup.js +++ b/ext/fg/js/popup.js @@ -18,38 +18,55 @@  class Popup { -    constructor(id, depth) { +    constructor(id, depth, frameIdPromise) {          this.id = id;          this.depth = depth; +        this.frameIdPromise = frameIdPromise; +        this.frameId = null;          this.parent = null;          this.children = [];          this.container = document.createElement('iframe');          this.container.id = 'yomichan-float';          this.container.addEventListener('mousedown', e => e.stopPropagation());          this.container.addEventListener('scroll', e => e.stopPropagation()); -        this.container.setAttribute('src', chrome.extension.getURL(`/fg/float.html?id=${id}&depth=${depth}`));          this.container.style.width = '0px';          this.container.style.height = '0px'; -        this.injected = null; +        this.injectPromise = null; +        this.isInjected = false;      }      inject(options) { -        if (!this.injected) { -            this.injected = new Promise((resolve, reject) => { -                this.container.addEventListener('load', () => { -                    this.invokeApi('setOptions', { -                        general: { -                            customPopupCss: options.general.customPopupCss -                        } -                    }); -                    resolve(); -                }); -                this.observeFullscreen(); -                this.onFullscreenChanged(); -            }); +        if (this.injectPromise === null) { +            this.injectPromise = this.createInjectPromise(options); +        } +        return this.injectPromise; +    } + +    async createInjectPromise(options) { +        try { +            const {frameId} = await this.frameIdPromise; +            if (typeof frameId === 'number') { +                this.frameId = frameId; +            } +        } catch (e) { +            // NOP          } -        return this.injected; +        return new Promise((resolve) => { +            const parent = (typeof this.frameId === 'number' ? this.frameId : ''); +            this.container.setAttribute('src', chrome.extension.getURL(`/fg/float.html?id=${this.id}&depth=${this.depth}&parent=${parent}`)); +            this.container.addEventListener('load', () => { +                this.invokeApi('setOptions', { +                    general: { +                        customPopupCss: options.general.customPopupCss +                    } +                }); +                resolve(); +            }); +            this.observeFullscreen(); +            this.onFullscreenChanged(); +            this.isInjected = true; +        });      }      async show(elementRect, writingMode, options) { @@ -215,7 +232,7 @@ class Popup {      }      isVisible() { -        return this.injected && this.container.style.visibility !== 'hidden'; +        return this.isInjected && this.container.style.visibility !== 'hidden';      }      setVisible(visible) { @@ -260,7 +277,7 @@ class Popup {      }      clearAutoPlayTimer() { -        if (this.injected) { +        if (this.isInjected) {              this.invokeApi('clearAutoPlayTimer');          }      } diff --git a/ext/manifest.json b/ext/manifest.json index eed6e40a..06d13dd1 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -23,9 +23,9 @@              "fg/js/document.js",              "fg/js/frontend-api-receiver.js",              "fg/js/popup.js", -            "fg/js/popup-proxy-host.js",              "fg/js/source.js",              "fg/js/util.js", +            "fg/js/popup-proxy-host.js",              "fg/js/frontend.js"          ],          "css": ["fg/css/client.css"], |