mirror of https://github.com/gorhill/uBlock.git
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:
parent
2da8948928
commit
56cc2b1256
|
@ -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 */
|
||||
|
|
|
@ -217,7 +217,7 @@ const getHostnameDict = function(hostnameToCountMap) {
|
|||
blockCount: blockCount,
|
||||
allowCount: allowCount,
|
||||
totalBlockCount: 0,
|
||||
totalAllowCount: 0
|
||||
totalAllowCount: 0,
|
||||
};
|
||||
}
|
||||
return r;
|
||||
|
|
117
src/js/popup.js
117
src/js/popup.js
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue