finally a fully working draft: now onto myriad finishing touches

This commit is contained in:
gorhill 2014-12-31 10:47:19 -05:00
parent a953cd5c0c
commit 43e773aab2
6 changed files with 213 additions and 116 deletions

View File

@ -8,13 +8,13 @@ body {
white-space: nowrap;
}
h1,h2,h3,h4 {
margin: 0;
padding: 4px;
background-color: #444;
border: 0;
color: white;
background-color: #444;
text-align: center;
cursor: pointer;
margin: 0;
padding: 4px;
text-align: center;
}
a {
color: inherit;
@ -24,9 +24,9 @@ a {
outline: 0;
}
#version {
margin-left: 1em;
font-weight: normal;
font-size: 11px;
font-weight: normal;
margin-left: 1em;
}
body > div {
background-color: transparent;
@ -47,14 +47,14 @@ body > div:nth-of-type(2) {
}
p {
margin: 16px 0;
white-space: nowrap;
text-align: center;
white-space: nowrap;
}
#switch .fa {
margin: 0;
font-size: 96px;
color: green;
cursor: pointer;
font-size: 96px;
margin: 0;
}
#switch .fa:hover {
opacity: 0.9;
@ -63,22 +63,22 @@ p {
color: #ccc;
}
#switch-hint {
font-size: 11px;
color: #888;
font-size: 11px;
}
[data-i18n="popupBlockedRequestPrompt"] {
font-size: 16px;
}
#page-blocked {
margin-top: 4px;
font-size: 20px;
margin-top: 4px;
}
#total-blocked {
margin-top: 4px;
margin-bottom: 8px;
font-size: 14px;
margin-bottom: 8px;
margin-top: 4px;
}
#stats {
.stats {
margin-bottom: 4px;
text-align: center;
}
@ -142,11 +142,11 @@ body.dynamicFilteringEnabled #dynamicFilteringToggler::before {
margin: 0;
padding: 0;
text-align: right;
width: 7px;
width: 5px;
}
body.dynamicFilteringEnabled #dynamicFilteringContainer {
display: block;
width: 280px;
width: auto;
}
#dynamicFilteringContainer > div {
background-color: transparent;
@ -154,7 +154,7 @@ body.dynamicFilteringEnabled #dynamicFilteringContainer {
direction: ltr;
margin: 0;
padding: 0;
width: 280px;
width: 320px;
}
body.dynamicFilteringEnabled #dynamicFilteringContainer > div {
background-color: #e6e6e6;
@ -176,8 +176,9 @@ body.dynamicFilteringEnabled #dynamicFilteringContainer > div:hover {
color: transparent;
display: inline-block;
height: 24px;
line-height: 28px;
line-height: 24px;
pointer-events: none;
position: relative;
vertical-align: top;
}
body.dynamicFilteringEnabled #dynamicFilteringContainer > div > span {
@ -188,33 +189,74 @@ body.dynamicFilteringEnabled #dynamicFilteringContainer > div > span {
#dynamicFilteringContainer > div > span:nth-of-type(1) {
border-right: 1px solid white;
padding-right: 4px;
width: 75%;
width: 70%;
}
#dynamicFilteringContainer > div > span:nth-of-type(2) {
cursor: pointer;
width: 9%;
width: 15%;
}
#dynamicFilteringContainer > div > span:nth-of-type(3) {
border-left: 1px solid white;
cursor: pointer;
text-align: center;
width: 16%;
width: 15%;
}
#dynamicFilteringContainer > div.isDomain > span:nth-of-type(1) {
font-weight: bold;
}
body.dynamicFilteringEnabled #dynamicFilteringContainer > div > span:nth-of-type(3) {
color: #444;
color: #666;
pointer-events: auto;
}
#dynamicFilteringContainer span.blocked[data-src] {
background-color: #fbb;
#dynamicFilteringContainer span.aRule {
background-color: rgba(0, 160, 0, 0.3);
}
#dynamicFilteringContainer span.ownFilter[data-src] {
background-color: #bbb;
#dynamicFilteringContainer span.bRule {
background-color: rgba(192, 0, 0, 0.3);
}
#dynamicFilteringContainer span.nRule {
background-color: rgba(96, 96, 96, 0.3);
}
#dynamicFilteringContainer span.aRule.ownRule {
background-color: rgba(0, 160, 0, 1);
color: white;
}
#dynamicFilteringContainer span.blocked.ownFilter[data-src] {
background-color: #f66;
#dynamicFilteringContainer span.bRule.ownRule {
background-color: rgba(192, 0, 0, 1);
color: white;
}
}
#dynamicFilteringContainer span.nRule.ownRule {
background-color: rgba(108, 108, 108, 1);
color: white;
}
#actionSelector {
bottom: 0;
left: 0;
position: absolute;
right: 0;
top: 0;
}
#actionSelector > span {
display: inline-block;
height: 24px;
opacity: 0.2;
width: 33.33%;
}
#actionSelector > span:hover {
opacity: 0.75;
}
#actionSelector > span:nth-of-type(1) {
background-color: rgb(0, 160, 0);
}
#actionSelector > span:nth-of-type(2) {
background-color: rgb(108, 108, 108);
}
#actionSelector > span:nth-of-type(3) {
background-color: rgb(192, 0, 0);
}
#dynamicFilteringContainer span.aRule #actionSelector > span:nth-of-type(1),
#dynamicFilteringContainer span.nRule #actionSelector > span:nth-of-type(2),
#dynamicFilteringContainer span.bRule #actionSelector > span:nth-of-type(3) {
visibility: hidden;
}

View File

@ -130,52 +130,43 @@ Matrix.prototype.setCell = function(srcHostname, desHostname, type, state) {
/******************************************************************************/
Matrix.prototype.blockCell = function(srcHostname, desHostname, type) {
Matrix.prototype.unsetCell = function(srcHostname, desHostname, type) {
this.evaluateCellZY(srcHostname, desHostname, type);
if ( this.r === 1 ) {
if ( this.r === 0 ) {
return false;
}
this.setCell(srcHostname, desHostname, type, 0);
return true;
};
/******************************************************************************/
Matrix.prototype.setCellZ = function(srcHostname, desHostname, type, action) {
this.evaluateCellZY(srcHostname, desHostname, type);
if ( this.r === action ) {
return false;
}
this.setCell(srcHostname, desHostname, type, 0);
this.evaluateCellZY(srcHostname, desHostname, type);
if ( this.r === 1 ) {
if ( this.r === action ) {
return true;
}
this.setCell(srcHostname, desHostname, type, 1);
this.setCell(srcHostname, desHostname, type, action);
return true;
};
/******************************************************************************/
Matrix.prototype.blockCell = function(srcHostname, desHostname, type) {
return this.setCellZ(srcHostname, desHostname, type, 1);
};
// https://www.youtube.com/watch?v=Csewb_eIStY
/******************************************************************************/
Matrix.prototype.allowCell = function(srcHostname, desHostname, type) {
this.evaluateCellZY(srcHostname, desHostname, type);
if ( this.r === 2 ) {
return false;
}
this.setCell(srcHostname, desHostname, type, 0);
this.evaluateCellZY(srcHostname, desHostname, type);
if ( this.r === 2 ) {
return true;
}
this.setCell(srcHostname, desHostname, type, 2);
return true;
};
/******************************************************************************/
Matrix.prototype.unsetCell = function(srcHostname, desHostname, type) {
this.evaluateCellZY(srcHostname, desHostname, type);
if ( this.r === 0 ) {
return false;
}
this.setCell(srcHostname, desHostname, type, 0);
this.evaluateCellZY(srcHostname, desHostname, type);
if ( this.r === 0 || this.r === 3 ) {
return true;
}
this.setCell(srcHostname, desHostname, type, 3);
return true;
return this.setCellZ(srcHostname, desHostname, type, 2);
};
/******************************************************************************/

View File

@ -440,6 +440,9 @@ PageStore.prototype.filterRequest = function(context) {
//console.debug('cache MISS: PageStore.filterRequest("%s")', requestURL);
this.recordResult(context.requestType, requestURL, result);
// TODO: send this to a dev-panel tool
//console.debug('[%s, %s] = "%s"', context.requestHostname, context.requestType, result);
var requestHostname = context.requestHostname;
if ( this.hostnameToCountMap.hasOwnProperty(requestHostname) === false ) {
this.hostnameToCountMap[requestHostname] = 0;

View File

@ -46,8 +46,9 @@ var scopeToSrcHostnameMap = {
'.': ''
};
var threePlus = '+++';
var threeMinus = '\u2012\u2012\u2012';
var threeMinus = '';
var sixSpace = '\u2007\u2007\u2007\u2007\u2007\u2007';
var dynaHotspots = null;
/******************************************************************************/
@ -102,6 +103,7 @@ var addDynamicFilterRow = function(des) {
row.toggleClass('isDomain', isDomain);
if ( hnDetails.allowCount !== 0 ) {
touchedDomains[hnDetails.domain] = true;
row.addClass('wasTouched');
}
row.appendTo('#dynamicFilteringContainer');
@ -120,7 +122,7 @@ var addDynamicFilterRow = function(des) {
/******************************************************************************/
var syncDynamicFilter = function(scope, des, type, result) {
var syncDynamicFilterCell = function(scope, des, type, result) {
var selector = '#dynamicFilteringContainer span[data-src="' + scope + '"][data-des="' + des + '"][data-type="' + type + '"]';
var cell = uDom(selector);
@ -129,17 +131,20 @@ var syncDynamicFilter = function(scope, des, type, result) {
cell = addDynamicFilterRow(des).descendants(selector);
}
var blocked = result.charAt(1) === 'b';
cell.toggleClass('blocked', blocked);
cell.removeClass();
var action = result.charAt(1);
if ( action !== '' ) {
cell.toggleClass(action + 'Rule', true);
}
// Use dark shade visual cue if the filter is specific to the cell.
var ownFilter = false;
var ownRule = false;
var matches = reSrcHostnameFromResult.exec(result);
if ( matches !== null ) {
ownFilter = matches[2] === des &&
ownRule = matches[2] === des &&
matches[1] === scopeToSrcHostnameMap[scope];
}
cell.toggleClass('ownFilter', ownFilter);
cell.toggleClass('ownRule', ownRule);
if ( scope !== '.' || type !== '*' ) {
return;
@ -150,29 +155,30 @@ var syncDynamicFilter = function(scope, des, type, result) {
var hnDetails = stats.hostnameDict[des];
var aCount = Math.min(Math.ceil(Math.log10(hnDetails.allowCount + 1)), 3);
var bCount = Math.min(Math.ceil(Math.log10(hnDetails.blockCount + 1)), 3);
cell.text(
threePlus.slice(0, aCount) +
sixSpace.slice(aCount + bCount) +
threeMinus.slice(0, bCount)
);
// IMPORTANT: It is completely assumed the first node is a TEXT_NODE, so
// ensure this in the HTML file counterpart when you make
// changes
cell.nodeAt(0).firstChild.nodeValue = threePlus.slice(0, aCount) +
sixSpace.slice(aCount + bCount) +
threeMinus.slice(0, bCount);
};
/******************************************************************************/
var syncAllDynamicFilters = function() {
var hasBlock = false;
var hasRule = false;
var rules = stats.dynamicFilterRules;
var type, result;
var types = dynaTypes;
var i = types.length;
while ( i-- ) {
type = types[i];
syncDynamicFilter('/', '*', type, rules['/ * ' + type] || '');
syncDynamicFilterCell('/', '*', type, rules['/ * ' + type] || '');
result = rules['. * ' + type] || '';
if ( result.charAt(1) === 'b' ) {
hasBlock = true;
if ( result.charAt(1) !== '' ) {
hasRule = true;
}
syncDynamicFilter('.', '*', type, result);
syncDynamicFilterCell('.', '*', type, result);
}
// Sort hostnames. First-party hostnames must always appear at the top
@ -185,10 +191,9 @@ var syncAllDynamicFilters = function() {
if ( key.slice(-1) !== '*' ) {
continue;
}
syncDynamicFilter(key.charAt(0), key.slice(2, key.indexOf(' ', 2)), '*', rules[key]);
syncDynamicFilterCell(key.charAt(0), key.slice(2, key.indexOf(' ', 2)), '*', rules[key]);
}
uDom('body').toggleClass('hasDynamicBlock', hasBlock);
uDom('#privacyInfo > b').text(Object.keys(touchedDomains).length);
};
@ -333,30 +338,6 @@ var gotoLink = function(ev) {
/******************************************************************************/
var onDynamicFilterClicked = function(ev) {
// This can happen on pages where uBlock does not work
if ( typeof stats.pageHostname !== 'string' || stats.pageHostname === '' ) {
return;
}
var cell = uDom(ev.target);
var scope = cell.attr('data-src') === '/' ? '*' : stats.pageHostname;
var onDynamicFilterChanged = function(details) {
cachePopupData(details);
syncAllDynamicFilters();
};
messager.send({
what: 'toggleDynamicFilter',
tabId: stats.tabId,
pageHostname: stats.pageHostname,
srcHostname: scope,
desHostname: cell.attr('data-des'),
requestType: cell.attr('data-type'),
block: cell.hasClass('blocked') === false
}, onDynamicFilterChanged);
};
/******************************************************************************/
var toggleDynamicFiltering = function(ev) {
var el = uDom('body');
el.toggleClass('dynamicFilteringEnabled');
@ -369,6 +350,79 @@ var toggleDynamicFiltering = function(ev) {
/******************************************************************************/
var mouseenterCellHandler = function() {
if ( uDom(this).hasClass('ownRule') === false ) {
dynaHotspots.appendTo(this);
}
};
var mouseleaveCellHandler = function() {
dynaHotspots.detach();
};
/******************************************************************************/
var setDynamicFilter = function(src, des, type, action) {
// This can happen on pages where uBlock does not work
if ( typeof stats.pageHostname !== 'string' || stats.pageHostname === '' ) {
return;
}
var onDynamicFilterChanged = function(details) {
cachePopupData(details);
syncAllDynamicFilters();
};
messager.send({
what: 'toggleDynamicFilter',
tabId: stats.tabId,
pageHostname: stats.pageHostname,
srcHostname: src,
desHostname: des,
requestType: type,
action: action
}, onDynamicFilterChanged);
};
/******************************************************************************/
var unsetDynamicFilterHandler = function() {
var cell = uDom(this);
setDynamicFilter(
cell.attr('data-src') === '/' ? '*' : stats.pageHostname,
cell.attr('data-des'),
cell.attr('data-type'),
0
);
dynaHotspots.appendTo(cell);
};
/******************************************************************************/
var setDynamicFilterHandler = function() {
var hotspot = uDom(this);
var cell = hotspot.ancestors('[data-src]');
if ( cell.length === 0 ) {
return;
}
var action = 0;
var hotspotId = hotspot.attr('id');
if ( hotspotId === 'dynaAllow' ) {
action = 2;
} else if ( hotspotId === 'dynaNoop' ) {
action = 3
} else {
action = 1;
}
setDynamicFilter(
cell.attr('data-src') === '/' ? '*' : stats.pageHostname,
cell.attr('data-des'),
cell.attr('data-type'),
action
);
dynaHotspots.detach();
};
/******************************************************************************/
var installEventHandlers = function() {
uDom('h1,h2,h3,h4').on('click', gotoDashboard);
uDom('#switch .fa').on('click', toggleNetFilteringSwitch);
@ -376,7 +430,13 @@ var installEventHandlers = function() {
uDom('#gotoPick').on('click', gotoPick);
uDom('a[href^=http]').on('click', gotoLink);
uDom('#dynamicFilteringToggler').on('click', toggleDynamicFiltering);
uDom('#dynamicFilteringContainer').on('click', 'span[data-type]', onDynamicFilterClicked);
uDom('#dynamicFilteringContainer').on('click', 'span[data-src]', unsetDynamicFilterHandler);
uDom('#dynamicFilteringContainer')
.on('mouseenter', '[data-src]', mouseenterCellHandler)
.on('mouseleave', '[data-src]', mouseleaveCellHandler);
dynaHotspots = uDom('#actionSelector');
dynaHotspots.on('click', 'span', setDynamicFilterHandler).detach();
};
/******************************************************************************/

View File

@ -308,8 +308,8 @@ var matchWhitelistDirective = function(url, hostname, directive) {
µBlock.toggleDynamicFilter = function(details) {
var changed = false;
if ( details.block ) {
changed = this.dynamicNetFilteringEngine.blockCell(details.srcHostname, details.desHostname, details.requestType);
if ( details.action !== 0 ) {
changed = this.dynamicNetFilteringEngine.setCellZ(details.srcHostname, details.desHostname, details.requestType, details.action);
} else {
changed = this.dynamicNetFilteringEngine.unsetCell(details.srcHostname, details.desHostname, details.requestType);
}

View File

@ -12,30 +12,31 @@
<h4 title="popupTipDashboard">v<span id="version"></span></h4>
<div>
<div id="dynamicFilteringContainer">
<div><span>images</span><span data-src="/" data-des="*" data-type="image"></span><span data-src="." data-des="*" data-type="image"></span></div>
<div><span>inline scripts</span><span data-src="/" data-des="*" data-type="inline-script"></span><span data-src="." data-des="*" data-type="inline-script"></span></div>
<div><span>1st-party scripts</span><span data-src="/" data-des="*" data-type="1p-script"></span><span data-src="." data-des="*" data-type="1p-script"></span></div>
<div><span>3rd-party scripts</span><span data-src="/" data-des="*" data-type="3p-script"></span><span data-src="." data-des="*" data-type="3p-script"></span></div>
<div><span>3rd-party frames</span><span data-src="/" data-des="*" data-type="3p-frame"></span><span data-src="." data-des="*" data-type="3p-frame"></span></div>
<div><span>images</span><span data-src="/" data-des="*" data-type="image"> </span><span data-src="." data-des="*" data-type="image"></span></div>
<div><span>inline scripts</span><span data-src="/" data-des="*" data-type="inline-script"> </span><span data-src="." data-des="*" data-type="inline-script"> </span></div>
<div><span>1st-party scripts</span><span data-src="/" data-des="*" data-type="1p-script"> </span><span data-src="." data-des="*" data-type="1p-script"> </span></div>
<div><span>3rd-party scripts</span><span data-src="/" data-des="*" data-type="3p-script"> </span><span data-src="." data-des="*" data-type="3p-script"> </span></div>
<div><span>3rd-party frames</span><span data-src="/" data-des="*" data-type="3p-frame"> </span><span data-src="." data-des="*" data-type="3p-frame"> </span></div>
<div id="privacyInfo"><b>?</b> distinct domains touched</div>
</div>
</div><!-- DO NOT REMOVE --><div>
</div><!-- DO NOT REMOVE --><div>
<p id="switch" data-i18n-tip="popupPowerSwitchInfo"><span class="fa">&#xf011;</span></p>
<p id="switch-hint"></p>
<p id="dynamicFilteringToggler" data-i18n="popupBlockedRequestPrompt"></p>
<p id="stats">
<p class="stats">
<span data-i18n="popupBlockedOnThisPagePrompt"></span>&ensp;
<span id="gotoPick" class="fa tool" data-i18n-tip="popupTipPicker" data-tip-anchor="top">&#xf1fb;</span>&ensp;
<span id="gotoLog" class="fa tool" data-i18n-tip="popupTipLog" data-tip-anchor="top">&#xf06e;</span>
</p>
<p id="page-blocked">?</p>
<p id="stats" data-i18n="popupBlockedSinceInstallPrompt"></p>
<p class="stats" data-i18n="popupBlockedSinceInstallPrompt"></p>
<p id="total-blocked">?</p>
</div>
<div id="templates" style="display: none">
<div><span></span><span data-src="/" data-des="" data-type="*"></span><span data-src="." data-des="" data-type="*"></span></div>
<div>
<div><span></span><span data-src="/" data-des="" data-type="*"> </span><span data-src="." data-des="" data-type="*"> </span></div>
<div id='actionSelector'><span id="dynaAllow"></span><span id="dynaNoop"></span><span id="dynaBlock"></span></div>
</div>
<script src="js/vapi-common.js"></script>
<script src="js/vapi-client.js"></script>