Skip to content

Commit 7ff750e

Browse files
committed
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.
1 parent 5e1f4d7 commit 7ff750e

File tree

8 files changed

+118
-63
lines changed

8 files changed

+118
-63
lines changed

platform/chromium/vapi-background.js

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -661,28 +661,25 @@ vAPI.Tabs = class {
661661
// https://github.com/uBlockOrigin/uBlock-issues/issues/32
662662
// Ensure ImageData for toolbar icon is valid before use.
663663

664-
vAPI.setIcon = (function() {
665-
const browserAction = chrome.browserAction,
666-
titleTemplate =
667-
chrome.runtime.getManifest().browser_action.default_title +
668-
' ({badge})';
664+
vAPI.setIcon = (( ) => {
665+
const browserAction = chrome.browserAction;
666+
const titleTemplate =
667+
browser.runtime.getManifest().browser_action.default_title +
668+
' ({badge})';
669669
const icons = [
670-
{
671-
path: { '16': 'img/icon_16-off.png', '32': 'img/icon_32-off.png' }
672-
},
673-
{
674-
path: { '16': 'img/icon_16.png', '32': 'img/icon_32.png' }
675-
}
670+
{ path: { '16': 'img/icon_16-off.png', '32': 'img/icon_32-off.png' } },
671+
{ path: { '16': 'img/icon_16.png', '32': 'img/icon_32.png' } },
676672
];
677673

678-
(function() {
674+
(( ) => {
679675
if ( browserAction.setIcon === undefined ) { return; }
680676

681-
// The global badge background color.
677+
// The global badge text and background color.
682678
if ( browserAction.setBadgeBackgroundColor !== undefined ) {
683-
browserAction.setBadgeBackgroundColor({
684-
color: [ 0x66, 0x66, 0x66, 0xFF ]
685-
});
679+
browserAction.setBadgeBackgroundColor({ color: '#666666' });
680+
}
681+
if ( browserAction.setBadgeTextColor !== undefined ) {
682+
browserAction.setBadgeTextColor({ color: '#FFFFFF' });
686683
}
687684

688685
// As of 2018-05, benchmarks show that only Chromium benefits for sure
@@ -698,7 +695,7 @@ vAPI.setIcon = (function() {
698695

699696
const imgs = [];
700697
for ( let i = 0; i < icons.length; i++ ) {
701-
let path = icons[i].path;
698+
const path = icons[i].path;
702699
for ( const key in path ) {
703700
if ( path.hasOwnProperty(key) === false ) { continue; }
704701
imgs.push({ i: i, p: key });
@@ -719,10 +716,10 @@ vAPI.setIcon = (function() {
719716
for ( const img of imgs ) {
720717
if ( img.r.complete === false ) { return; }
721718
}
722-
let ctx = document.createElement('canvas').getContext('2d');
723-
let iconData = [ null, null ];
719+
const ctx = document.createElement('canvas').getContext('2d');
720+
const iconData = [ null, null ];
724721
for ( const img of imgs ) {
725-
let w = img.r.naturalWidth, h = img.r.naturalHeight;
722+
const w = img.r.naturalWidth, h = img.r.naturalHeight;
726723
ctx.width = w; ctx.height = h;
727724
ctx.clearRect(0, 0, w, h);
728725
ctx.drawImage(img.r, 0, 0);
@@ -753,16 +750,23 @@ vAPI.setIcon = (function() {
753750
}
754751
})();
755752

756-
var onTabReady = function(tab, state, badge, parts) {
753+
const onTabReady = function(tab, details) {
757754
if ( vAPI.lastError() || !tab ) { return; }
758755

756+
const { parts, state, badge, color } = details;
757+
759758
if ( browserAction.setIcon !== undefined ) {
760-
if ( parts === undefined || (parts & 0x01) !== 0 ) {
759+
if ( parts === undefined || (parts & 0b001) !== 0 ) {
761760
browserAction.setIcon(
762761
Object.assign({ tabId: tab.id }, icons[state])
763762
);
764763
}
765-
browserAction.setBadgeText({ tabId: tab.id, text: badge });
764+
if ( (parts & 0b010) !== 0 ) {
765+
browserAction.setBadgeText({ tabId: tab.id, text: badge });
766+
}
767+
if ( (parts & 0b100) !== 0 ) {
768+
browserAction.setBadgeBackgroundColor({ tabId: tab.id, color });
769+
}
766770
}
767771

768772
if ( browserAction.setTitle !== undefined ) {
@@ -778,14 +782,13 @@ vAPI.setIcon = (function() {
778782

779783
// parts: bit 0 = icon
780784
// bit 1 = badge
785+
// bit 2 = badge color
781786

782-
return function(tabId, state, badge, parts) {
787+
return function(tabId, details) {
783788
tabId = toChromiumTabId(tabId);
784789
if ( tabId === 0 ) { return; }
785790

786-
chrome.tabs.get(tabId, function(tab) {
787-
onTabReady(tab, state, badge, parts);
788-
});
791+
browser.tabs.get(tabId, tab => onTabReady(tab, details));
789792

790793
if ( vAPI.contextMenu instanceof Object ) {
791794
vAPI.contextMenu.onMustUpdate(tabId);

src/js/background.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ const µBlock = (function() { // jshint ignore:line
4242
autoUpdateAssetFetchPeriod: 120,
4343
autoUpdateDelayAfterLaunch: 180,
4444
autoUpdatePeriod: 7,
45-
blockingProfiles: '11101 00001',
45+
blockingProfiles: '11101 11001 00001',
46+
blockingProfileColors: '#666666 #E7552C #F69454 #008DCB',
4647
cacheStorageAPI: 'unset',
4748
cacheStorageCompression: true,
4849
cacheControlForFirefox1376932: 'no-cache, no-store, must-revalidate',

src/js/commands.js

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -39,40 +39,15 @@
3939
if ( µBlock.canUseShortcuts === false ) { return; }
4040

4141
const relaxBlockingMode = function(tab) {
42-
if (
43-
tab instanceof Object === false ||
44-
tab.id <= 0
45-
) {
46-
return;
47-
}
42+
if ( tab instanceof Object === false || tab.id <= 0 ) { return; }
4843

4944
const µb = µBlock;
5045
const normalURL = µb.normalizePageURL(tab.id, tab.url);
5146

5247
if ( µb.getNetFilteringSwitch(normalURL) === false ) { return; }
5348

5449
const hn = µb.URI.hostnameFromURI(normalURL);
55-
56-
// Construct current blocking profile
57-
const ssw = µb.sessionSwitches;
58-
const sfw = µb.sessionFirewall;
59-
let currentProfile = 0;
60-
61-
if ( ssw.evaluateZ('no-scripting', hn) ) {
62-
currentProfile |= 0b00000010;
63-
}
64-
if ( µb.userSettings.advancedUserEnabled ) {
65-
if ( sfw.evaluateCellZY(hn, '*', '3p') === 1 ) {
66-
currentProfile |= 0b00000100;
67-
}
68-
if ( sfw.evaluateCellZY(hn, '*', '3p-script') === 1 ) {
69-
currentProfile |= 0b00001000;
70-
}
71-
if ( sfw.evaluateCellZY(hn, '*', '3p-frame') === 1 ) {
72-
currentProfile |= 0b00010000;
73-
}
74-
}
75-
50+
const currentProfile = µb.blockingModeFromHostname(hn);
7651
const profiles = [];
7752
for ( const s of µb.hiddenSettings.blockingProfiles.split(/\s+/) ) {
7853
const v = parseInt(s, 2);

src/js/messaging.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ var onMessage = function(request, sender, callback) {
425425
request.srcHostname,
426426
'net'
427427
);
428+
µb.updateToolbarIcon(request.tabId, 0b100);
428429
response = popupDataFromTabId(request.tabId);
429430
break;
430431

@@ -462,7 +463,7 @@ var onMessage = function(request, sender, callback) {
462463
pageStore = µb.pageStoreFromTabId(request.tabId);
463464
if ( pageStore ) {
464465
pageStore.toggleNetFilteringSwitch(request.url, request.scope, request.state);
465-
µb.updateToolbarIcon(request.tabId, 0x03);
466+
µb.updateToolbarIcon(request.tabId, 0b111);
466467
}
467468
break;
468469

src/js/storage.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
}
123123
self.log.verbosity = this.hiddenSettings.consoleLogLevel;
124124
resolve();
125+
this.fireDOMEvent('hiddenSettingsChanged');
125126
});
126127

127128
// <<<< end of executor

src/js/tab.js

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@
342342

343343
// Blocked
344344
if ( µb.userSettings.showIconBadge ) {
345-
µb.updateToolbarIcon(openerTabId, 0x02);
345+
µb.updateToolbarIcon(openerTabId, 0b010);
346346
}
347347

348348
// It is a popup, block and remove the tab.
@@ -859,7 +859,7 @@ vAPI.tabs = new vAPI.Tabs();
859859
// Create an entry for the tab if it doesn't exist.
860860

861861
µBlock.bindTabToPageStats = function(tabId, context) {
862-
this.updateToolbarIcon(tabId, 0x03);
862+
this.updateToolbarIcon(tabId, 0b111);
863863

864864
// Do not create a page store for URLs which are of no interests
865865
if ( this.tabContextManager.exists(tabId) === false ) {
@@ -954,6 +954,24 @@ vAPI.tabs = new vAPI.Tabs();
954954

955955
µBlock.updateToolbarIcon = (( ) => {
956956
const tabIdToDetails = new Map();
957+
const blockingProfileColors = [
958+
'#666666',
959+
'#E7552C',
960+
'#F69454',
961+
'#008DCB',
962+
];
963+
964+
self.addEventListener(
965+
'hiddenSettingsChanged',
966+
( ) => {
967+
const colors = µBlock.hiddenSettings.blockingProfileColors;
968+
if ( /^#[0-9a-f]{6}(\s#[0-9a-f]{6}){3}$/i.test(colors) === false ) {
969+
return;
970+
}
971+
blockingProfileColors.length = 0;
972+
blockingProfileColors.push(...colors.split(/\s+/));
973+
}
974+
);
957975

958976
const updateBadge = function(tabId) {
959977
const µb = µBlock;
@@ -962,26 +980,40 @@ vAPI.tabs = new vAPI.Tabs();
962980

963981
let state = 0;
964982
let badge = '';
983+
let color = blockingProfileColors[0];
965984

966985
let pageStore = µb.pageStoreFromTabId(tabId);
967986
if ( pageStore !== null ) {
968987
state = pageStore.getNetFilteringSwitch() ? 1 : 0;
969988
if (
970989
state === 1 &&
971-
µb.userSettings.showIconBadge &&
972-
pageStore.perLoadBlockedRequestCount
990+
µb.userSettings.showIconBadge
973991
) {
974-
badge = µb.formatCount(pageStore.perLoadBlockedRequestCount);
992+
if ( (parts & 0b010) !== 0 && pageStore.perLoadBlockedRequestCount ) {
993+
badge = µb.formatCount(pageStore.perLoadBlockedRequestCount);
994+
}
995+
if ( (parts & 0b100) !== 0 ) {
996+
let profile = µb.blockingModeFromHostname(pageStore.tabHostname);
997+
if ( (profile & 0b00000010) !== 0 ) {
998+
color = blockingProfileColors[3];
999+
} else if ( (profile & 0b00000100) !== 0 ) {
1000+
color = blockingProfileColors[2];
1001+
} else if ( (profile & 0b00011000) !== 0 ) {
1002+
color = blockingProfileColors[1];
1003+
}
1004+
}
9751005
}
9761006
}
9771007

978-
vAPI.setIcon(tabId, state, badge, parts);
1008+
vAPI.setIcon(tabId, { parts, state, badge, color });
9791009
};
9801010

9811011
// parts: bit 0 = icon
9821012
// bit 1 = badge
1013+
// bit 2 = badge color
9831014

984-
return function(tabId, newParts = 0b11) {
1015+
return function(tabId, newParts = 0b111) {
1016+
if ( typeof tabId !== 'number' ) { return; }
9851017
if ( vAPI.isBehindTheSceneTabId(tabId) ) { return; }
9861018
let currentParts = tabIdToDetails.get(tabId);
9871019
if ( currentParts === newParts ) { return; }

src/js/ublock.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ const matchBucket = function(url, hostname, bucket, start) {
409409
this.redirectEngine.invalidateResourcesSelfie();
410410
this.loadRedirectResources();
411411
}
412+
this.fireDOMEvent('hiddenSettingsChanged');
412413
};
413414

414415
/******************************************************************************/
@@ -506,6 +507,10 @@ const matchBucket = function(url, hostname, bucket, start) {
506507

507508
// https://github.com/chrisaljoudi/uBlock/issues/420
508509
this.cosmeticFilteringEngine.removeFromSelectorCache(srcHostname, 'net');
510+
511+
if ( requestType.startsWith('3p') ) {
512+
this.updateToolbarIcon(details.tabId, 0b100);
513+
}
509514
};
510515

511516
/******************************************************************************/
@@ -548,6 +553,9 @@ const matchBucket = function(url, hostname, bucket, start) {
548553

549554
// Take action if needed
550555
switch ( details.name ) {
556+
case 'no-scripting':
557+
this.updateToolbarIcon(details.tabId, 0b100);
558+
break;
551559
case 'no-cosmetic-filtering':
552560
this.scriptlets.injectDeep(
553561
details.tabId,
@@ -577,6 +585,28 @@ const matchBucket = function(url, hostname, bucket, start) {
577585

578586
/******************************************************************************/
579587

588+
µBlock.blockingModeFromHostname = function(hn) {
589+
let bits = 0;
590+
if ( this.sessionSwitches.evaluateZ('no-scripting', hn) ) {
591+
bits |= 0b00000010;
592+
}
593+
if ( this.userSettings.advancedUserEnabled ) {
594+
const fw = this.sessionFirewall;
595+
if ( fw.evaluateCellZY(hn, '*', '3p') === 1 ) {
596+
bits |= 0b00000100;
597+
}
598+
if ( fw.evaluateCellZY(hn, '*', '3p-script') === 1 ) {
599+
bits |= 0b00001000;
600+
}
601+
if ( fw.evaluateCellZY(hn, '*', '3p-frame') === 1 ) {
602+
bits |= 0b00010000;
603+
}
604+
}
605+
return bits;
606+
};
607+
608+
/******************************************************************************/
609+
580610
// https://github.com/NanoMeow/QuickReports/issues/6#issuecomment-414516623
581611
// Inject as early as possible to make the cosmetic logger code less
582612
// sensitive to the removal of DOM nodes which may match injected

src/js/utils.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,3 +700,15 @@
700700
return datasetPromise;
701701
};
702702
})();
703+
704+
/******************************************************************************/
705+
706+
µBlock.fireDOMEvent = function(name) {
707+
if (
708+
window instanceof Object &&
709+
window.dispatchEvent instanceof Function &&
710+
window.CustomEvent instanceof Function
711+
) {
712+
window.dispatchEvent(new CustomEvent(name));
713+
}
714+
};

0 commit comments

Comments
 (0)