diff options
| author | siikamiika <siikamiika@users.noreply.github.com> | 2020-03-19 02:55:31 +0200 | 
|---|---|---|
| committer | siikamiika <siikamiika@users.noreply.github.com> | 2020-04-05 19:57:37 +0300 | 
| commit | 4814db8df12598c167b1e97096511f43e32c5e36 (patch) | |
| tree | d577ade32f004092bd7d9d952f708a096e2ce26a /ext | |
| parent | b6c4914b79d96b06760093be8957fbb1730eff3b (diff) | |
adjust iframe popup position to root page
Diffstat (limited to 'ext')
| -rw-r--r-- | ext/fg/js/popup-proxy-host.js | 33 | ||||
| -rw-r--r-- | ext/fg/js/popup-proxy.js | 69 | 
2 files changed, 100 insertions, 2 deletions
| diff --git a/ext/fg/js/popup-proxy-host.js b/ext/fg/js/popup-proxy-host.js index 4dc79943..487dda90 100644 --- a/ext/fg/js/popup-proxy-host.js +++ b/ext/fg/js/popup-proxy-host.js @@ -19,6 +19,7 @@  /* global   * FrontendApiReceiver   * Popup + * apiForward   * apiFrameInformationGet   */ @@ -48,6 +49,12 @@ class PopupProxyHost {              ['clearAutoPlayTimer', this._onApiClearAutoPlayTimer.bind(this)],              ['setContentScale', this._onApiSetContentScale.bind(this)]          ])); + +        this._windowMessageHandlers = new Map([ +            ['getIframeOffset', ({offset, uniqueId}, e) => { return this._onGetIframeOffset(offset, uniqueId, e); }] +        ]); + +        window.addEventListener('message', this.onMessage.bind(this), false);      }      getOrCreatePopup(id=null, parentId=null, depth=null) { @@ -95,7 +102,7 @@ class PopupProxyHost {          return popup;      } -    // Message handlers +    // API message handlers      async _onApiGetOrCreatePopup({id, parentId}) {          const popup = this.getOrCreatePopup(id, parentId); @@ -152,6 +159,30 @@ class PopupProxyHost {          return popup.setContentScale(scale);      } +    // Window message handlers + +    onMessage(e) { +        const {action, params} = e.data; +        const handler = this._windowMessageHandlers.get(action); +        if (typeof handler !== 'function') { return; } +        handler(params, e); +    } + +    _onGetIframeOffset(offset, uniqueId, e) { +        let sourceIframe = null; +        for (const iframe of document.querySelectorAll('iframe:not(.yomichan-float)')) { +            if (iframe.contentWindow !== e.source) { continue; } +            sourceIframe = iframe; +            break; +        } +        if (sourceIframe === null) { return; } + +        const [forwardedX, forwardedY] = offset; +        const {x, y} = sourceIframe.getBoundingClientRect(); +        offset = [forwardedX + x, forwardedY + y]; +        apiForward('iframeOffset', {offset, uniqueId}); +    } +      // Private functions      _getPopup(id) { diff --git a/ext/fg/js/popup-proxy.js b/ext/fg/js/popup-proxy.js index 997b1317..c1ee76ce 100644 --- a/ext/fg/js/popup-proxy.js +++ b/ext/fg/js/popup-proxy.js @@ -29,6 +29,12 @@ class PopupProxy {          this._depth = depth;          this._url = url;          this._apiSender = new FrontendApiSender(); + +        this._windowMessageHandlers = new Map([ +            ['getIframeOffset', ({offset, uniqueId}, e) => { return this._onGetIframeOffset(offset, uniqueId, e); }] +        ]); + +        window.addEventListener('message', this.onMessage.bind(this), false);      }      // Public properties @@ -83,12 +89,19 @@ class PopupProxy {          if (this._id === null) {              return false;          } +        if (this._depth === 0) { +            [x, y] = await PopupProxy._convertIframePointToRootPagePoint(x, y); +        }          return await this._invokeHostApi('containsPoint', {id: this._id, x, y});      }      async showContent(elementRect, writingMode, type=null, details=null) {          const id = await this._getPopupId(); -        elementRect = PopupProxy._convertDOMRectToJson(elementRect); +        let {x, y, width, height} = PopupProxy._convertDOMRectToJson(elementRect); +        if (this._depth === 0) { +            [x, y] = await PopupProxy._convertIframePointToRootPagePoint(x, y); +            elementRect = {x, y, width, height}; +        }          return await this._invokeHostApi('showContent', {id, elementRect, writingMode, type, details});      } @@ -109,6 +122,31 @@ class PopupProxy {          this._invokeHostApi('setContentScale', {id, scale});      } +    // Window message handlers + +    onMessage(e) { +        const {action, params} = e.data; +        const handler = this._windowMessageHandlers.get(action); +        if (typeof handler !== 'function') { return; } +        handler(params, e); +    } + +    _onGetIframeOffset(offset, uniqueId, e) { +        let sourceIframe = null; +        for (const iframe of document.querySelectorAll('iframe:not(.yomichan-float)')) { +            if (iframe.contentWindow !== e.source) { continue; } +            sourceIframe = iframe; +            break; +        } +        if (sourceIframe === null) { return; } + +        const [forwardedX, forwardedY] = offset; +        const {x, y} = sourceIframe.getBoundingClientRect(); +        offset = [forwardedX + x, forwardedY + y]; +        window.parent.postMessage({action: 'getIframeOffset', params: {offset, uniqueId}}, '*'); +    } + +      // Private      _getPopupId() { @@ -131,6 +169,35 @@ class PopupProxy {          return this._apiSender.invoke(action, params, `popup-proxy-host#${this._parentFrameId}`);      } +    static async _convertIframePointToRootPagePoint(x, y) { +        const uniqueId = yomichan.generateId(16); + +        let frameOffsetResolve = null; +        const frameOffsetPromise = new Promise((resolve) => (frameOffsetResolve = resolve)); + +        const runtimeMessageCallback = ({action, params}, sender, callback) => { +            if (action === 'iframeOffset' && isObject(params) && params.uniqueId === uniqueId) { +                chrome.runtime.onMessage.removeListener(runtimeMessageCallback); +                callback(); +                frameOffsetResolve(params); +                return false; +            } +        }; +        chrome.runtime.onMessage.addListener(runtimeMessageCallback); + +        window.parent.postMessage({ +            action: 'getIframeOffset', +            params: { +                uniqueId, +                offset: [x, y] +            } +        }, '*'); + +        const {offset} = await frameOffsetPromise; + +        return offset; +    } +      static _convertDOMRectToJson(domRect) {          return {              x: domRect.x, |