mirror of
https://github.com/gorhill/uBlock.git
synced 2026-03-11 09:04:36 +00:00
[mv3] New approach to toggle toolbar icon not requiring extra permissions
Related issue: https://github.com/uBlockOrigin/uBOL-home/issues/198#issuecomment-2855135571 As a result, the permissions `tabs` and `webNavigation` have been removed.
This commit is contained in:
parent
0ee6e3044d
commit
cc2760f4d6
8 changed files with 97 additions and 84 deletions
|
|
@ -40,9 +40,7 @@
|
|||
"activeTab",
|
||||
"declarativeNetRequest",
|
||||
"scripting",
|
||||
"storage",
|
||||
"tabs",
|
||||
"webNavigation"
|
||||
"storage"
|
||||
],
|
||||
"short_name": "uBO Lite",
|
||||
"storage": {
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@
|
|||
Home: https://github.com/gorhill/uBlock
|
||||
*/
|
||||
|
||||
import { matchesFromHostnames, strArrayEq } from './utils.js';
|
||||
import { browser } from './ext.js';
|
||||
import { getFilteringModeDetails } from './mode-manager.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
@ -28,14 +28,6 @@ let reverseMode = false;
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
function toggleToolbarIcon(tabId) {
|
||||
if ( reverseMode ) {
|
||||
enableToolbarIcon(tabId);
|
||||
} else {
|
||||
disableToolbarIcon(tabId);
|
||||
}
|
||||
}
|
||||
|
||||
function disableToolbarIcon(tabId) {
|
||||
const details = {
|
||||
path: {
|
||||
|
|
@ -68,9 +60,12 @@ function enableToolbarIcon(tabId) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
function toolbarIconListener(details) {
|
||||
if ( details.frameId !== 0 ) { return; }
|
||||
toggleToolbarIcon(details.tabId);
|
||||
export function toggleToolbarIcon(tabId) {
|
||||
if ( reverseMode ) {
|
||||
enableToolbarIcon(tabId);
|
||||
} else {
|
||||
disableToolbarIcon(tabId);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
@ -78,13 +73,8 @@ function toolbarIconListener(details) {
|
|||
// https://github.com/uBlockOrigin/uBOL-home/issues/198
|
||||
// Ensure the toolbar icon reflects the no-filtering mode of "trusted sites"
|
||||
|
||||
export async function syncToolbarIcon(wakeup) {
|
||||
const { webNavigation } = browser;
|
||||
if ( typeof webNavigation !== 'object' ) { return; }
|
||||
|
||||
webNavigation.onCommitted.removeListener(toolbarIconListener);
|
||||
|
||||
const { none, basic, optimal, complete } = await getFilteringModeDetails();
|
||||
export async function registerToolbarIconToggler(context) {
|
||||
const { none, basic, optimal, complete } = context.filteringModeDetails;
|
||||
const reverseModeAfter = none.delete('all-urls');
|
||||
const toToggle = reverseModeAfter ?
|
||||
new Set([ ...basic, ...optimal, ...complete ])
|
||||
|
|
@ -101,20 +91,20 @@ export async function syncToolbarIcon(wakeup) {
|
|||
|
||||
if ( toToggle.size === 0 ) { return; }
|
||||
|
||||
webNavigation.onCommitted.addListener(toolbarIconListener, {
|
||||
url: Array.from(toToggle).map(a => ({
|
||||
originAndPathMatches: `^https?://([^.].*\\.)?${a.replaceAll('.', '\\.')}/`
|
||||
})),
|
||||
});
|
||||
const registered = context.before.get('toolbar-icon');
|
||||
context.before.delete('toolbar-icon'); // Important!
|
||||
|
||||
if ( wakeup === undefined ) { return; }
|
||||
const directive = {
|
||||
id: 'toolbar-icon',
|
||||
js: [ '/js/scripting/toolbar-icon.js' ],
|
||||
matches: matchesFromHostnames(toToggle),
|
||||
runAt: 'document_start',
|
||||
};
|
||||
|
||||
// If waking up, update icon for existing tabs
|
||||
const tabs = await browser.tabs.query({
|
||||
url: Array.from(toToggle).map(a => `*://*.${a}/*`)
|
||||
}).catch(( ) => ([]));
|
||||
|
||||
for ( const tab of tabs ) {
|
||||
toggleToolbarIcon(tab.id);
|
||||
if ( registered === undefined ) {
|
||||
context.toAdd.push(directive);
|
||||
} else if ( strArrayEq(registered.matches, directive.matches) === false ) {
|
||||
context.toRemove.push('toolbar-icon');
|
||||
context.toAdd.push(directive);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
import {
|
||||
MODE_BASIC,
|
||||
MODE_NONE,
|
||||
MODE_OPTIMAL,
|
||||
getDefaultFilteringMode,
|
||||
getFilteringMode,
|
||||
|
|
@ -78,7 +77,7 @@ import {
|
|||
|
||||
import { dnr } from './ext-compat.js';
|
||||
import { registerInjectables } from './scripting-manager.js';
|
||||
import { syncToolbarIcon } from './action.js';
|
||||
import { toggleToolbarIcon } from './action.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
@ -170,6 +169,14 @@ function onMessage(request, sender, callback) {
|
|||
return false;
|
||||
}
|
||||
|
||||
case 'toggleToolbarIcon': {
|
||||
const tabId = sender?.tab?.id ?? false;
|
||||
if ( tabId ) {
|
||||
toggleToolbarIcon(tabId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -313,17 +320,11 @@ function onMessage(request, sender, callback) {
|
|||
break;
|
||||
|
||||
case 'setFilteringMode': {
|
||||
let trustedSitesChanged = false;
|
||||
getFilteringMode(request.hostname).then(beforeLevel => {
|
||||
if ( request.level === beforeLevel ) { return beforeLevel; }
|
||||
trustedSitesChanged = beforeLevel === MODE_NONE;
|
||||
return setFilteringMode(request.hostname, request.level);
|
||||
}).then(afterLevel => {
|
||||
registerInjectables();
|
||||
trustedSitesChanged ||= afterLevel === MODE_NONE;
|
||||
if ( trustedSitesChanged ) {
|
||||
syncToolbarIcon();
|
||||
}
|
||||
callback(afterLevel);
|
||||
});
|
||||
return true;
|
||||
|
|
@ -357,7 +358,6 @@ function onMessage(request, sender, callback) {
|
|||
case 'setTrustedSites':
|
||||
setTrustedSites(request.hostnames).then(( ) => {
|
||||
registerInjectables();
|
||||
syncToolbarIcon(true);
|
||||
return Promise.all([
|
||||
getDefaultFilteringMode(),
|
||||
getTrustedSites(),
|
||||
|
|
@ -485,7 +485,6 @@ async function start() {
|
|||
await startSession();
|
||||
}
|
||||
|
||||
syncToolbarIcon(process.wakeupRun);
|
||||
toggleDeveloperMode(rulesetConfig.developerMode);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import { browser } from './ext.js';
|
|||
import { fetchJSON } from './fetch.js';
|
||||
import { getEnabledRulesetsDetails } from './ruleset-manager.js';
|
||||
import { getFilteringModeDetails } from './mode-manager.js';
|
||||
import { registerToolbarIconToggler } from './action.js';
|
||||
import { ubolLog } from './debug.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
@ -53,19 +54,6 @@ function getGenericDetails() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// Important: We need to sort the arrays for fast comparison
|
||||
const arrayEq = (a = [], b = [], sort = true) => {
|
||||
const alen = a.length;
|
||||
if ( alen !== b.length ) { return false; }
|
||||
if ( sort ) { a.sort(); b.sort(); }
|
||||
for ( let i = 0; i < alen; i++ ) {
|
||||
if ( a[i] !== b[i] ) { return false; }
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const normalizeMatches = matches => {
|
||||
if ( matches.length <= 1 ) { return; }
|
||||
if ( matches.includes('<all_urls>') === false ) {
|
||||
|
|
@ -168,9 +156,9 @@ function registerHighGeneric(context, genericDetails) {
|
|||
|
||||
// update
|
||||
if (
|
||||
arrayEq(registered.css, css, false) === false ||
|
||||
arrayEq(registered.matches, matches) === false ||
|
||||
arrayEq(registered.excludeMatches, excludeMatches) === false
|
||||
ut.strArrayEq(registered.css, css, false) === false ||
|
||||
ut.strArrayEq(registered.matches, matches) === false ||
|
||||
ut.strArrayEq(registered.excludeMatches, excludeMatches) === false
|
||||
) {
|
||||
context.toRemove.push('css-generichigh');
|
||||
context.toAdd.push(directive);
|
||||
|
|
@ -231,8 +219,8 @@ function registerGeneric(context, genericDetails) {
|
|||
if ( registered === undefined ) { // register
|
||||
context.toAdd.push(directive);
|
||||
} else if ( // update
|
||||
arrayEq(registered.js, js, false) === false ||
|
||||
arrayEq(registered.matches, directive.matches) === false
|
||||
ut.strArrayEq(registered.js, js, false) === false ||
|
||||
ut.strArrayEq(registered.matches, directive.matches) === false
|
||||
) {
|
||||
context.toRemove.push('css-generic-some');
|
||||
context.toAdd.push(directive);
|
||||
|
|
@ -257,8 +245,8 @@ function registerGeneric(context, genericDetails) {
|
|||
if ( registeredAll === undefined ) { // register
|
||||
context.toAdd.push(directiveAll);
|
||||
} else if ( // update
|
||||
arrayEq(registeredAll.js, js, false) === false ||
|
||||
arrayEq(registeredAll.excludeMatches, directiveAll.excludeMatches) === false
|
||||
ut.strArrayEq(registeredAll.js, js, false) === false ||
|
||||
ut.strArrayEq(registeredAll.excludeMatches, directiveAll.excludeMatches) === false
|
||||
) {
|
||||
context.toRemove.push('css-generic-all');
|
||||
context.toAdd.push(directiveAll);
|
||||
|
|
@ -281,8 +269,8 @@ function registerGeneric(context, genericDetails) {
|
|||
if ( registeredSome === undefined ) { // register
|
||||
context.toAdd.push(directiveSome);
|
||||
} else if ( // update
|
||||
arrayEq(registeredSome.js, js, false) === false ||
|
||||
arrayEq(registeredSome.matches, directiveSome.matches) === false
|
||||
ut.strArrayEq(registeredSome.js, js, false) === false ||
|
||||
ut.strArrayEq(registeredSome.matches, directiveSome.matches) === false
|
||||
) {
|
||||
context.toRemove.push('css-generic-some');
|
||||
context.toAdd.push(directiveSome);
|
||||
|
|
@ -342,9 +330,9 @@ function registerProcedural(context) {
|
|||
|
||||
// update
|
||||
if (
|
||||
arrayEq(registered.js, js, false) === false ||
|
||||
arrayEq(registered.matches, matches) === false ||
|
||||
arrayEq(registered.excludeMatches, excludeMatches) === false
|
||||
ut.strArrayEq(registered.js, js, false) === false ||
|
||||
ut.strArrayEq(registered.matches, matches) === false ||
|
||||
ut.strArrayEq(registered.excludeMatches, excludeMatches) === false
|
||||
) {
|
||||
context.toRemove.push('css-procedural');
|
||||
context.toAdd.push(directive);
|
||||
|
|
@ -404,9 +392,9 @@ function registerDeclarative(context) {
|
|||
|
||||
// update
|
||||
if (
|
||||
arrayEq(registered.js, js, false) === false ||
|
||||
arrayEq(registered.matches, matches) === false ||
|
||||
arrayEq(registered.excludeMatches, excludeMatches) === false
|
||||
ut.strArrayEq(registered.js, js, false) === false ||
|
||||
ut.strArrayEq(registered.matches, matches) === false ||
|
||||
ut.strArrayEq(registered.excludeMatches, excludeMatches) === false
|
||||
) {
|
||||
context.toRemove.push('css-declarative');
|
||||
context.toAdd.push(directive);
|
||||
|
|
@ -466,9 +454,9 @@ function registerSpecific(context) {
|
|||
|
||||
// update
|
||||
if (
|
||||
arrayEq(registered.js, js, false) === false ||
|
||||
arrayEq(registered.matches, matches) === false ||
|
||||
arrayEq(registered.excludeMatches, excludeMatches) === false
|
||||
ut.strArrayEq(registered.js, js, false) === false ||
|
||||
ut.strArrayEq(registered.matches, matches) === false ||
|
||||
ut.strArrayEq(registered.excludeMatches, excludeMatches) === false
|
||||
) {
|
||||
context.toRemove.push('css-specific');
|
||||
context.toAdd.push(directive);
|
||||
|
|
@ -545,8 +533,8 @@ function registerScriptlet(context, scriptletDetails) {
|
|||
|
||||
// update
|
||||
if (
|
||||
arrayEq(registered.matches, matches) === false ||
|
||||
arrayEq(registered.excludeMatches, excludeMatches) === false
|
||||
ut.strArrayEq(registered.matches, matches) === false ||
|
||||
ut.strArrayEq(registered.excludeMatches, excludeMatches) === false
|
||||
) {
|
||||
context.toRemove.push(id);
|
||||
context.toAdd.push(directive);
|
||||
|
|
@ -599,6 +587,7 @@ async function registerInjectables() {
|
|||
registerSpecific(context);
|
||||
registerGeneric(context, genericDetails);
|
||||
registerHighGeneric(context, genericDetails);
|
||||
registerToolbarIconToggler(context);
|
||||
|
||||
toRemove.push(...Array.from(before.keys()));
|
||||
|
||||
|
|
|
|||
27
platform/mv3/extension/js/scripting/toolbar-icon.js
Normal file
27
platform/mv3/extension/js/scripting/toolbar-icon.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*******************************************************************************
|
||||
|
||||
uBlock Origin Lite - a comprehensive, MV3-compliant content blocker
|
||||
Copyright (C) 2025-present Raymond Hill
|
||||
|
||||
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 {http://www.gnu.org/licenses/}.
|
||||
|
||||
Home: https://github.com/gorhill/uBlock
|
||||
*/
|
||||
|
||||
(function uBOL_toggleToolbarIcon() {
|
||||
chrome.runtime.sendMessage({
|
||||
what: 'toggleToolbarIcon',
|
||||
}).catch(( ) => {
|
||||
});
|
||||
})();
|
||||
|
|
@ -182,6 +182,19 @@ async function gotoURL(url, type) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// Important: We need to sort the arrays for fast comparison
|
||||
const strArrayEq = (a = [], b = [], sort = true) => {
|
||||
const alen = a.length;
|
||||
if ( alen !== b.length ) { return false; }
|
||||
if ( sort ) { a.sort(); b.sort(); }
|
||||
for ( let i = 0; i < alen; i++ ) {
|
||||
if ( a[i] !== b[i] ) { return false; }
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
export {
|
||||
broadcastMessage,
|
||||
parsedURLromOrigin,
|
||||
|
|
@ -195,4 +208,5 @@ export {
|
|||
hostnamesFromMatches,
|
||||
hasBroadHostPermissions,
|
||||
gotoURL,
|
||||
strArrayEq,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -52,9 +52,7 @@
|
|||
"activeTab",
|
||||
"declarativeNetRequest",
|
||||
"scripting",
|
||||
"storage",
|
||||
"tabs",
|
||||
"webNavigation"
|
||||
"storage"
|
||||
],
|
||||
"short_name": "uBO Lite",
|
||||
"version": "1.0",
|
||||
|
|
|
|||
|
|
@ -40,9 +40,7 @@
|
|||
"declarativeNetRequest",
|
||||
"declarativeNetRequestWithHostAccess",
|
||||
"scripting",
|
||||
"storage",
|
||||
"tabs",
|
||||
"webNavigation"
|
||||
"storage"
|
||||
],
|
||||
"short_name": "uBO Lite",
|
||||
"version": "1.0",
|
||||
|
|
|
|||
Loading…
Reference in a new issue