Support expanding/collpasing of specific domains

This is related to the list of domains/subdomains in
the dynamic filtering pane of the popup panel.

Related issue:
- https://github.com/gorhill/uBlock/issues/284

Clicking on the empty space of a row will toggle
the visibility of the subdomains.

Additionally, the root context will always be visible
regardless of the expand/collspase state, along with
a visual indicator that a specific domain or subdomain
is the actual root context.  (the root context is the
hostname in which local rules are created).
This commit is contained in:
Raymond Hill 2019-12-30 09:54:11 -05:00
parent 2da8948928
commit 56cc2b1256
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
4 changed files with 143 additions and 72 deletions

View File

@ -244,42 +244,41 @@ body[dir="rtl"] #tooltip {
text-align: right;
}
#firewallContainer > div {
background-color: #e6e6e6;
border: 0;
direction: ltr;
display: flex;
justify-content: flex-end;
margin: 0;
margin-top: 1px;
padding: 0;
}
#firewallContainer > div:hover {
background-color: #f0f0f0;
#firewallContainer > div:first-child {
margin-top: 0;
}
#firewallContainer > div:first-child ~ div:not([class]) {
#firewallContainer > div:first-child ~ div[data-des="*"] {
display: none;
}
#firewallContainer.minimized > div.isSubDomain {
#firewallContainer:not(.expanded) > div.isSubDomain:not(.expandException):not(.isRootContext),
#firewallContainer.expanded > div.isSubDomain.expandException:not(.isRootContext) {
display: none;
}
#firewallContainer > div > span {
background-color: transparent;
background-color: #e6e6e6;
border: none;
border-bottom: 1px solid white;
box-sizing: border-box;
-moz-box-sizing: border-box;
color: #000;
display: inline-block;
height: 1.9em;
line-height: 1.9;
overflow: hidden;
display: inline-flex;
flex-shrink: 0;
line-height: 2;
position: relative;
vertical-align: top;
}
#firewallContainer > div:first-of-type > span:first-of-type {
cursor: pointer;
}
#firewallContainer > div > span:first-of-type {
justify-content: flex-end;
padding-right: 2px;
position: relative;
text-overflow: ellipsis;
width: calc(100% - 4em);
}
#firewallContainer > div > span:first-of-type > sup {
@ -295,45 +294,47 @@ body[dir="rtl"] #tooltip {
#firewallContainer > div.isDomain > span.isIDN:first-of-type > sup::before {
content: '\0416\2002';
}
#firewallContainer > div > span:first-of-type ~ span {
margin-left: 1px;
width: 4em;
}
#firewallContainer > div > span:nth-of-type(2) {
display: none;
}
#firewallContainer > div > span:first-of-type ~ span {
border-left: 1px solid white;
width: 4em;
}
#firewallContainer > div > span:nth-of-type(3),
#firewallContainer > div > span:nth-of-type(4) {
color: #444;
text-align: center;
}
#firewallContainer > div > span:nth-of-type(4) {
display: none;
font-family: monospace;
text-align: center;
}
#firewallContainer > div.isDomain > span:first-of-type {
font-weight: bold;
}
#firewallContainer > div:first-of-type > span:first-of-type::before {
color: #aaa;
content: '\2012';
content: '+';
padding-right: 0.25em;
}
#firewallContainer.minimized > div:first-of-type > span:first-of-type::before {
content: '+';
#firewallContainer.expanded > div:first-of-type > span:first-of-type::before {
content: '\2012';
}
#firewallContainer.minimized > div.isDomain > span:nth-of-type(3) {
display: none;
}
#firewallContainer.minimized > div.isDomain > span:nth-of-type(4) {
display: inline-block;
#firewallContainer > div[data-des="*"] > span:nth-of-type(3),
#firewallContainer > div.isSubDomain > span:nth-of-type(3),
#firewallContainer > div.isSubDomain.isRootContext > span:nth-of-type(3),
#firewallContainer.expanded > div:not(.expandException) > span:nth-of-type(3),
#firewallContainer:not(.expanded) > div.expandException > span:nth-of-type(3),
#firewallContainer:not(.expanded) > div.isDomain:not(.expandException) > span:nth-of-type(4),
#firewallContainer.expanded > div.isDomain.expandException > span:nth-of-type(4) {
display: inline-flex;
justify-content: space-between;
}
#firewallContainer > div > span[data-acount]::before,
#firewallContainer > div > span[data-bcount]::after {
font-family: monospace;
position: absolute;
content: ' ';
}
#firewallContainer > div > span[data-acount]::before {
left: 0.1em;
padding-left: 0.1em;
}
#firewallContainer > div > span[data-acount="1"]::before {
content: '+';
@ -345,7 +346,7 @@ body[dir="rtl"] #tooltip {
content: '+++';
}
#firewallContainer > div > span[data-bcount]::after {
right: 0.1em;
padding-right: 0.1em;
}
#firewallContainer > div > span[data-bcount="1"]::after {
content: '\2212';
@ -361,10 +362,10 @@ body.advancedUser #firewallContainer > div > span:first-of-type {
width: calc(100% - 8em);
}
body.advancedUser #firewallContainer > div > span:nth-of-type(2) {
display: inline-block;
display: inline-flex;
}
body.advancedUser #firewallContainer > div:first-child ~ div:not([class]) {
display: block;
body.advancedUser #firewallContainer > div:first-child ~ div[data-des="*"] {
display: flex;
}
body.advancedUser #firewallContainer > div > span:first-of-type ~ span {
cursor: pointer;
@ -373,10 +374,13 @@ body.advancedUser #firewallContainer > div > span:first-of-type ~ span {
/**
Small coloured label at the left of a row
*/
#firewallContainer > div.isRootContext > span:first-of-type::before,
#firewallContainer > div.allowed > span:first-of-type::before,
#firewallContainer > div.blocked > span:first-of-type::before,
#firewallContainer.minimized > div.isDomain.totalAllowed > span:first-of-type::before,
#firewallContainer.minimized > div.isDomain.totalBlocked > span:first-of-type::before {
#firewallContainer:not(.expanded) > div.isDomain.totalAllowed:not(.expandException) > span:first-of-type::before,
#firewallContainer:not(.expanded) > div.isDomain.totalBlocked:not(.expandException) > span:first-of-type::before,
#firewallContainer.expanded > div.isDomain.totalAllowed.expandException > span:first-of-type::before,
#firewallContainer.expanded > div.isDomain.totalBlocked.expandException > span:first-of-type::before {
box-sizing: border-box;
content: '';
display: inline-block;
@ -386,28 +390,32 @@ body.advancedUser #firewallContainer > div > span:first-of-type ~ span {
position: absolute;
width: 7px;
}
#firewallContainer > div.isRootContext > span:first-of-type::before {
background-color: rgb(127, 127, 127);
width: 14px !important;
}
/**
Source for color-blind color scheme from https://github.com/WyohKnott:
https://github.com/chrisaljoudi/uBlock/issues/467#issuecomment-95177219
*/
#firewallContainer > div.allowed > span:first-of-type::before,
#firewallContainer.minimized > div.isDomain.totalAllowed > span:first-of-type::before {
#firewallContainer > div.isDomain.totalAllowed > span:first-of-type::before {
background-color: rgb(0, 160, 0);
}
#firewallContainer.colorBlind > div.allowed > span:first-of-type::before,
#firewallContainer.colorBlind.minimized > div.isDomain.totalAllowed > span:first-of-type::before {
#firewallContainer.colorBlind > div.isDomain.totalAllowed > span:first-of-type::before {
background-color: rgb(255, 194, 57);
}
#firewallContainer > div.blocked > span:first-of-type::before,
#firewallContainer.minimized > div.isDomain.totalBlocked > span:first-of-type::before {
#firewallContainer > div.isDomain.totalBlocked > span:first-of-type::before {
background-color: rgb(192, 0, 0);
}
#firewallContainer.colorBlind > div.blocked > span:first-of-type::before,
#firewallContainer.colorBlind.minimized > div.isDomain.totalBlocked > span:first-of-type::before {
#firewallContainer.colorBlind > div.isDomain.totalBlocked > span:first-of-type::before {
background-color: rgb(0, 19, 110);
}
#firewallContainer > div.allowed.blocked > span:first-of-type::before,
#firewallContainer.minimized > div.isDomain.totalAllowed.totalBlocked > span:first-of-type::before {
#firewallContainer > div.isDomain.totalAllowed.totalBlocked > span:first-of-type::before {
background-color: rgb(192, 160, 0);
}
/* Rule cells */

View File

@ -217,7 +217,7 @@ const getHostnameDict = function(hostnameToCountMap) {
blockCount: blockCount,
allowCount: allowCount,
totalBlockCount: 0,
totalAllowCount: 0
totalAllowCount: 0,
};
}
return r;

View File

@ -244,12 +244,12 @@ const updateFirewallCell = function(scope, des, type, rule) {
if ( hnDetails.allowCount !== 0 ) {
cell.setAttribute('data-acount', Math.min(Math.ceil(Math.log(hnDetails.allowCount + 1) / Math.LN10), 3));
} else {
cell.removeAttribute('data-acount');
cell.setAttribute('data-acount', '0');
}
if ( hnDetails.blockCount !== 0 ) {
cell.setAttribute('data-bcount', Math.min(Math.ceil(Math.log(hnDetails.blockCount + 1) / Math.LN10), 3));
} else {
cell.removeAttribute('data-bcount');
cell.setAttribute('data-bcount', '0');
}
if ( hnDetails.domain !== des ) {
@ -260,12 +260,12 @@ const updateFirewallCell = function(scope, des, type, rule) {
if ( hnDetails.totalAllowCount !== 0 ) {
cell.setAttribute('data-acount', Math.min(Math.ceil(Math.log(hnDetails.totalAllowCount + 1) / Math.LN10), 3));
} else {
cell.removeAttribute('data-acount');
cell.setAttribute('data-acount', '0');
}
if ( hnDetails.totalBlockCount !== 0 ) {
cell.setAttribute('data-bcount', Math.min(Math.ceil(Math.log(hnDetails.totalBlockCount + 1) / Math.LN10), 3));
} else {
cell.removeAttribute('data-bcount');
cell.setAttribute('data-bcount', '0');
}
};
@ -302,9 +302,9 @@ const buildAllFirewallRows = function() {
dfHotspots.detach();
// Update incrementally: reuse existing rows if possible.
let rowContainer = document.getElementById('firewallContainer');
let toAppend = document.createDocumentFragment();
let rowTemplate = document.querySelector('#templates > div:nth-of-type(1)');
const rowContainer = document.getElementById('firewallContainer');
const toAppend = document.createDocumentFragment();
const rowTemplate = document.querySelector('#templates > div:nth-of-type(1)');
let row = rowContainer.querySelector('div:nth-of-type(7) + div');
for ( const des of allHostnameRows ) {
@ -331,12 +331,14 @@ const buildAllFirewallRows = function() {
span.title = isDomain && isPunycoded ? des : '';
const classList = row.classList;
classList.toggle('isRootContext', des === popupData.pageHostname);
classList.toggle('isDomain', isDomain);
classList.toggle('isSubDomain', !isDomain);
classList.toggle('allowed', hnDetails.allowCount !== 0);
classList.toggle('blocked', hnDetails.blockCount !== 0);
classList.toggle('totalAllowed', hnDetails.totalAllowCount !== 0);
classList.toggle('totalBlocked', hnDetails.totalBlockCount !== 0);
classList.toggle('expandException', expandExceptions.has(hnDetails.domain));
row = row.nextElementSibling;
}
@ -445,7 +447,7 @@ const renderPopup = function() {
popupData.pageURL === '' || popupData.netFilteringSwitch !== true
);
let canElementPicker = popupData.canElementPicker === true &&
const canElementPicker = popupData.canElementPicker === true &&
popupData.netFilteringSwitch === true;
uDom.nodeFromId('gotoPick').classList.toggle('enabled', canElementPicker);
uDom.nodeFromId('gotoZap').classList.toggle('enabled', canElementPicker);
@ -510,16 +512,13 @@ const renderPopup = function() {
dfPaneVisible === true
);
elem = uDom.nodeFromId('firewallContainer');
elem.classList.toggle(
'minimized',
popupData.firewallPaneMinimized === true
);
elem.classList.toggle(
uDom.nodeFromId('firewallContainer').classList.toggle(
'colorBlind',
popupData.colorBlindFriendly === true
);
setGlobalExpand(popupData.firewallPaneMinimized === false, true);
// Build dynamic filtering pane only if in use
if ( dfPaneVisible ) {
buildAllFirewallRows();
@ -923,7 +922,66 @@ document.addEventListener(
/******************************************************************************/
const toggleMinimize = function(ev) {
const expandExceptions = new Set();
(( ) => {
try {
const exceptions = JSON.parse(
vAPI.localStorage.getItem('popupExpandExceptions')
);
if ( Array.isArray(exceptions) === false ) { return; }
for ( const exception of exceptions ) {
expandExceptions.add(exception);
}
}
catch(ex) {
}
})();
const saveExpandExceptions = function() {
vAPI.localStorage.setItem(
'popupExpandExceptions',
JSON.stringify(Array.from(expandExceptions))
);
};
const setGlobalExpand = function(state, internal = false) {
uDom('.expandException').removeClass('expandException');
if ( state ) {
uDom('#firewallContainer').addClass('expanded');
} else {
uDom('#firewallContainer').removeClass('expanded');
}
positionRulesetTools();
if ( internal ) { return; }
popupData.firewallPaneMinimized = !state;
expandExceptions.clear();
saveExpandExceptions();
messaging.send('popupPanel', {
what: 'userSettings',
name: 'firewallPaneMinimized',
value: popupData.firewallPaneMinimized,
});
};
const setSpecificExpand = function(domain, state, internal = false) {
const unodes = uDom(`[data-des="${domain}"],[data-des$=".${domain}"]`);
if ( state ) {
unodes.addClass('expandException');
} else {
unodes.removeClass('expandException');
}
if ( internal ) { return; }
if ( state ) {
expandExceptions.add(domain);
} else {
expandExceptions.delete(domain);
}
saveExpandExceptions();
};
uDom('[data-i18n="popupAnyRulePrompt"]').on('click', ev => {
// Special display mode: in its own tab/window, with no vertical restraint.
// Useful to take snapshots of the whole list of domains -- example:
// https://github.com/gorhill/uBlock/issues/736#issuecomment-178879944
@ -931,25 +989,31 @@ const toggleMinimize = function(ev) {
messaging.send('popupPanel', {
what: 'gotoURL',
details: {
url: 'popup.html?tabId=' + popupData.tabId + '&responsive=1',
url: `popup.html?tabId=${popupData.tabId}&responsive=1`,
select: true,
index: -1
index: -1,
},
});
vAPI.closePopup();
return;
}
popupData.firewallPaneMinimized =
uDom.nodeFromId('firewallContainer').classList.toggle('minimized');
setGlobalExpand(
uDom('#firewallContainer').hasClass('expanded') === false
);
});
messaging.send('popupPanel', {
what: 'userSettings',
name: 'firewallPaneMinimized',
value: popupData.firewallPaneMinimized,
});
positionRulesetTools();
};
uDom('#firewallContainer').on(
'click', '.isDomain[data-type="*"] > span:first-of-type',
ev => {
const div = ev.target.closest('[data-des]');
if ( div === null ) { return; }
setSpecificExpand(
div.getAttribute('data-des'),
div.classList.contains('expandException') === false
);
}
);
/******************************************************************************/
@ -1137,7 +1201,6 @@ uDom('h2').on('click', toggleFirewallPane);
uDom('.hnSwitch').on('click', ev => { toggleHostnameSwitch(ev); });
uDom('#saveRules').on('click', saveFirewallRules);
uDom('#revertRules').on('click', ( ) => { revertFirewallRules(); });
uDom('[data-i18n="popupAnyRulePrompt"]').on('click', toggleMinimize);
uDom('body').on('mouseenter', '[data-tip]', onShowTooltip)
.on('mouseleave', '[data-tip]', onHideTooltip);

View File

@ -42,7 +42,7 @@
<span id="no-scripting" class="hnSwitch fa-icon fa-icon-badged" role="button" aria-label tabindex="0">code<svg class="nope" viewBox="0 0 20 20"><path d="M1,1 19,19M1,19 19,1" /></svg></span>
</div>
</div><!-- DO NOT REMOVE --><div class="tooltipContainer">
<div id="firewallContainer" class="minimized">
<div id="firewallContainer">
<div data-des="*" data-type="*"><span data-i18n="popupAnyRulePrompt"></span><span data-src="/" data-i18n-tip="popupTipGlobalRules" data-tip-position="under"> </span><span data-src="." data-i18n-tip="popupTipLocalRules" data-tip-position="under"> </span></div>
<div data-des="*" data-type="image"><span data-i18n="popupImageRulePrompt"></span><span data-src="/"> </span><span data-src="."> </span></div>
<div data-des="*" data-type="3p"><span data-i18n="popup3pAnyRulePrompt"></span><span data-src="/"> </span><span data-src="."> </span></div>