diff options
| author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2020-07-18 14:15:36 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-07-18 14:15:36 -0400 | 
| commit | dac33e696145ad3c2cfe076a7fadc82c05732102 (patch) | |
| tree | 06dff8bd7dd2d8ebad5a025cf71e2910b2af80d4 | |
| parent | f9c76efea00ff62021119c4d0fcf414e8988be1d (diff) | |
Extension unload indication fix (#662)
* Remove unused function
* Rename field
* Change extensionUnloaded trigger function
* Update how extension unloaded content is shown
* Ignore certain errors caused by extension unload
* Add _showExtensionUnloaded function
* Wrap internals of updateOptions
* Suppress errors caued by extension unload
* Make the frontend trigger the popup's extensionUnloaded event
| -rw-r--r-- | ext/fg/js/float.js | 25 | ||||
| -rw-r--r-- | ext/fg/js/frontend.js | 76 | ||||
| -rw-r--r-- | ext/fg/js/popup-proxy.js | 14 | ||||
| -rw-r--r-- | ext/fg/js/popup.js | 32 | ||||
| -rw-r--r-- | ext/mixed/js/display.js | 15 | ||||
| -rw-r--r-- | ext/mixed/js/yomichan.js | 12 | 
6 files changed, 119 insertions, 55 deletions
| diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js index 61d42fb3..690d1b9e 100644 --- a/ext/fg/js/float.js +++ b/ext/fg/js/float.js @@ -31,7 +31,7 @@ class DisplayFloat extends Display {          this._nestedPopupsPrepared = false;          this._ownerFrameId = null;          this._frameEndpoint = new FrameEndpoint(); -        this._windowMessageHandlers = new Map([ +        this._messageHandlers = new Map([              ['configure',          {async: true,  handler: this._onMessageConfigure.bind(this)}],              ['setOptionsContext',  {async: false, handler: this._onMessageSetOptionsContext.bind(this)}],              ['setContent',         {async: false, handler: this._onMessageSetContent.bind(this)}], @@ -39,6 +39,9 @@ class DisplayFloat extends Display {              ['setCustomCss',       {async: false, handler: this._onMessageSetCustomCss.bind(this)}],              ['setContentScale',    {async: false, handler: this._onMessageSetContentScale.bind(this)}]          ]); +        this._windowMessageHandlers = new Map([ +            ['extensionUnloaded', {async: false, handler: this._onMessageExtensionUnloaded.bind(this)}] +        ]);          this.registerActions([              ['copy-host-selection', () => this._copySelection()] @@ -54,6 +57,7 @@ class DisplayFloat extends Display {          api.crossFrame.registerHandlers([              ['popupMessage', {async: 'dynamic', handler: this._onMessage.bind(this)}]          ]); +        window.addEventListener('message', this._onWindowMessage.bind(this), false);          this._frameEndpoint.signal();      } @@ -107,7 +111,7 @@ class DisplayFloat extends Display {          }          const {action, params} = data.data; -        const handlerInfo = this._windowMessageHandlers.get(action); +        const handlerInfo = this._messageHandlers.get(action);          if (typeof handlerInfo === 'undefined') {              throw new Error(`Invalid action: ${action}`);          } @@ -117,6 +121,18 @@ class DisplayFloat extends Display {          return {async, result};      } +    _onWindowMessage(e) { +        const data = e.data; +        if (!this._frameEndpoint.authenticate(data)) { return; } + +        const {action, params} = data.data; +        const messageHandler = this._windowMessageHandlers.get(action); +        if (typeof messageHandler === 'undefined') { return; } + +        const callback = () => {}; // NOP +        yomichan.invokeMessageHandler(messageHandler, params, callback); +    } +      async _onMessageConfigure({frameId, ownerFrameId, popupId, optionsContext, childrenSupported, scale}) {          this._ownerFrameId = ownerFrameId;          this.setOptionsContext(optionsContext); @@ -152,6 +168,11 @@ class DisplayFloat extends Display {          this._setContentScale(scale);      } +    _onMessageExtensionUnloaded() { +        if (yomichan.isExtensionUnloaded) { return; } +        yomichan.triggerExtensionUnloaded(); +    } +      // Private      _copySelection() { diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js index aa03d4b5..bd64f1ac 100644 --- a/ext/fg/js/frontend.js +++ b/ext/fg/js/frontend.js @@ -147,26 +147,13 @@ class Frontend {      }      async updateOptions() { -        const optionsContext = await this.getOptionsContext(); -        this._options = await api.optionsGet(optionsContext); - -        await this._updatePopup(); - -        this._textScanner.setOptions(this._options); -        this._updateTextScannerEnabled(); - -        const ignoreNodes = ['.scan-disable', '.scan-disable *']; -        if (!this._options.scanning.enableOnPopupExpressions) { -            ignoreNodes.push('.source-text', '.source-text *'); -        } -        this._textScanner.ignoreNodes = ignoreNodes.join(','); - -        this._updateContentScale(); - -        const textSourceCurrent = this._textScanner.getCurrentTextSource(); -        const causeCurrent = this._textScanner.causeCurrent; -        if (textSourceCurrent !== null && causeCurrent !== null) { -            await this._search(textSourceCurrent, causeCurrent); +        try { +            await this._updateOptionsInternal(); +        } catch (e) { +            if (!yomichan.isExtensionUnloaded) { +                throw e; +            } +            this._showExtensionUnloaded(null);          }      } @@ -243,6 +230,30 @@ class Frontend {          await this.updateOptions();      } +    async _updateOptionsInternal() { +        const optionsContext = await this.getOptionsContext(); +        this._options = await api.optionsGet(optionsContext); + +        await this._updatePopup(); + +        this._textScanner.setOptions(this._options); +        this._updateTextScannerEnabled(); + +        const ignoreNodes = ['.scan-disable', '.scan-disable *']; +        if (!this._options.scanning.enableOnPopupExpressions) { +            ignoreNodes.push('.source-text', '.source-text *'); +        } +        this._textScanner.ignoreNodes = ignoreNodes.join(','); + +        this._updateContentScale(); + +        const textSourceCurrent = this._textScanner.getCurrentTextSource(); +        const causeCurrent = this._textScanner.causeCurrent; +        if (textSourceCurrent !== null && causeCurrent !== null) { +            await this._search(textSourceCurrent, causeCurrent); +        } +    } +      async _updatePopup() {          const showIframePopupsInRootFrame = this._options.general.showIframePopupsInRootFrame;          const isIframe = !this._useProxyPopup && (window !== window.parent); @@ -328,8 +339,15 @@ class Frontend {          return this._popup === null || this._popup.isProxy() ? [] : [this._popup.getContainer()];      } -    _ignorePoint(x, y) { -        return this._popup !== null && this._popup.containsPoint(x, y); +    async _ignorePoint(x, y) { +        try { +            return this._popup !== null && await this._popup.containsPoint(x, y); +        } catch (e) { +            if (!yomichan.isExtensionUnloaded) { +                throw e; +            } +            return false; +        }      }      async _search(textSource, cause) { @@ -352,7 +370,7 @@ class Frontend {          } catch (e) {              if (yomichan.isExtensionUnloaded) {                  if (textSource !== null && this._options.scanning.modifier !== 'none') { -                    this._showPopupContent(textSource, await this.getOptionsContext(), 'extensionUnloaded'); +                    this._showExtensionUnloaded(textSource);                  }              } else {                  yomichan.logError(e); @@ -392,6 +410,14 @@ class Frontend {          return {definitions, type: 'kanji'};      } +    async _showExtensionUnloaded(textSource) { +        if (textSource === null) { +            textSource = this._textScanner.getCurrentTextSource(); +            if (textSource === null) { return; } +        } +        this._showPopupContent(textSource, await this.getOptionsContext()); +    } +      _showContent(textSource, focus, definitions, type, optionsContext) {          const {url} = optionsContext;          const sentenceExtent = this._options.anki.sentenceExt; @@ -414,6 +440,10 @@ class Frontend {              details,              context          ); +        this._lastShowPromise.catch((error) => { +            if (yomichan.isExtensionUnloaded) { return; } +            yomichan.logError(error); +        });          return this._lastShowPromise;      } diff --git a/ext/fg/js/popup-proxy.js b/ext/fg/js/popup-proxy.js index 352c5b34..09c184db 100644 --- a/ext/fg/js/popup-proxy.js +++ b/ext/fg/js/popup-proxy.js @@ -69,7 +69,11 @@ class PopupProxy extends EventDispatcher {      }      async isVisible() { -        return await this._invoke('isVisible', {id: this._id}); +        try { +            return await this._invoke('isVisible', {id: this._id}); +        } catch (e) { +            return false; +        }      }      setVisibleOverride(visible) { @@ -98,8 +102,12 @@ class PopupProxy extends EventDispatcher {          this._invoke('setCustomCss', {id: this._id, css});      } -    clearAutoPlayTimer() { -        this._invoke('clearAutoPlayTimer', {id: this._id}); +    async clearAutoPlayTimer() { +        try { +            await this._invoke('clearAutoPlayTimer', {id: this._id}); +        } catch (e) { +            // NOP +        }      }      setContentScale(scale) { diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js index 4f2de4f2..35e66044 100644 --- a/ext/fg/js/popup.js +++ b/ext/fg/js/popup.js @@ -83,6 +83,7 @@ class Popup {          this._frame.addEventListener('mousedown', (e) => e.stopPropagation());          this._frame.addEventListener('scroll', (e) => e.stopPropagation());          this._frame.addEventListener('load', this._onFrameLoad.bind(this)); +        yomichan.on('extensionUnloaded', this._onExtensionUnloaded.bind(this));      }      isProxy() { @@ -149,8 +150,12 @@ class Popup {          this._invokeApi('setCustomCss', {css});      } -    clearAutoPlayTimer() { -        this._invokeApi('clearAutoPlayTimer'); +    async clearAutoPlayTimer() { +        try { +            await this._invokeApi('clearAutoPlayTimer'); +        } catch (e) { +            // NOP +        }      }      setContentScale(scale) { @@ -447,6 +452,18 @@ class Popup {          return await api.crossFrame.invoke(this._frameClient.frameId, 'popupMessage', message);      } +    _invokeWindowApi(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); +    } + +    _onExtensionUnloaded() { +        this._invokeWindowApi('extensionUnloaded'); +    } +      _getFrameParentElement() {          const defaultParent = document.body;          const fullscreenElement = DOM.getFullscreenElement(); @@ -636,15 +653,4 @@ class Popup {              bottom: window.innerHeight          };      } - -    static isFrameAboutBlank(frame) { -        try { -            const contentDocument = frame.contentDocument; -            if (contentDocument === null) { return false; } -            const url = contentDocument.location.href; -            return /^about:blank(?:[#?]|$)/.test(url); -        } catch (e) { -            return false; -        } -    }  } diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 7dc63e65..bf3e3eae 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -97,14 +97,12 @@ class Display {          this._setInteractive(true);          await yomichan.ready();          await this._displayGenerator.prepare(); +        yomichan.on('extensionUnloaded', this._onExtensionUnloaded.bind(this));      }      onError(error) { -        if (yomichan.isExtensionUnloaded) { -            this.setContent('extensionUnloaded'); -        } else { -            yomichan.logError(error); -        } +        if (yomichan.isExtensionUnloaded) { return; } +        yomichan.logError(error);      }      onEscape() { @@ -176,9 +174,6 @@ class Display {                  case 'kanji':                      await this._setContentKanji(details.definitions, details.context, token);                      break; -                case 'extensionUnloaded': -                    this._setContentExtensionUnloaded(); -                    break;              }          } catch (e) {              this.onError(e); @@ -236,6 +231,10 @@ class Display {      // Private +    _onExtensionUnloaded() { +        this._setContentExtensionUnloaded(); +    } +      _onSourceTermView(e) {          e.preventDefault();          this._sourceTermView(); diff --git a/ext/mixed/js/yomichan.js b/ext/mixed/js/yomichan.js index 7fffbaa6..33870658 100644 --- a/ext/mixed/js/yomichan.js +++ b/ext/mixed/js/yomichan.js @@ -196,7 +196,7 @@ const yomichan = (() => {              try {                  return chrome.runtime.sendMessage(...args);              } catch (e) { -                this._onExtensionUnloaded(e); +                this.triggerExtensionUnloaded();                  throw e;              }          } @@ -205,7 +205,7 @@ const yomichan = (() => {              try {                  return chrome.runtime.connect(...args);              } catch (e) { -                this._onExtensionUnloaded(e); +                this.triggerExtensionUnloaded();                  throw e;              }          } @@ -247,13 +247,13 @@ const yomichan = (() => {              }          } -        // Private - -        _onExtensionUnloaded(error) { +        triggerExtensionUnloaded() {              this._isExtensionUnloaded = true; -            this.trigger('extensionUnloaded', {error}); +            this.trigger('extensionUnloaded');          } +        // Private +          _getUrl() {              return (typeof window === 'object' && window !== null ? window.location.href : '');          } |