mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-10 09:07:54 +01:00
Reflect blocking mode in badge color of toolbar icon
Related feedback: - https://www.reddit.com/r/uBlockOrigin/comments/cmh910/ Additionally, the `3p` rule has been made distinct from `3p-script`/`3p-frame` for the purpose of "Relax blocking mode" command. The badge color will hint at the current blocking mode. There are four colors for the four following blocking modes: - JavaScript wholly disabled - All 3rd parties blocked - 3rd-party scripts and frames blocked - None of the above The default badge color will be used when JavaScript is not wholly disabled and when there are no rules for `3p`, `3p-script` or `3p-frame`. A new advanced setting has been added to let the user choose the badge colors for the various blocking modes, `blockingProfileColors`. The value *must* be a sequence of 4 valid CSS color values that match 6 hexadecimal digits prefixed with`#` -- anything else will be ignored.
This commit is contained in:
parent
5e1f4d7906
commit
7ff750eaf6
8 changed files with 118 additions and 63 deletions
|
@ -661,28 +661,25 @@ vAPI.Tabs = class {
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/32
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/32
|
||||||
// Ensure ImageData for toolbar icon is valid before use.
|
// Ensure ImageData for toolbar icon is valid before use.
|
||||||
|
|
||||||
vAPI.setIcon = (function() {
|
vAPI.setIcon = (( ) => {
|
||||||
const browserAction = chrome.browserAction,
|
const browserAction = chrome.browserAction;
|
||||||
titleTemplate =
|
const titleTemplate =
|
||||||
chrome.runtime.getManifest().browser_action.default_title +
|
browser.runtime.getManifest().browser_action.default_title +
|
||||||
' ({badge})';
|
' ({badge})';
|
||||||
const icons = [
|
const icons = [
|
||||||
{
|
{ path: { '16': 'img/icon_16-off.png', '32': 'img/icon_32-off.png' } },
|
||||||
path: { '16': 'img/icon_16-off.png', '32': 'img/icon_32-off.png' }
|
{ path: { '16': 'img/icon_16.png', '32': 'img/icon_32.png' } },
|
||||||
},
|
|
||||||
{
|
|
||||||
path: { '16': 'img/icon_16.png', '32': 'img/icon_32.png' }
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
(function() {
|
(( ) => {
|
||||||
if ( browserAction.setIcon === undefined ) { return; }
|
if ( browserAction.setIcon === undefined ) { return; }
|
||||||
|
|
||||||
// The global badge background color.
|
// The global badge text and background color.
|
||||||
if ( browserAction.setBadgeBackgroundColor !== undefined ) {
|
if ( browserAction.setBadgeBackgroundColor !== undefined ) {
|
||||||
browserAction.setBadgeBackgroundColor({
|
browserAction.setBadgeBackgroundColor({ color: '#666666' });
|
||||||
color: [ 0x66, 0x66, 0x66, 0xFF ]
|
}
|
||||||
});
|
if ( browserAction.setBadgeTextColor !== undefined ) {
|
||||||
|
browserAction.setBadgeTextColor({ color: '#FFFFFF' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// As of 2018-05, benchmarks show that only Chromium benefits for sure
|
// As of 2018-05, benchmarks show that only Chromium benefits for sure
|
||||||
|
@ -698,7 +695,7 @@ vAPI.setIcon = (function() {
|
||||||
|
|
||||||
const imgs = [];
|
const imgs = [];
|
||||||
for ( let i = 0; i < icons.length; i++ ) {
|
for ( let i = 0; i < icons.length; i++ ) {
|
||||||
let path = icons[i].path;
|
const path = icons[i].path;
|
||||||
for ( const key in path ) {
|
for ( const key in path ) {
|
||||||
if ( path.hasOwnProperty(key) === false ) { continue; }
|
if ( path.hasOwnProperty(key) === false ) { continue; }
|
||||||
imgs.push({ i: i, p: key });
|
imgs.push({ i: i, p: key });
|
||||||
|
@ -719,10 +716,10 @@ vAPI.setIcon = (function() {
|
||||||
for ( const img of imgs ) {
|
for ( const img of imgs ) {
|
||||||
if ( img.r.complete === false ) { return; }
|
if ( img.r.complete === false ) { return; }
|
||||||
}
|
}
|
||||||
let ctx = document.createElement('canvas').getContext('2d');
|
const ctx = document.createElement('canvas').getContext('2d');
|
||||||
let iconData = [ null, null ];
|
const iconData = [ null, null ];
|
||||||
for ( const img of imgs ) {
|
for ( const img of imgs ) {
|
||||||
let w = img.r.naturalWidth, h = img.r.naturalHeight;
|
const w = img.r.naturalWidth, h = img.r.naturalHeight;
|
||||||
ctx.width = w; ctx.height = h;
|
ctx.width = w; ctx.height = h;
|
||||||
ctx.clearRect(0, 0, w, h);
|
ctx.clearRect(0, 0, w, h);
|
||||||
ctx.drawImage(img.r, 0, 0);
|
ctx.drawImage(img.r, 0, 0);
|
||||||
|
@ -753,16 +750,23 @@ vAPI.setIcon = (function() {
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var onTabReady = function(tab, state, badge, parts) {
|
const onTabReady = function(tab, details) {
|
||||||
if ( vAPI.lastError() || !tab ) { return; }
|
if ( vAPI.lastError() || !tab ) { return; }
|
||||||
|
|
||||||
|
const { parts, state, badge, color } = details;
|
||||||
|
|
||||||
if ( browserAction.setIcon !== undefined ) {
|
if ( browserAction.setIcon !== undefined ) {
|
||||||
if ( parts === undefined || (parts & 0x01) !== 0 ) {
|
if ( parts === undefined || (parts & 0b001) !== 0 ) {
|
||||||
browserAction.setIcon(
|
browserAction.setIcon(
|
||||||
Object.assign({ tabId: tab.id }, icons[state])
|
Object.assign({ tabId: tab.id }, icons[state])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
browserAction.setBadgeText({ tabId: tab.id, text: badge });
|
if ( (parts & 0b010) !== 0 ) {
|
||||||
|
browserAction.setBadgeText({ tabId: tab.id, text: badge });
|
||||||
|
}
|
||||||
|
if ( (parts & 0b100) !== 0 ) {
|
||||||
|
browserAction.setBadgeBackgroundColor({ tabId: tab.id, color });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( browserAction.setTitle !== undefined ) {
|
if ( browserAction.setTitle !== undefined ) {
|
||||||
|
@ -778,14 +782,13 @@ vAPI.setIcon = (function() {
|
||||||
|
|
||||||
// parts: bit 0 = icon
|
// parts: bit 0 = icon
|
||||||
// bit 1 = badge
|
// bit 1 = badge
|
||||||
|
// bit 2 = badge color
|
||||||
|
|
||||||
return function(tabId, state, badge, parts) {
|
return function(tabId, details) {
|
||||||
tabId = toChromiumTabId(tabId);
|
tabId = toChromiumTabId(tabId);
|
||||||
if ( tabId === 0 ) { return; }
|
if ( tabId === 0 ) { return; }
|
||||||
|
|
||||||
chrome.tabs.get(tabId, function(tab) {
|
browser.tabs.get(tabId, tab => onTabReady(tab, details));
|
||||||
onTabReady(tab, state, badge, parts);
|
|
||||||
});
|
|
||||||
|
|
||||||
if ( vAPI.contextMenu instanceof Object ) {
|
if ( vAPI.contextMenu instanceof Object ) {
|
||||||
vAPI.contextMenu.onMustUpdate(tabId);
|
vAPI.contextMenu.onMustUpdate(tabId);
|
||||||
|
|
|
@ -42,7 +42,8 @@ const µBlock = (function() { // jshint ignore:line
|
||||||
autoUpdateAssetFetchPeriod: 120,
|
autoUpdateAssetFetchPeriod: 120,
|
||||||
autoUpdateDelayAfterLaunch: 180,
|
autoUpdateDelayAfterLaunch: 180,
|
||||||
autoUpdatePeriod: 7,
|
autoUpdatePeriod: 7,
|
||||||
blockingProfiles: '11101 00001',
|
blockingProfiles: '11101 11001 00001',
|
||||||
|
blockingProfileColors: '#666666 #E7552C #F69454 #008DCB',
|
||||||
cacheStorageAPI: 'unset',
|
cacheStorageAPI: 'unset',
|
||||||
cacheStorageCompression: true,
|
cacheStorageCompression: true,
|
||||||
cacheControlForFirefox1376932: 'no-cache, no-store, must-revalidate',
|
cacheControlForFirefox1376932: 'no-cache, no-store, must-revalidate',
|
||||||
|
|
|
@ -39,12 +39,7 @@
|
||||||
if ( µBlock.canUseShortcuts === false ) { return; }
|
if ( µBlock.canUseShortcuts === false ) { return; }
|
||||||
|
|
||||||
const relaxBlockingMode = function(tab) {
|
const relaxBlockingMode = function(tab) {
|
||||||
if (
|
if ( tab instanceof Object === false || tab.id <= 0 ) { return; }
|
||||||
tab instanceof Object === false ||
|
|
||||||
tab.id <= 0
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const µb = µBlock;
|
const µb = µBlock;
|
||||||
const normalURL = µb.normalizePageURL(tab.id, tab.url);
|
const normalURL = µb.normalizePageURL(tab.id, tab.url);
|
||||||
|
@ -52,27 +47,7 @@ const relaxBlockingMode = function(tab) {
|
||||||
if ( µb.getNetFilteringSwitch(normalURL) === false ) { return; }
|
if ( µb.getNetFilteringSwitch(normalURL) === false ) { return; }
|
||||||
|
|
||||||
const hn = µb.URI.hostnameFromURI(normalURL);
|
const hn = µb.URI.hostnameFromURI(normalURL);
|
||||||
|
const currentProfile = µb.blockingModeFromHostname(hn);
|
||||||
// Construct current blocking profile
|
|
||||||
const ssw = µb.sessionSwitches;
|
|
||||||
const sfw = µb.sessionFirewall;
|
|
||||||
let currentProfile = 0;
|
|
||||||
|
|
||||||
if ( ssw.evaluateZ('no-scripting', hn) ) {
|
|
||||||
currentProfile |= 0b00000010;
|
|
||||||
}
|
|
||||||
if ( µb.userSettings.advancedUserEnabled ) {
|
|
||||||
if ( sfw.evaluateCellZY(hn, '*', '3p') === 1 ) {
|
|
||||||
currentProfile |= 0b00000100;
|
|
||||||
}
|
|
||||||
if ( sfw.evaluateCellZY(hn, '*', '3p-script') === 1 ) {
|
|
||||||
currentProfile |= 0b00001000;
|
|
||||||
}
|
|
||||||
if ( sfw.evaluateCellZY(hn, '*', '3p-frame') === 1 ) {
|
|
||||||
currentProfile |= 0b00010000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const profiles = [];
|
const profiles = [];
|
||||||
for ( const s of µb.hiddenSettings.blockingProfiles.split(/\s+/) ) {
|
for ( const s of µb.hiddenSettings.blockingProfiles.split(/\s+/) ) {
|
||||||
const v = parseInt(s, 2);
|
const v = parseInt(s, 2);
|
||||||
|
|
|
@ -425,6 +425,7 @@ var onMessage = function(request, sender, callback) {
|
||||||
request.srcHostname,
|
request.srcHostname,
|
||||||
'net'
|
'net'
|
||||||
);
|
);
|
||||||
|
µb.updateToolbarIcon(request.tabId, 0b100);
|
||||||
response = popupDataFromTabId(request.tabId);
|
response = popupDataFromTabId(request.tabId);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -462,7 +463,7 @@ var onMessage = function(request, sender, callback) {
|
||||||
pageStore = µb.pageStoreFromTabId(request.tabId);
|
pageStore = µb.pageStoreFromTabId(request.tabId);
|
||||||
if ( pageStore ) {
|
if ( pageStore ) {
|
||||||
pageStore.toggleNetFilteringSwitch(request.url, request.scope, request.state);
|
pageStore.toggleNetFilteringSwitch(request.url, request.scope, request.state);
|
||||||
µb.updateToolbarIcon(request.tabId, 0x03);
|
µb.updateToolbarIcon(request.tabId, 0b111);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -122,6 +122,7 @@
|
||||||
}
|
}
|
||||||
self.log.verbosity = this.hiddenSettings.consoleLogLevel;
|
self.log.verbosity = this.hiddenSettings.consoleLogLevel;
|
||||||
resolve();
|
resolve();
|
||||||
|
this.fireDOMEvent('hiddenSettingsChanged');
|
||||||
});
|
});
|
||||||
|
|
||||||
// <<<< end of executor
|
// <<<< end of executor
|
||||||
|
|
|
@ -342,7 +342,7 @@
|
||||||
|
|
||||||
// Blocked
|
// Blocked
|
||||||
if ( µb.userSettings.showIconBadge ) {
|
if ( µb.userSettings.showIconBadge ) {
|
||||||
µb.updateToolbarIcon(openerTabId, 0x02);
|
µb.updateToolbarIcon(openerTabId, 0b010);
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is a popup, block and remove the tab.
|
// It is a popup, block and remove the tab.
|
||||||
|
@ -859,7 +859,7 @@ vAPI.tabs = new vAPI.Tabs();
|
||||||
// Create an entry for the tab if it doesn't exist.
|
// Create an entry for the tab if it doesn't exist.
|
||||||
|
|
||||||
µBlock.bindTabToPageStats = function(tabId, context) {
|
µBlock.bindTabToPageStats = function(tabId, context) {
|
||||||
this.updateToolbarIcon(tabId, 0x03);
|
this.updateToolbarIcon(tabId, 0b111);
|
||||||
|
|
||||||
// Do not create a page store for URLs which are of no interests
|
// Do not create a page store for URLs which are of no interests
|
||||||
if ( this.tabContextManager.exists(tabId) === false ) {
|
if ( this.tabContextManager.exists(tabId) === false ) {
|
||||||
|
@ -954,6 +954,24 @@ vAPI.tabs = new vAPI.Tabs();
|
||||||
|
|
||||||
µBlock.updateToolbarIcon = (( ) => {
|
µBlock.updateToolbarIcon = (( ) => {
|
||||||
const tabIdToDetails = new Map();
|
const tabIdToDetails = new Map();
|
||||||
|
const blockingProfileColors = [
|
||||||
|
'#666666',
|
||||||
|
'#E7552C',
|
||||||
|
'#F69454',
|
||||||
|
'#008DCB',
|
||||||
|
];
|
||||||
|
|
||||||
|
self.addEventListener(
|
||||||
|
'hiddenSettingsChanged',
|
||||||
|
( ) => {
|
||||||
|
const colors = µBlock.hiddenSettings.blockingProfileColors;
|
||||||
|
if ( /^#[0-9a-f]{6}(\s#[0-9a-f]{6}){3}$/i.test(colors) === false ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
blockingProfileColors.length = 0;
|
||||||
|
blockingProfileColors.push(...colors.split(/\s+/));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const updateBadge = function(tabId) {
|
const updateBadge = function(tabId) {
|
||||||
const µb = µBlock;
|
const µb = µBlock;
|
||||||
|
@ -962,26 +980,40 @@ vAPI.tabs = new vAPI.Tabs();
|
||||||
|
|
||||||
let state = 0;
|
let state = 0;
|
||||||
let badge = '';
|
let badge = '';
|
||||||
|
let color = blockingProfileColors[0];
|
||||||
|
|
||||||
let pageStore = µb.pageStoreFromTabId(tabId);
|
let pageStore = µb.pageStoreFromTabId(tabId);
|
||||||
if ( pageStore !== null ) {
|
if ( pageStore !== null ) {
|
||||||
state = pageStore.getNetFilteringSwitch() ? 1 : 0;
|
state = pageStore.getNetFilteringSwitch() ? 1 : 0;
|
||||||
if (
|
if (
|
||||||
state === 1 &&
|
state === 1 &&
|
||||||
µb.userSettings.showIconBadge &&
|
µb.userSettings.showIconBadge
|
||||||
pageStore.perLoadBlockedRequestCount
|
|
||||||
) {
|
) {
|
||||||
badge = µb.formatCount(pageStore.perLoadBlockedRequestCount);
|
if ( (parts & 0b010) !== 0 && pageStore.perLoadBlockedRequestCount ) {
|
||||||
|
badge = µb.formatCount(pageStore.perLoadBlockedRequestCount);
|
||||||
|
}
|
||||||
|
if ( (parts & 0b100) !== 0 ) {
|
||||||
|
let profile = µb.blockingModeFromHostname(pageStore.tabHostname);
|
||||||
|
if ( (profile & 0b00000010) !== 0 ) {
|
||||||
|
color = blockingProfileColors[3];
|
||||||
|
} else if ( (profile & 0b00000100) !== 0 ) {
|
||||||
|
color = blockingProfileColors[2];
|
||||||
|
} else if ( (profile & 0b00011000) !== 0 ) {
|
||||||
|
color = blockingProfileColors[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vAPI.setIcon(tabId, state, badge, parts);
|
vAPI.setIcon(tabId, { parts, state, badge, color });
|
||||||
};
|
};
|
||||||
|
|
||||||
// parts: bit 0 = icon
|
// parts: bit 0 = icon
|
||||||
// bit 1 = badge
|
// bit 1 = badge
|
||||||
|
// bit 2 = badge color
|
||||||
|
|
||||||
return function(tabId, newParts = 0b11) {
|
return function(tabId, newParts = 0b111) {
|
||||||
|
if ( typeof tabId !== 'number' ) { return; }
|
||||||
if ( vAPI.isBehindTheSceneTabId(tabId) ) { return; }
|
if ( vAPI.isBehindTheSceneTabId(tabId) ) { return; }
|
||||||
let currentParts = tabIdToDetails.get(tabId);
|
let currentParts = tabIdToDetails.get(tabId);
|
||||||
if ( currentParts === newParts ) { return; }
|
if ( currentParts === newParts ) { return; }
|
||||||
|
|
|
@ -409,6 +409,7 @@ const matchBucket = function(url, hostname, bucket, start) {
|
||||||
this.redirectEngine.invalidateResourcesSelfie();
|
this.redirectEngine.invalidateResourcesSelfie();
|
||||||
this.loadRedirectResources();
|
this.loadRedirectResources();
|
||||||
}
|
}
|
||||||
|
this.fireDOMEvent('hiddenSettingsChanged');
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -506,6 +507,10 @@ const matchBucket = function(url, hostname, bucket, start) {
|
||||||
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/420
|
// https://github.com/chrisaljoudi/uBlock/issues/420
|
||||||
this.cosmeticFilteringEngine.removeFromSelectorCache(srcHostname, 'net');
|
this.cosmeticFilteringEngine.removeFromSelectorCache(srcHostname, 'net');
|
||||||
|
|
||||||
|
if ( requestType.startsWith('3p') ) {
|
||||||
|
this.updateToolbarIcon(details.tabId, 0b100);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -548,6 +553,9 @@ const matchBucket = function(url, hostname, bucket, start) {
|
||||||
|
|
||||||
// Take action if needed
|
// Take action if needed
|
||||||
switch ( details.name ) {
|
switch ( details.name ) {
|
||||||
|
case 'no-scripting':
|
||||||
|
this.updateToolbarIcon(details.tabId, 0b100);
|
||||||
|
break;
|
||||||
case 'no-cosmetic-filtering':
|
case 'no-cosmetic-filtering':
|
||||||
this.scriptlets.injectDeep(
|
this.scriptlets.injectDeep(
|
||||||
details.tabId,
|
details.tabId,
|
||||||
|
@ -577,6 +585,28 @@ const matchBucket = function(url, hostname, bucket, start) {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
µBlock.blockingModeFromHostname = function(hn) {
|
||||||
|
let bits = 0;
|
||||||
|
if ( this.sessionSwitches.evaluateZ('no-scripting', hn) ) {
|
||||||
|
bits |= 0b00000010;
|
||||||
|
}
|
||||||
|
if ( this.userSettings.advancedUserEnabled ) {
|
||||||
|
const fw = this.sessionFirewall;
|
||||||
|
if ( fw.evaluateCellZY(hn, '*', '3p') === 1 ) {
|
||||||
|
bits |= 0b00000100;
|
||||||
|
}
|
||||||
|
if ( fw.evaluateCellZY(hn, '*', '3p-script') === 1 ) {
|
||||||
|
bits |= 0b00001000;
|
||||||
|
}
|
||||||
|
if ( fw.evaluateCellZY(hn, '*', '3p-frame') === 1 ) {
|
||||||
|
bits |= 0b00010000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bits;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
// https://github.com/NanoMeow/QuickReports/issues/6#issuecomment-414516623
|
// https://github.com/NanoMeow/QuickReports/issues/6#issuecomment-414516623
|
||||||
// Inject as early as possible to make the cosmetic logger code less
|
// Inject as early as possible to make the cosmetic logger code less
|
||||||
// sensitive to the removal of DOM nodes which may match injected
|
// sensitive to the removal of DOM nodes which may match injected
|
||||||
|
|
|
@ -700,3 +700,15 @@
|
||||||
return datasetPromise;
|
return datasetPromise;
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
µBlock.fireDOMEvent = function(name) {
|
||||||
|
if (
|
||||||
|
window instanceof Object &&
|
||||||
|
window.dispatchEvent instanceof Function &&
|
||||||
|
window.CustomEvent instanceof Function
|
||||||
|
) {
|
||||||
|
window.dispatchEvent(new CustomEvent(name));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in a new issue