diff options
| author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2021-11-23 22:08:30 -0500 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-11-23 22:08:30 -0500 | 
| commit | d454b52a18127f782fafdf71534ea2c41f20ef44 (patch) | |
| tree | baa980dbd94d624d44bac2df3d691fb759d8300d /ext/js | |
| parent | ecc994a8bbd52a426434a549f8e3e68eba6e786e (diff) | |
Google Docs accessibility refactor (#2023)
* Skip urlRegex if it's used as a filter
* Add getRequiredContentScriptRegistrationPermissions function
* Add a reentrant check to google-docs.js
* Remove script node
* Move forceGoogleDocsHtmlRendering check into google-docs.js
* Replace document-start.js usage with google-docs.js
* Remove documentStart handling
* Add missing parameter descriptions
Diffstat (limited to 'ext/js')
| -rw-r--r-- | ext/js/accessibility/google-docs.js | 32 | ||||
| -rw-r--r-- | ext/js/background/backend.js | 26 | ||||
| -rw-r--r-- | ext/js/background/script-manager.js | 35 | ||||
| -rw-r--r-- | ext/js/document-start.js | 18 | 
4 files changed, 61 insertions, 50 deletions
| diff --git a/ext/js/accessibility/google-docs.js b/ext/js/accessibility/google-docs.js index f9ba0f7f..e45743ab 100644 --- a/ext/js/accessibility/google-docs.js +++ b/ext/js/accessibility/google-docs.js @@ -15,7 +15,36 @@   * along with this program.  If not, see <https://www.gnu.org/licenses/>.   */ -(() => { +(async () => { +    // Reentrant check +    if (self.googleDocsAccessibilitySetup) { return; } +    self.googleDocsAccessibilitySetup = true; + +    const invokeApi = (action, params) => { +        return new Promise((resolve, reject) => { +            chrome.runtime.sendMessage({action, params}, (response) => { +                void chrome.runtime.lastError; +                if (typeof response !== 'object' || response === null) { +                    reject(new Error('Unexpected response')); +                } else if (typeof response.error !== 'undefined') { +                    reject(new Error('Invalid response')); +                } else { +                    resolve(response.result); +                } +            }); +        }); +    }; + +    const optionsContext = {depth: 0, url: location.href}; +    let options; +    try { +        options = await invokeApi('optionsGet', {optionsContext}); +    } catch (e) { +        return; +    } + +    if (!options.accessibility.forceGoogleDocsHtmlRendering) { return; } +      let parent = document.head;      if (parent === null) {          parent = document.documentElement; @@ -24,4 +53,5 @@      const script = document.createElement('script');      script.textContent = 'window._docs_force_html_by_ext = true;';      parent.appendChild(script); +    parent.removeChild(script);  })(); diff --git a/ext/js/background/backend.js b/ext/js/background/backend.js index db43ec57..4e86a23c 100644 --- a/ext/js/background/backend.js +++ b/ext/js/background/backend.js @@ -127,7 +127,6 @@ class Backend {              ['triggerDatabaseUpdated',       {async: false, contentScript: true,  handler: this._onApiTriggerDatabaseUpdated.bind(this)}],              ['testMecab',                    {async: true,  contentScript: true,  handler: this._onApiTestMecab.bind(this)}],              ['textHasJapaneseCharacters',    {async: false, contentScript: true,  handler: this._onApiTextHasJapaneseCharacters.bind(this)}], -            ['documentStart',                {async: false, contentScript: true,  handler: this._onApiDocumentStart.bind(this)}],              ['getTermFrequencies',           {async: true,  contentScript: true,  handler: this._onApiGetTermFrequencies.bind(this)}]          ]);          this._messageHandlersWithProgress = new Map([ @@ -747,12 +746,6 @@ class Backend {          return this._japaneseUtil.isStringPartiallyJapanese(text);      } -    _onApiDocumentStart(params, sender) { -        const {tab, frameId, url} = sender; -        if (typeof url !== 'string' || typeof tab !== 'object' || tab === null) { return; } -        this._updateTabAccessibility(url, tab.id, frameId); -    } -      async _onApiGetTermFrequencies({termReadingList, dictionaries}) {          return await this._translator.getTermFrequencies(termReadingList, dictionaries);      } @@ -2140,25 +2133,6 @@ class Backend {          }      } -    async _updateTabAccessibility(url, tabId, frameId) { -        let file = null; - -        switch (new URL(url).hostname) { -            case 'docs.google.com': -                { -                    const optionsContext = {depth: 0, url}; -                    const options = this._getProfileOptions(optionsContext); -                    if (!options.accessibility.forceGoogleDocsHtmlRendering) { return; } -                    file = 'js/accessibility/google-docs.js'; -                } -                break; -        } - -        if (file === null) { return; } - -        await this._scriptManager.injectScript(file, tabId, frameId, false, true, 'document_start'); -    } -      async _getNormalizedDictionaryDatabaseMedia(targets) {          const results = await this._dictionaryDatabase.getMedia(targets);          for (const item of results) { diff --git a/ext/js/background/script-manager.js b/ext/js/background/script-manager.js index c6bdc0bb..ba4f8671 100644 --- a/ext/js/background/script-manager.js +++ b/ext/js/background/script-manager.js @@ -106,9 +106,9 @@ class ScriptManager {       * @param {string} id A unique identifier for the registration.       * @param {object} details The script registration details.       * @param {boolean} [details.allFrames] Same as `all_frames` in the `content_scripts` manifest key. -     * @param {string[]} [details.css] +     * @param {string[]} [details.css] List of CSS paths.       * @param {string[]} [details.excludeMatches] Same as `exclude_matches` in the `content_scripts` manifest key. -     * @param {string[]} [details.js] +     * @param {string[]} [details.js] List of script paths.       * @param {boolean} [details.matchAboutBlank] Same as `match_about_blank` in the `content_scripts` manifest key.       * @param {string[]} details.matches Same as `matches` in the `content_scripts` manifest key.       * @param {string} [details.urlMatches] Regex match pattern to use as a fallback @@ -181,6 +181,31 @@ class ScriptManager {          return true;      } +    /** +     * Gets the optional permissions required to register a content script. +     * @returns {string[]} An array of the required permissions, which may be empty. +     */ +    getRequiredContentScriptRegistrationPermissions() { +        if ( +            // Firefox +            ( +                typeof browser === 'object' && browser !== null && +                isObject(browser.contentScripts) && +                typeof browser.contentScripts.register === 'function' +            ) || +            // Chrome +            ( +                isObject(chrome.scripting) && +                typeof chrome.scripting.registerContentScripts === 'function' +            ) +        ) { +            return []; +        } + +        // Fallback +        return ['webNavigation']; +    } +      // Private      _injectStylesheetMV2(type, content, tabId, frameId, allFrames, matchAboutBlank, runAt) { @@ -333,8 +358,7 @@ class ScriptManager {      _registerContentScriptFallback(id, details) {          const {allFrames, css, js, matchAboutBlank, runAt, urlMatches} = details; -        const urlRegex = new RegExp(urlMatches); -        const details2 = {allFrames, css, js, matchAboutBlank, runAt, urlRegex}; +        const details2 = {allFrames, css, js, matchAboutBlank, runAt, urlRegex: null};          let unregister;          const webNavigationEvent = this._getWebNavigationEvent(runAt);          if (isObject(webNavigationEvent)) { @@ -356,6 +380,7 @@ class ScriptManager {                  chrome.tabs.onUpdated.addListener(onTabUpdated, extraParameters);              } catch (e) {                  // Chrome +                details2.urlRegex = new RegExp(urlMatches);                  chrome.tabs.onUpdated.addListener(onTabUpdated);              }              unregister = () => chrome.tabs.onUpdated.removeListener(onTabUpdated); @@ -378,7 +403,7 @@ class ScriptManager {      async _injectContentScript(isWebNavigation, details, status, url, tabId, frameId) {          const {urlRegex} = details; -        if (typeof urlRegex !== 'undefined' && !urlRegex.test(url)) { return; } +        if (urlRegex !== null && !urlRegex.test(url)) { return; }          let {allFrames, css, js, matchAboutBlank, runAt} = details; diff --git a/ext/js/document-start.js b/ext/js/document-start.js deleted file mode 100644 index de1c2403..00000000 --- a/ext/js/document-start.js +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) 2021  Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program.  If not, see <https://www.gnu.org/licenses/>. - */ - -chrome.runtime.sendMessage({action: 'documentStart'}, () => void chrome.runtime.lastError); |