diff options
Diffstat (limited to 'ext')
| -rw-r--r-- | ext/bg/js/backend.js | 85 | ||||
| -rw-r--r-- | ext/bg/js/search.js | 117 | ||||
| -rw-r--r-- | ext/fg/js/float.js | 2 | ||||
| -rw-r--r-- | ext/mixed/js/display.js | 51 | 
4 files changed, 152 insertions, 103 deletions
| diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 85b9b5e6..07920e01 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -899,24 +899,8 @@ class Backend {                  );              });              if (tab !== null) { -                const isValidTab = await new Promise((resolve) => { -                    chrome.tabs.sendMessage( -                        tabId, -                        {action: 'getUrl', params: {}}, -                        {frameId: 0}, -                        (response) => { -                            let result = false; -                            try { -                                const {url} = yomichan.getMessageResponseResult(response); -                                result = url.startsWith(baseUrl); -                            } catch (e) { -                                // NOP -                            } -                            resolve(result); -                        } -                    ); -                }); -                // windowId +                const url = await this._getTabUrl(tabId); +                const isValidTab = (url !== null && url.startsWith(baseUrl));                  if (isValidTab) {                      return {tab, created: false};                  } @@ -935,7 +919,7 @@ class Backend {          const popupWindow = await new Promise((resolve, reject) => {              chrome.windows.create(                  { -                    url: `${baseUrl}?mode=popup`, +                    url: baseUrl,                      width: popupWidth,                      height: popupHeight,                      type: 'popup' @@ -959,23 +943,22 @@ class Backend {          const tab = tabs[0];          await this._waitUntilTabFrameIsReady(tab.id, 0, 2000); +        await this._sendMessageTab( +            tab.id, +            {action: 'setMode', params: {mode: 'popup'}}, +            {frameId: 0} +        ); +          this._searchPopupTabId = tab.id;          return {tab, created: true};      }      _updateSearchQuery(tabId, text, animate) { -        return new Promise((resolve, reject) => { -            const callback = (response) => { -                try { -                    resolve(yomichan.getMessageResponseResult(response)); -                } catch (error) { -                    reject(error); -                } -            }; - -            const message = {action: 'updateSearchQuery', params: {text, animate}}; -            chrome.tabs.sendMessage(tabId, message, callback); -        }); +        return this._sendMessageTab( +            tabId, +            {action: 'updateSearchQuery', params: {text, animate}}, +            {frameId: 0} +        );      }      _sendMessageAllTabs(action, params={}) { @@ -1381,18 +1364,20 @@ class Backend {          return typeof templates === 'string' ? templates : this._defaultAnkiFieldTemplates;      } -    _getTabUrl(tab) { -        return new Promise((resolve) => { -            chrome.tabs.sendMessage(tab.id, {action: 'getUrl'}, {frameId: 0}, (response) => { -                let url = null; -                try { -                    ({url} = yomichan.getMessageResponseResult(response)); -                } catch (error) { -                    // NOP -                } -                resolve({tab, url}); -            }); -        }); +    async _getTabUrl(tabId) { +        try { +            const {url} = await this._sendMessageTab( +                tabId, +                {action: 'getUrl', params: {}}, +                {frameId: 0} +            ); +            if (typeof url === 'string') { +                return url; +            } +        } catch (e) { +            // NOP +        } +        return null;      }      async _findTab(timeout, checkUrl) { @@ -1538,4 +1523,18 @@ class Backend {          }          return await (json ? response.json() : response.text());      } + +    _sendMessageTab(...args) { +        return new Promise((resolve, reject) => { +            const callback = (response) => { +                try { +                    resolve(yomichan.getMessageResponseResult(response)); +                } catch (error) { +                    reject(error); +                } +            }; + +            chrome.tabs.sendMessage(...args, callback); +        }); +    }  } diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index d95fd5e4..d2ec5090 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -37,6 +37,7 @@ class DisplaySearch extends Display {          this._clipboardMonitor = new ClipboardMonitor({              getClipboard: api.clipboardGet.bind(api)          }); +        this._clipboardMonitorEnabled = false;          this._onKeyDownIgnoreKeys = new Map([              ['ANY_MOD', new Set([                  'Tab', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'PageDown', 'PageUp', 'Home', 'End', @@ -51,9 +52,6 @@ class DisplaySearch extends Display {              ['AltGraph', new Set()],              ['Shift', new Set()]          ]); -        this._runtimeMessageHandlers = new Map([ -            ['updateSearchQuery', {async: false, handler: this._onExternalSearchUpdate.bind(this)}] -        ]);      }      async prepare() { @@ -62,18 +60,16 @@ class DisplaySearch extends Display {          yomichan.on('optionsUpdated', () => this.updateOptions());          this.on('contentUpdating', this._onContentUpdating.bind(this)); +        this.on('modeChange', this._onModeChange.bind(this)); + +        this.registerMessageHandlers([ +            ['updateSearchQuery', {async: false, handler: this._onExternalSearchUpdate.bind(this)}] +        ]);          this.queryParserVisible = true;          this.setHistorySettings({useBrowserHistory: true});          const options = this.getOptions(); - -        const urlSearchParams = new URLSearchParams(location.search); -        let mode = urlSearchParams.get('mode'); -        if (mode === null) { mode = ''; } - -        document.documentElement.dataset.searchMode = mode; -          if (options.general.enableWanakana === true) {              this._wanakanaEnable.checked = true;              wanakana.bind(this._query); @@ -81,25 +77,15 @@ class DisplaySearch extends Display {              this._wanakanaEnable.checked = false;          } -        if (mode !== 'popup') { -            if (options.general.enableClipboardMonitor === true) { -                this._clipboardMonitorEnable.checked = true; -                this._clipboardMonitor.start(); -            } else { -                this._clipboardMonitorEnable.checked = false; -            } -            this._clipboardMonitorEnable.addEventListener('change', this._onClipboardMonitorEnableChange.bind(this)); -        } - -        chrome.runtime.onMessage.addListener(this._onRuntimeMessage.bind(this)); -          this._search.addEventListener('click', this._onSearch.bind(this), false);          this._query.addEventListener('input', this._onSearchInput.bind(this), false);          this._wanakanaEnable.addEventListener('change', this._onWanakanaEnableChange.bind(this));          window.addEventListener('copy', this._onCopy.bind(this));          this._clipboardMonitor.on('change', this._onExternalSearchUpdate.bind(this)); +        this._clipboardMonitorEnable.addEventListener('change', this._onClipboardMonitorEnableChange.bind(this));          this._updateSearchButton(); +        this._onModeChange();          await this._prepareNestedPopups(); @@ -209,12 +195,6 @@ class DisplaySearch extends Display {          this._onSearchQueryUpdated(query, true);      } -    _onRuntimeMessage({action, params}, sender, callback) { -        const messageHandler = this._runtimeMessageHandlers.get(action); -        if (typeof messageHandler === 'undefined') { return false; } -        return yomichan.invokeMessageHandler(messageHandler, params, callback, sender); -    } -      _onCopy() {          // ignore copy from search page          this._clipboardMonitor.setPreviousText(window.getSelection().toString().trim()); @@ -261,34 +241,15 @@ class DisplaySearch extends Display {      }      _onClipboardMonitorEnableChange(e) { -        if (e.target.checked) { -            chrome.permissions.request( -                {permissions: ['clipboardRead']}, -                (granted) => { -                    if (granted) { -                        this._clipboardMonitor.start(); -                        api.modifySettings([{ -                            action: 'set', -                            path: 'general.enableClipboardMonitor', -                            value: true, -                            scope: 'profile', -                            optionsContext: this.getOptionsContext() -                        }], 'search'); -                    } else { -                        e.target.checked = false; -                    } -                } -            ); -        } else { -            this._clipboardMonitor.stop(); -            api.modifySettings([{ -                action: 'set', -                path: 'general.enableClipboardMonitor', -                value: false, -                scope: 'profile', -                optionsContext: this.getOptionsContext() -            }], 'search'); -        } +        const enabled = e.target.checked; +        this._setClipboardMonitorEnabled(enabled); +    } + +    _onModeChange() { +        let mode = this.mode; +        if (mode === null) { mode = ''; } +        document.documentElement.dataset.searchMode = mode; +        this._updateClipboardMonitorEnabled();      }      _isWanakanaEnabled() { @@ -381,4 +342,48 @@ class DisplaySearch extends Display {          await onOptionsUpdated();      } + +    async _setClipboardMonitorEnabled(value) { +        let modify = true; +        if (value) { +            value = await this._requestPermissions(['clipboardRead']); +            modify = value; +        } + +        this._clipboardMonitorEnabled = value; +        this._updateClipboardMonitorEnabled(); + +        if (!modify) { return; } + +        await api.modifySettings([{ +            action: 'set', +            path: 'general.enableClipboardMonitor', +            value, +            scope: 'profile', +            optionsContext: this.getOptionsContext() +        }], 'search'); +    } + +    _updateClipboardMonitorEnabled() { +        const mode = this.mode; +        const enabled = this._clipboardMonitorEnabled; +        this._clipboardMonitorEnable.checked = enabled; +        if (enabled && mode !== 'popup') { +            this._clipboardMonitor.start(); +        } else { +            this._clipboardMonitor.stop(); +        } +    } + +    _requestPermissions(permissions) { +        return new Promise((resolve) => { +            chrome.permissions.request( +                {permissions}, +                (granted) => { +                    const e = chrome.runtime.lastError; +                    resolve(!e && granted); +                } +            ); +        }); +    }  } diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js index 794ccc6e..83c542d1 100644 --- a/ext/fg/js/float.js +++ b/ext/fg/js/float.js @@ -44,7 +44,7 @@ class DisplayFloat extends Display {      async prepare() {          await super.prepare(); -        this.registerMessageHandlers([ +        this.registerDirectMessageHandlers([              ['configure',       {async: true,  handler: this._onMessageConfigure.bind(this)}],              ['setContentScale', {async: false, handler: this._onMessageSetContentScale.bind(this)}]          ]); diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 93272666..418707ca 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -65,6 +65,7 @@ class Display extends EventDispatcher {          this._hotkeys = new Map();          this._actions = new Map();          this._messageHandlers = new Map(); +        this._directMessageHandlers = new Map();          this._history = new DisplayHistory({clearable: true, useBrowserHistory: false});          this._historyChangeIgnore = false;          this._historyHasChanged = false; @@ -80,6 +81,7 @@ class Display extends EventDispatcher {              getOptionsContext: this.getOptionsContext.bind(this),              setSpinnerVisible: this.setSpinnerVisible.bind(this)          }); +        this._mode = null;          this.registerActions([              ['close',            () => { this.onEscape(); }], @@ -114,6 +116,9 @@ class Display extends EventDispatcher {              {key: 'V',         modifiers: ['alt'], action: 'viewNote'}          ]);          this.registerMessageHandlers([ +            ['setMode', {async: false, handler: this._onMessageSetMode.bind(this)}] +        ]); +        this.registerDirectMessageHandlers([              ['setOptionsContext',  {async: false, handler: this._onMessageSetOptionsContext.bind(this)}],              ['setContent',         {async: false, handler: this._onMessageSetContent.bind(this)}],              ['clearAutoPlayTimer', {async: false, handler: this._onMessageClearAutoPlayTimer.bind(this)}], @@ -138,7 +143,12 @@ class Display extends EventDispatcher {          this._updateQueryParserVisibility();      } +    get mode() { +        return this._mode; +    } +      async prepare() { +        this._updateMode();          this._setInteractive(true);          await this._displayGenerator.prepare();          await this._queryParser.prepare(); @@ -146,8 +156,9 @@ class Display extends EventDispatcher {          this._history.on('stateChanged', this._onStateChanged.bind(this));          this._queryParser.on('searched', this._onQueryParserSearch.bind(this));          yomichan.on('extensionUnloaded', this._onExtensionUnloaded.bind(this)); +        chrome.runtime.onMessage.addListener(this._onMessage.bind(this));          api.crossFrame.registerHandlers([ -            ['popupMessage', {async: 'dynamic', handler: this._onMessage.bind(this)}] +            ['popupMessage', {async: 'dynamic', handler: this._onDirectMessage.bind(this)}]          ]);      } @@ -313,6 +324,12 @@ class Display extends EventDispatcher {          }      } +    registerDirectMessageHandlers(handlers) { +        for (const [name, handlerInfo] of handlers) { +            this._directMessageHandlers.set(name, handlerInfo); +        } +    } +      async setupNestedPopups(frontendInitializationData) {          await dynamicLoader.loadScripts([              '/mixed/js/text-scanner.js', @@ -343,10 +360,16 @@ class Display extends EventDispatcher {      // Message handlers -    _onMessage(data) { +    _onMessage({action, params}, sender, callback) { +        const messageHandler = this._messageHandlers.get(action); +        if (typeof messageHandler === 'undefined') { return false; } +        return yomichan.invokeMessageHandler(messageHandler, params, callback, sender); +    } + +    _onDirectMessage(data) {          data = this.authenticateMessageData(data);          const {action, params} = data; -        const handlerInfo = this._messageHandlers.get(action); +        const handlerInfo = this._directMessageHandlers.get(action);          if (typeof handlerInfo === 'undefined') {              throw new Error(`Invalid action: ${action}`);          } @@ -356,6 +379,10 @@ class Display extends EventDispatcher {          return {async, result};      } +    _onMessageSetMode({mode}) { +        this._setMode(mode, true); +    } +      _onMessageSetOptionsContext({optionsContext}) {          this.setOptionsContext(optionsContext);      } @@ -1253,4 +1280,22 @@ class Display extends EventDispatcher {      _closePopups() {          yomichan.trigger('closePopups');      } + +    _updateMode() { +        const mode = sessionStorage.getItem('mode'); +        this._setMode(mode, false); +    } + +    _setMode(mode, save) { +        if (mode === this._mode) { return; } +        if (save) { +            if (mode === null) { +                sessionStorage.removeItem('mode'); +            } else { +                sessionStorage.setItem('mode', mode); +            } +        } +        this._mode = mode; +        this.trigger('modeChange', {mode}); +    }  } |