diff --git a/.eslintrc.json b/.eslintrc.json
index a1e47ef1..cc43ba41 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -182,6 +182,7 @@
"files": [
"ext/js/core.js",
"ext/js/yomichan.js",
+ "ext/js/accessibility/accessibility-controller.js",
"ext/js/background/backend.js",
"ext/js/background/environment.js",
"ext/js/background/profile-conditions-util.js",
diff --git a/dev/data/manifest-variants.json b/dev/data/manifest-variants.json
index 957fa159..bdb4bd9a 100644
--- a/dev/data/manifest-variants.json
+++ b/dev/data/manifest-variants.json
@@ -63,18 +63,6 @@
"js/script/dynamic-loader.js",
"js/app/content-script-main.js"
]
- },
- {
- "run_at": "document_start",
- "matches": [
- "http://docs.google.com/*",
- "https://docs.google.com/*"
- ],
- "match_about_blank": true,
- "all_frames": true,
- "js": [
- "js/accessibility/google-docs.js"
- ]
}
],
"minimum_chrome_version": "57.0.0.0",
diff --git a/ext/background.html b/ext/background.html
index 44027a48..84e64c9c 100644
--- a/ext/background.html
+++ b/ext/background.html
@@ -23,6 +23,7 @@
+
diff --git a/ext/js/accessibility/accessibility-controller.js b/ext/js/accessibility/accessibility-controller.js
new file mode 100644
index 00000000..a995d5d0
--- /dev/null
+++ b/ext/js/accessibility/accessibility-controller.js
@@ -0,0 +1,97 @@
+/*
+ * 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 .
+ */
+
+/**
+ * This class controls the registration of accessibility handlers.
+ */
+class AccessibilityController {
+ /**
+ * Creates a new instance.
+ * @param {ScriptManager} scriptManager An instance of the `ScriptManager` class.
+ */
+ constructor(scriptManager) {
+ this._scriptManager = scriptManager;
+ this._updateGoogleDocsAccessibilityToken = null;
+ this._updateGoogleDocsAccessibilityPromise = null;
+ this._forceGoogleDocsHtmlRenderingAny = false;
+ }
+
+ /**
+ * Updates the accessibility handlers.
+ * @param {object} fullOptions The full options object from the `Backend` instance.
+ * The value is treated as read-only and is not modified.
+ */
+ async update(fullOptions) {
+ let forceGoogleDocsHtmlRenderingAny = false;
+ for (const {options} of fullOptions.profiles) {
+ if (options.accessibility.forceGoogleDocsHtmlRendering) {
+ forceGoogleDocsHtmlRenderingAny = true;
+ break;
+ }
+ }
+
+ await this._updateGoogleDocsAccessibility(forceGoogleDocsHtmlRenderingAny);
+ }
+
+ // Private
+
+ async _updateGoogleDocsAccessibility(forceGoogleDocsHtmlRenderingAny) {
+ // Reentrant token
+ const token = {};
+ this._updateGoogleDocsAccessibilityToken = token;
+
+ // Wait for previous
+ let promise = this._updateGoogleDocsAccessibilityPromise;
+ if (promise !== null) { await promise; }
+
+ // Reentrant check
+ if (this._updateGoogleDocsAccessibilityToken !== token) { return; }
+
+ // Update
+ promise = this._updateGoogleDocsAccessibilityInner(forceGoogleDocsHtmlRenderingAny);
+ this._updateGoogleDocsAccessibilityPromise = promise;
+ await promise;
+ this._updateGoogleDocsAccessibilityPromise = null;
+ }
+
+ async _updateGoogleDocsAccessibilityInner(forceGoogleDocsHtmlRenderingAny) {
+ if (this._forceGoogleDocsHtmlRenderingAny === forceGoogleDocsHtmlRenderingAny) { return; }
+
+ this._forceGoogleDocsHtmlRenderingAny = forceGoogleDocsHtmlRenderingAny;
+
+ const id = 'googleDocsAccessibility';
+ try {
+ if (forceGoogleDocsHtmlRenderingAny) {
+ if (await this._scriptManager.isContentScriptRegistered(id)) { return; }
+ const details = {
+ allFrames: true,
+ matchAboutBlank: true,
+ matches: ['*://docs.google.com/*'],
+ urlMatches: '^[^:]*://docs.google.com/[\\w\\W]*$',
+ runAt: 'document_start',
+ js: ['js/accessibility/google-docs.js']
+ };
+ await this._scriptManager.registerContentScript(id, details);
+ } else {
+ await this._scriptManager.unregisterContentScript(id);
+ }
+ } catch (e) {
+ log.error(e);
+ }
+ }
+}
+
diff --git a/ext/js/background/backend.js b/ext/js/background/backend.js
index 4e86a23c..f8424e80 100644
--- a/ext/js/background/backend.js
+++ b/ext/js/background/backend.js
@@ -16,6 +16,7 @@
*/
/* global
+ * AccessibilityController
* AnkiConnect
* AnkiUtil
* AudioDownloader
@@ -69,6 +70,7 @@ class Backend {
});
this._optionsUtil = new OptionsUtil();
this._scriptManager = new ScriptManager();
+ this._accessibilityController = new AccessibilityController(this._scriptManager);
this._searchPopupTabId = null;
this._searchPopupTabCreatePromise = null;
@@ -988,6 +990,8 @@ class Backend {
this._clipboardMonitor.stop();
}
+ this._accessibilityController.update(this._getOptionsFull(false));
+
this._sendMessageAllTabsIgnoreResponse('Yomichan.optionsUpdated', {source});
}
diff --git a/ext/manifest.json b/ext/manifest.json
index 422d296e..33d1ed1d 100644
--- a/ext/manifest.json
+++ b/ext/manifest.json
@@ -62,18 +62,6 @@
"js/script/dynamic-loader.js",
"js/app/content-script-main.js"
]
- },
- {
- "run_at": "document_start",
- "matches": [
- "http://docs.google.com/*",
- "https://docs.google.com/*"
- ],
- "match_about_blank": true,
- "all_frames": true,
- "js": [
- "js/accessibility/google-docs.js"
- ]
}
],
"minimum_chrome_version": "57.0.0.0",
diff --git a/ext/sw.js b/ext/sw.js
index 2624a04d..af6c9a43 100644
--- a/ext/sw.js
+++ b/ext/sw.js
@@ -20,6 +20,7 @@ self.importScripts(
'/lib/wanakana.min.js',
'/js/core.js',
'/js/yomichan.js',
+ '/js/accessibility/accessibility-controller.js',
'/js/background/backend.js',
'/js/background/environment.js',
'/js/background/profile-conditions-util.js',