aboutsummaryrefslogtreecommitdiff
path: root/ext/js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/js')
-rw-r--r--ext/js/accessibility/google-docs.js32
-rw-r--r--ext/js/background/backend.js26
-rw-r--r--ext/js/background/script-manager.js35
-rw-r--r--ext/js/document-start.js18
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);