aboutsummaryrefslogtreecommitdiff
path: root/ext/js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/js')
-rw-r--r--ext/js/background/backend.js4
-rw-r--r--ext/js/background/request-builder.js1
-rw-r--r--ext/js/background/script-manager.js115
-rw-r--r--ext/js/language/text-scanner.js3
-rw-r--r--ext/js/pages/settings/recommended-permissions-controller.js74
-rw-r--r--ext/js/pages/welcome-main.js4
6 files changed, 95 insertions, 106 deletions
diff --git a/ext/js/background/backend.js b/ext/js/background/backend.js
index db6cfada..dd233abb 100644
--- a/ext/js/background/backend.js
+++ b/ext/js/background/backend.js
@@ -593,7 +593,7 @@ class Backend {
async _onApiInjectStylesheet({type, value}, sender) {
const {frameId, tab} = sender;
if (!isObject(tab)) { throw new Error('Invalid tab'); }
- return await this._scriptManager.injectStylesheet(type, value, tab.id, frameId, false, true, 'document_start');
+ return await this._scriptManager.injectStylesheet(type, value, tab.id, frameId, false);
}
async _onApiGetStylesheetContent({url}) {
@@ -790,7 +790,7 @@ class Backend {
if (typeof tabId !== 'number') { throw new Error('Sender has invalid tab ID'); }
const {frameId} = sender;
for (const file of files) {
- await this._scriptManager.injectScript(file, tabId, frameId, false, true, 'document_start');
+ await this._scriptManager.injectScript(file, tabId, frameId, false);
}
}
diff --git a/ext/js/background/request-builder.js b/ext/js/background/request-builder.js
index eca7d0d3..663e242b 100644
--- a/ext/js/background/request-builder.js
+++ b/ext/js/background/request-builder.js
@@ -54,7 +54,6 @@ class RequestBuilder {
* @returns {Promise<Response>} The response of the `fetch` call.
*/
async fetchAnonymous(url, init) {
- fetch(1, 2);
if (isObject(chrome.declarativeNetRequest)) {
return await this._fetchAnonymousDeclarative(url, init);
}
diff --git a/ext/js/background/script-manager.js b/ext/js/background/script-manager.js
index 722a46f0..694b64db 100644
--- a/ext/js/background/script-manager.js
+++ b/ext/js/background/script-manager.js
@@ -36,14 +36,10 @@ class ScriptManager {
* @param {number} tabId The id of the tab to inject into.
* @param {number} [frameId] The id of the frame to inject into.
* @param {boolean} [allFrames] Whether or not the stylesheet should be injected into all frames.
- * @param {boolean} [matchAboutBlank] Whether or not the stylesheet should be injected into about:blank frames.
- * @param {string} [runAt] The time to inject the stylesheet at.
* @returns {Promise<void>}
*/
- injectStylesheet(type, content, tabId, frameId, allFrames, matchAboutBlank, runAt) {
- if (isObject(chrome.tabs) && typeof chrome.tabs.insertCSS === 'function') {
- return this._injectStylesheetMV2(type, content, tabId, frameId, allFrames, matchAboutBlank, runAt);
- } else if (isObject(chrome.scripting) && typeof chrome.scripting.insertCSS === 'function') {
+ injectStylesheet(type, content, tabId, frameId, allFrames) {
+ if (isObject(chrome.scripting) && typeof chrome.scripting.insertCSS === 'function') {
return this._injectStylesheetMV3(type, content, tabId, frameId, allFrames);
} else {
return Promise.reject(new Error('Stylesheet injection not supported'));
@@ -56,14 +52,10 @@ class ScriptManager {
* @param {number} tabId The id of the tab to inject into.
* @param {number} [frameId] The id of the frame to inject into.
* @param {boolean} [allFrames] Whether or not the script should be injected into all frames.
- * @param {boolean} [matchAboutBlank] Whether or not the script should be injected into about:blank frames.
- * @param {string} [runAt] The time to inject the script at.
* @returns {Promise<{frameId: number, result: object}>} The id of the frame and the result of the script injection.
*/
- injectScript(file, tabId, frameId, allFrames, matchAboutBlank, runAt) {
- if (isObject(chrome.tabs) && typeof chrome.tabs.executeScript === 'function') {
- return this._injectScriptMV2(file, tabId, frameId, allFrames, matchAboutBlank, runAt);
- } else if (isObject(chrome.scripting) && typeof chrome.scripting.executeScript === 'function') {
+ injectScript(file, tabId, frameId, allFrames) {
+ if (isObject(chrome.scripting) && typeof chrome.scripting.executeScript === 'function') {
return this._injectScriptMV3(file, tabId, frameId, allFrames);
} else {
return Promise.reject(new Error('Script injection not supported'));
@@ -122,19 +114,6 @@ class ScriptManager {
throw new Error('Registration already exists');
}
- // Firefox
- if (
- typeof browser === 'object' && browser !== null &&
- isObject(browser.contentScripts) &&
- typeof browser.contentScripts.register === 'function'
- ) {
- const details2 = this._convertContentScriptRegistrationDetails(details, id, true);
- const registration = await browser.contentScripts.register(details2);
- this._contentScriptRegistrations.set(id, registration);
- return;
- }
-
- // Chrome
if (isObject(chrome.scripting) && typeof chrome.scripting.registerContentScripts === 'function') {
const details2 = this._convertContentScriptRegistrationDetails(details, id, false);
await new Promise((resolve, reject) => {
@@ -161,18 +140,17 @@ class ScriptManager {
* @returns {Promise<boolean>} `true` if the content script was unregistered, `false` otherwise.
*/
async unregisterContentScript(id) {
- // Chrome
if (isObject(chrome.scripting) && typeof chrome.scripting.unregisterContentScripts === 'function') {
this._contentScriptRegistrations.delete(id);
try {
- await this._unregisterContentScriptChrome(id);
+ await this._unregisterContentScriptMV3(id);
return true;
} catch (e) {
return false;
}
}
- // Firefox or fallback
+ // Fallback
const registration = this._contentScriptRegistrations.get(id);
if (typeof registration === 'undefined') { return false; }
this._contentScriptRegistrations.delete(id);
@@ -187,19 +165,7 @@ class ScriptManager {
* @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'
- )
- ) {
+ if (isObject(chrome.scripting) && typeof chrome.scripting.registerContentScripts === 'function') {
return [];
}
@@ -209,45 +175,12 @@ class ScriptManager {
// Private
- _injectStylesheetMV2(type, content, tabId, frameId, allFrames, matchAboutBlank, runAt) {
- return new Promise((resolve, reject) => {
- const details = (
- type === 'file' ?
- {
- file: content,
- runAt,
- cssOrigin: 'author',
- allFrames,
- matchAboutBlank
- } :
- {
- code: content,
- runAt,
- cssOrigin: 'user',
- allFrames,
- matchAboutBlank
- }
- );
- if (typeof frameId === 'number') {
- details.frameId = frameId;
- }
- chrome.tabs.insertCSS(tabId, details, () => {
- const e = chrome.runtime.lastError;
- if (e) {
- reject(new Error(e.message));
- } else {
- resolve();
- }
- });
- });
- }
-
_injectStylesheetMV3(type, content, tabId, frameId, allFrames) {
return new Promise((resolve, reject) => {
const details = (
type === 'file' ?
- {origin: chrome.scripting.StyleOrigin.AUTHOR, files: [content]} :
- {origin: chrome.scripting.StyleOrigin.USER, css: content}
+ {origin: 'AUTHOR', files: [content]} :
+ {origin: 'USER', css: content}
);
details.target = {
tabId,
@@ -267,27 +200,6 @@ class ScriptManager {
});
}
- _injectScriptMV2(file, tabId, frameId, allFrames, matchAboutBlank, runAt) {
- return new Promise((resolve, reject) => {
- const details = {
- allFrames,
- frameId,
- file,
- matchAboutBlank,
- runAt
- };
- chrome.tabs.executeScript(tabId, details, (results) => {
- const e = chrome.runtime.lastError;
- if (e) {
- reject(new Error(e.message));
- } else {
- const result = results[0];
- resolve({frameId, result});
- }
- });
- });
- }
-
_injectScriptMV3(file, tabId, frameId, allFrames) {
return new Promise((resolve, reject) => {
const details = {
@@ -310,7 +222,7 @@ class ScriptManager {
});
}
- _unregisterContentScriptChrome(id) {
+ _unregisterContentScriptMV3(id) {
return new Promise((resolve, reject) => {
chrome.scripting.unregisterContentScripts({ids: [id]}, () => {
const e = chrome.runtime.lastError;
@@ -407,7 +319,7 @@ class ScriptManager {
const {urlRegex} = details;
if (urlRegex !== null && !urlRegex.test(url)) { return; }
- let {allFrames, css, js, matchAboutBlank, runAt} = details;
+ let {allFrames, css, js, runAt} = details;
if (isWebNavigation) {
if (allFrames) {
@@ -425,14 +337,13 @@ class ScriptManager {
const promises = [];
if (Array.isArray(css)) {
- const runAtCss = (typeof runAt === 'string' ? runAt : 'document_start');
for (const file of css) {
- promises.push(this.injectStylesheet('file', file, tabId, frameId, allFrames, matchAboutBlank, runAtCss));
+ promises.push(this.injectStylesheet('file', file, tabId, frameId, allFrames));
}
}
if (Array.isArray(js)) {
for (const file of js) {
- promises.push(this.injectScript(file, tabId, frameId, allFrames, matchAboutBlank, runAt));
+ promises.push(this.injectScript(file, tabId, frameId, allFrames));
}
}
await Promise.all(promises);
diff --git a/ext/js/language/text-scanner.js b/ext/js/language/text-scanner.js
index 6fa7a454..af5cc8fe 100644
--- a/ext/js/language/text-scanner.js
+++ b/ext/js/language/text-scanner.js
@@ -145,7 +145,8 @@ class TextScanner extends EventDispatcher {
if (value) {
this._hookEvents();
- this._userHasNotSelectedAnythingManually = window.getSelection().isCollapsed;
+ const selection = window.getSelection();
+ this._userHasNotSelectedAnythingManually = (selection === null) ? true : selection.isCollapsed;
}
}
diff --git a/ext/js/pages/settings/recommended-permissions-controller.js b/ext/js/pages/settings/recommended-permissions-controller.js
new file mode 100644
index 00000000..3d25d5eb
--- /dev/null
+++ b/ext/js/pages/settings/recommended-permissions-controller.js
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 Yomitan Authors
+ * Copyright (C) 2021-2022 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/>.
+ */
+
+class RecommendedPermissionsController {
+ constructor(settingsController) {
+ this._settingsController = settingsController;
+ this._originToggleNodes = null;
+ this._eventListeners = new EventListenerCollection();
+ this._errorContainer = null;
+ }
+
+ async prepare() {
+ this._originToggleNodes = document.querySelectorAll('.recommended-permissions-toggle');
+ this._errorContainer = document.querySelector('#recommended-permissions-error');
+ for (const node of this._originToggleNodes) {
+ node.addEventListener('change', this._onOriginToggleChange.bind(this), false);
+ }
+
+ this._settingsController.on('permissionsChanged', this._onPermissionsChanged.bind(this));
+ await this._updatePermissions();
+ }
+
+ // Private
+
+ _onPermissionsChanged({permissions}) {
+ this._eventListeners.removeAllEventListeners();
+ const originsSet = new Set(permissions.origins);
+ for (const node of this._originToggleNodes) {
+ node.checked = originsSet.has(node.dataset.origin);
+ }
+ }
+
+ _onOriginToggleChange(e) {
+ const node = e.currentTarget;
+ const value = node.checked;
+ node.checked = !value;
+
+ const {origin} = node.dataset;
+ this._setOriginPermissionEnabled(origin, value);
+ }
+
+ async _updatePermissions() {
+ const permissions = await this._settingsController.permissionsUtil.getAllPermissions();
+ this._onPermissionsChanged({permissions});
+ }
+
+ async _setOriginPermissionEnabled(origin, enabled) {
+ let added = false;
+ try {
+ added = await this._settingsController.permissionsUtil.setPermissionsGranted({origins: [origin]}, enabled);
+ } catch (e) {
+ this._errorContainer.hidden = false;
+ this._errorContainer.textContent = e.message;
+ }
+ if (!added) { return false; }
+ await this._updatePermissions();
+ return true;
+ }
+}
diff --git a/ext/js/pages/welcome-main.js b/ext/js/pages/welcome-main.js
index eb8bd675..521ce2c2 100644
--- a/ext/js/pages/welcome-main.js
+++ b/ext/js/pages/welcome-main.js
@@ -23,6 +23,7 @@
* ExtensionContentController
* GenericSettingController
* ModalController
+ * RecommendedPermissionsController
* ScanInputsSimpleController
* SettingsController
* SettingsDisplayController
@@ -77,6 +78,9 @@ async function setupGenericSettingsController(genericSettingController) {
const simpleScanningInputController = new ScanInputsSimpleController(settingsController);
simpleScanningInputController.prepare();
+ const recommendedPermissionsController = new RecommendedPermissionsController(settingsController);
+ recommendedPermissionsController.prepare();
+
await Promise.all(preparePromises);
document.documentElement.dataset.loaded = 'true';