diff options
| -rw-r--r-- | ext/bg/js/search.js | 41 | ||||
| -rw-r--r-- | ext/fg/js/float.js | 102 | ||||
| -rw-r--r-- | ext/mixed/js/display.js | 107 | 
3 files changed, 126 insertions, 124 deletions
| diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index b046806e..a3741da0 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -19,11 +19,8 @@   * ClipboardMonitor   * DOM   * Display - * Frontend - * PopupFactory   * QueryParser   * api - * dynamicLoader   * wanakana   */ @@ -63,11 +60,6 @@ class DisplaySearch extends Display {          this._runtimeMessageHandlers = new Map([              ['updateSearchQuery', {async: false, handler: this._onExternalSearchUpdate.bind(this)}]          ]); - -        this.setOptionsContext({ -            depth: 0, -            url: window.location.href -        });      }      async prepare() { @@ -407,7 +399,11 @@ class DisplaySearch extends Display {              yomichan.off('optionsUpdated', onOptionsUpdated);              try { -                await this._setupNestedPopups(); +                await this.setupNestedPopups({ +                    depth: 1, +                    proxy: false, +                    isSearchPage: true +                });              } catch (e) {                  yomichan.logError(e);              } @@ -417,31 +413,4 @@ class DisplaySearch extends Display {          await onOptionsUpdated();      } - -    async _setupNestedPopups() { -        await dynamicLoader.loadScripts([ -            '/mixed/js/text-scanner.js', -            '/mixed/js/frame-client.js', -            '/fg/js/frame-offset-forwarder.js', -            '/fg/js/popup.js', -            '/fg/js/popup-factory.js', -            '/fg/js/frontend.js' -        ]); - -        const {frameId} = await api.frameInformationGet(); - -        const popupFactory = new PopupFactory(frameId); -        popupFactory.prepare(); - -        const frontend = new Frontend( -            frameId, -            popupFactory, -            { -                depth: 1, -                proxy: false, -                isSearchPage: true -            } -        ); -        await frontend.prepare(); -    }  } diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js index 690d1b9e..f23a9b93 100644 --- a/ext/fg/js/float.js +++ b/ext/fg/js/float.js @@ -18,27 +18,15 @@  /* global   * Display   * FrameEndpoint - * Frontend - * PopupFactory   * api - * dynamicLoader   */  class DisplayFloat extends Display {      constructor() {          super(document.querySelector('#spinner'), document.querySelector('#definitions')); -        this._autoPlayAudioTimer = null;          this._nestedPopupsPrepared = false;          this._ownerFrameId = null;          this._frameEndpoint = new FrameEndpoint(); -        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)}], -            ['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._windowMessageHandlers = new Map([              ['extensionUnloaded', {async: false, handler: this._onMessageExtensionUnloaded.bind(this)}]          ]); @@ -49,13 +37,16 @@ class DisplayFloat extends Display {          this.registerHotkeys([              {key: 'C', modifiers: ['ctrl'], action: 'copy-host-selection'}          ]); + +        this.autoPlayAudioDelay = 400;      }      async prepare() {          await super.prepare(); -        api.crossFrame.registerHandlers([ -            ['popupMessage', {async: 'dynamic', handler: this._onMessage.bind(this)}] +        this.registerMessageHandlers([ +            ['configure',       {async: true,  handler: this._onMessageConfigure.bind(this)}], +            ['setContentScale', {async: false, handler: this._onMessageSetContentScale.bind(this)}]          ]);          window.addEventListener('message', this._onWindowMessage.bind(this), false); @@ -98,29 +89,15 @@ class DisplayFloat extends Display {          }      } -    autoPlayAudio() { -        this._clearAutoPlayTimer(); -        this._autoPlayAudioTimer = window.setTimeout(() => super.autoPlayAudio(), 400); -    } - -    // Message handling - -    _onMessage(data) { +    authenticateMessageData(data) {          if (!this._frameEndpoint.authenticate(data)) {              throw new Error('Invalid authentication');          } - -        const {action, params} = data.data; -        const handlerInfo = this._messageHandlers.get(action); -        if (typeof handlerInfo === 'undefined') { -            throw new Error(`Invalid action: ${action}`); -        } - -        const {async, handler} = handlerInfo; -        const result = handler(params); -        return {async, result}; +        return data.data;      } +    // Message handling +      _onWindowMessage(e) {          const data = e.data;          if (!this._frameEndpoint.authenticate(data)) { return; } @@ -148,22 +125,6 @@ class DisplayFloat extends Display {          this._setContentScale(scale);      } -    _onMessageSetOptionsContext({optionsContext}) { -        this.setOptionsContext(optionsContext); -    } - -    _onMessageSetContent({type, details}) { -        this.setContent(type, details); -    } - -    _onMessageClearAutoPlayTimer() { -        this._clearAutoPlayTimer.bind(this); -    } - -    _onMessageSetCustomCss({css}) { -        this.setCustomCss(css); -    } -      _onMessageSetContentScale({scale}) {          this._setContentScale(scale);      } @@ -181,13 +142,6 @@ class DisplayFloat extends Display {          return true;      } -    _clearAutoPlayTimer() { -        if (this._autoPlayAudioTimer) { -            window.clearTimeout(this._autoPlayAudioTimer); -            this._autoPlayAudioTimer = null; -        } -    } -      _setContentScale(scale) {          const body = document.body;          if (body === null) { return; } @@ -207,7 +161,13 @@ class DisplayFloat extends Display {              yomichan.off('optionsUpdated', onOptionsUpdated);              try { -                await this._setupNestedPopups(id, depth, parentFrameId, url); +                await this.setupNestedPopups({ +                    id, +                    depth, +                    parentFrameId, +                    url, +                    proxy: true +                });              } catch (e) {                  yomichan.logError(e);              } @@ -218,36 +178,6 @@ class DisplayFloat extends Display {          await onOptionsUpdated();      } -    async _setupNestedPopups(id, depth, parentFrameId, url) { -        await dynamicLoader.loadScripts([ -            '/mixed/js/text-scanner.js', -            '/mixed/js/frame-client.js', -            '/fg/js/popup.js', -            '/fg/js/popup-proxy.js', -            '/fg/js/popup-factory.js', -            '/fg/js/frame-offset-forwarder.js', -            '/fg/js/frontend.js' -        ]); - -        const {frameId} = await api.frameInformationGet(); - -        const popupFactory = new PopupFactory(frameId); -        popupFactory.prepare(); - -        const frontend = new Frontend( -            frameId, -            popupFactory, -            { -                id, -                depth, -                parentFrameId, -                url, -                proxy: true -            } -        ); -        await frontend.prepare(); -    } -      _invoke(action, params={}) {          return api.crossFrame.invoke(this._ownerFrameId, action, params);      } diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 82e77353..4e6794f3 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -20,11 +20,14 @@   * DOM   * DisplayContext   * DisplayGenerator + * Frontend   * MediaLoader + * PopupFactory   * WindowScroll   * api   * docRangeFromPoint   * docSentenceExtract + * dynamicLoader   */  class Display { @@ -32,7 +35,7 @@ class Display {          this._spinner = spinner;          this._container = container;          this._definitions = []; -        this._optionsContext = null; +        this._optionsContext = {depth: 0, url: window.location.href};          this._options = null;          this._context = null;          this._index = 0; @@ -53,11 +56,14 @@ class Display {          this._eventListenersActive = false;          this._clickScanPrevent = false;          this._setContentToken = null; +        this._autoPlayAudioTimer = null; +        this._autoPlayAudioDelay = 0;          this._mediaLoader = new MediaLoader();          this._displayGenerator = new DisplayGenerator({mediaLoader: this._mediaLoader});          this._windowScroll = new WindowScroll();          this._hotkeys = new Map();          this._actions = new Map(); +        this._messageHandlers = new Map();          this.registerActions([              ['close',               () => { this.onEscape(); }], @@ -91,12 +97,29 @@ class Display {              {key: 'P',         modifiers: ['alt'], action: 'play-audio'},              {key: 'V',         modifiers: ['alt'], action: 'view-note'}          ]); +        this.registerMessageHandlers([ +            ['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)}] +        ]); +    } + +    get autoPlayAudioDelay() { +        return this._autoPlayAudioDelay; +    } + +    set autoPlayAudioDelay(value) { +        this._autoPlayAudioDelay = value;      }      async prepare() {          this._setInteractive(true);          await this._displayGenerator.prepare();          yomichan.on('extensionUnloaded', this._onExtensionUnloaded.bind(this)); +        api.crossFrame.registerHandlers([ +            ['popupMessage', {async: 'dynamic', handler: this._onMessage.bind(this)}] +        ]);      }      onError(error) { @@ -155,9 +178,28 @@ class Display {      }      autoPlayAudio() { +        this.clearAutoPlayTimer(); +          if (this._definitions.length === 0) { return; } -        this._audioPlay(this._definitions[0], this._getFirstExpressionIndex(), 0); +        const definition = this._definitions[0]; +        const expressionIndex = this._getFirstExpressionIndex(); +        const callback = () => { +            this._audioPlay(definition, expressionIndex, 0); +        }; + +        if (this._autoPlayAudioDelay > 0) { +            this._autoPlayAudioTimer = setTimeout(callback, this._autoPlayAudioDelay); +        } else { +            callback(); +        } +    } + +    clearAutoPlayTimer() { +        if (this._autoPlayAudioTimer !== null) { +            clearTimeout(this._autoPlayAudioTimer); +            this._autoPlayAudioTimer = null; +        }      }      async setContent(type, details) { @@ -228,6 +270,67 @@ class Display {          }      } +    registerMessageHandlers(handlers) { +        for (const [name, handlerInfo] of handlers) { +            this._messageHandlers.set(name, handlerInfo); +        } +    } + +    async setupNestedPopups(frontendInitializationData) { +        await dynamicLoader.loadScripts([ +            '/mixed/js/text-scanner.js', +            '/mixed/js/frame-client.js', +            '/fg/js/popup.js', +            '/fg/js/popup-proxy.js', +            '/fg/js/popup-factory.js', +            '/fg/js/frame-offset-forwarder.js', +            '/fg/js/frontend.js' +        ]); + +        const {frameId} = await api.frameInformationGet(); + +        const popupFactory = new PopupFactory(frameId); +        popupFactory.prepare(); + +        const frontend = new Frontend(frameId, popupFactory, frontendInitializationData); +        await frontend.prepare(); +    } + +    authenticateMessageData(data) { +        return data; +    } + +    // Message handlers + +    _onMessage(data) { +        data = this.authenticateMessageData(data); +        const {action, params} = data; +        const handlerInfo = this._messageHandlers.get(action); +        if (typeof handlerInfo === 'undefined') { +            throw new Error(`Invalid action: ${action}`); +        } + +        const {async, handler} = handlerInfo; +        const result = handler(params); +        return {async, result}; +    } + +    _onMessageSetOptionsContext({optionsContext}) { +        this.setOptionsContext(optionsContext); +    } + +    _onMessageSetContent({type, details}) { +        this.setContent(type, details); +    } + +    _onMessageClearAutoPlayTimer() { +        this.clearAutoPlayTimer(); +    } + +    _onMessageSetCustomCss({css}) { +        this.setCustomCss(css); +    } +      // Private      _onExtensionUnloaded() { |