diff options
Diffstat (limited to 'ext/fg/js/popup.js')
| -rw-r--r-- | ext/fg/js/popup.js | 88 | 
1 files changed, 68 insertions, 20 deletions
diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js index b7d4b57e..5ee62c9b 100644 --- a/ext/fg/js/popup.js +++ b/ext/fg/js/popup.js @@ -17,7 +17,7 @@  /* global   * DOM - * apiOptionsGet + * api   * dynamicLoader   */ @@ -47,6 +47,9 @@ class Popup {          this._frame.style.width = '0';          this._frame.style.height = '0'; +        this._container = this._frame; +        this._shadow = null; +          this._fullscreenEventListeners = new EventListenerCollection();      } @@ -89,7 +92,7 @@ class Popup {          this._optionsContext = optionsContext;          this._previousOptionsContextSource = source; -        this._options = await apiOptionsGet(optionsContext); +        this._options = await api.optionsGet(optionsContext);          this.updateTheme();          this._invokeApi('setOptionsContext', {optionsContext}); @@ -180,7 +183,12 @@ class Popup {      }      async setCustomOuterCss(css, useWebExtensionApi) { -        return await dynamicLoader.loadStyle('yomichan-popup-outer-user-stylesheet', 'code', css, useWebExtensionApi); +        let parentNode = null; +        if (this._shadow !== null) { +            useWebExtensionApi = false; +            parentNode = this._shadow; +        } +        return await dynamicLoader.loadStyle('yomichan-popup-outer-user-stylesheet', 'code', css, useWebExtensionApi, parentNode);      }      setChildrenSupported(value) { @@ -195,6 +203,10 @@ class Popup {          return this._frame.getBoundingClientRect();      } +    getContainer() { +        return this._container; +    } +      // Private functions      _inject() { @@ -326,14 +338,25 @@ class Popup {      }      async _createInjectPromise() { -        this._injectStyles(); +        if (this._options === null) { +            throw new Error('Options not initialized'); +        } + +        const {useSecurePopupFrameUrl, usePopupShadowDom} = this._options.general; + +        await this._setUpContainer(usePopupShadowDom);          const {secret, token} = await this._initializeFrame(this._frame, this._targetOrigin, this._frameId, (frame) => {              frame.removeAttribute('src');              frame.removeAttribute('srcdoc');              this._observeFullscreen(true);              this._onFullscreenChanged(); -            frame.contentDocument.location.href = chrome.runtime.getURL('/fg/float.html'); +            const url = chrome.runtime.getURL('/fg/float.html'); +            if (useSecurePopupFrameUrl) { +                frame.contentDocument.location.href = url; +            } else { +                frame.setAttribute('src', url); +            }          });          this._frameSecret = secret;          this._frameToken = token; @@ -371,9 +394,9 @@ class Popup {      }      _resetFrame() { -        const parent = this._frame.parentNode; +        const parent = this._container.parentNode;          if (parent !== null) { -            parent.removeChild(this._frame); +            parent.removeChild(this._container);          }          this._frame.removeAttribute('src');          this._frame.removeAttribute('srcdoc'); @@ -384,9 +407,31 @@ class Popup {          this._injectPromiseComplete = false;      } +    async _setUpContainer(usePopupShadowDom) { +        if (usePopupShadowDom && typeof this._frame.attachShadow === 'function') { +            const container = document.createElement('div'); +            container.style.setProperty('all', 'initial', 'important'); +            const shadow = container.attachShadow({mode: 'closed', delegatesFocus: true}); +            shadow.appendChild(this._frame); + +            this._container = container; +            this._shadow = shadow; +        } else { +            const frameParentNode = this._frame.parentNode; +            if (frameParentNode !== null) { +                frameParentNode.removeChild(this._frame); +            } + +            this._container = this._frame; +            this._shadow = null; +        } + +        await this._injectStyles(); +    } +      async _injectStyles() {          try { -            await dynamicLoader.loadStyle('yomichan-popup-outer-stylesheet', 'file', '/fg/css/client.css', true); +            await this._injectPopupOuterStylesheet();          } catch (e) {              // NOP          } @@ -398,6 +443,18 @@ class Popup {          }      } +    async _injectPopupOuterStylesheet() { +        let fileType = 'file'; +        let useWebExtensionApi = true; +        let parentNode = null; +        if (this._shadow !== null) { +            fileType = 'file-content'; +            useWebExtensionApi = false; +            parentNode = this._shadow; +        } +        await dynamicLoader.loadStyle('yomichan-popup-outer-stylesheet', fileType, '/fg/css/client.css', useWebExtensionApi, parentNode); +    } +      _observeFullscreen(observe) {          if (!observe) {              this._fullscreenEventListeners.removeAllEventListeners(); @@ -409,22 +466,13 @@ class Popup {              return;          } -        const fullscreenEvents = [ -            'fullscreenchange', -            'MSFullscreenChange', -            'mozfullscreenchange', -            'webkitfullscreenchange' -        ]; -        const onFullscreenChanged = this._onFullscreenChanged.bind(this); -        for (const eventName of fullscreenEvents) { -            this._fullscreenEventListeners.addEventListener(document, eventName, onFullscreenChanged, false); -        } +        DOM.addFullscreenChangeEventListener(this._onFullscreenChanged.bind(this), this._fullscreenEventListeners);      }      _onFullscreenChanged() {          const parent = this._getFrameParentElement(); -        if (parent !== null && this._frame.parentNode !== parent) { -            parent.appendChild(this._frame); +        if (parent !== null && this._container.parentNode !== parent) { +            parent.appendChild(this._container);          }      }  |