mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-06 19:02:30 +01:00
dynamic filtering
This commit is contained in:
parent
4227123393
commit
9bcad432cf
110
css/popup.css
110
css/popup.css
@ -5,7 +5,7 @@ body {
|
||||
font: 13px sans-serif;
|
||||
background-color: white;
|
||||
direction: __MSG_@@bidi_dir__;
|
||||
min-width: 160px;
|
||||
min-width: 180px;
|
||||
}
|
||||
h1,h2,h3,h4 {
|
||||
margin: 0;
|
||||
@ -58,6 +58,7 @@ p {
|
||||
}
|
||||
#total-blocked {
|
||||
margin-top: 4px;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
#stats {
|
||||
@ -76,3 +77,110 @@ p {
|
||||
.tool:hover {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
#dynamicFilteringToggler {
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
width: 100vw;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
#dynamicFilteringToggler::after {
|
||||
content: '\f107';
|
||||
}
|
||||
#dynamicFilteringToggler.on::after {
|
||||
content: '\f106';
|
||||
}
|
||||
#dynamicFilteringContainer {
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
display: none;
|
||||
}
|
||||
#dynamicFilteringToggler.on + #dynamicFilteringContainer {
|
||||
display: initial;
|
||||
}
|
||||
.dynamicFiltering {
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
height: 2.75em;
|
||||
position: relative;
|
||||
}
|
||||
.dynamicFiltering.local {
|
||||
border-bottom: 1px solid white;
|
||||
}
|
||||
.dynamicFiltering.global {
|
||||
height: 1.25em;
|
||||
}
|
||||
.dynamicFiltering > div {
|
||||
margin: 0;
|
||||
border: 1px solid #eee;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
background-color: #eee;
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
}
|
||||
.dynamicFiltering > div:not(:first-child) {
|
||||
border-left: 1px solid white !important;
|
||||
}
|
||||
.dynamicFiltering > div:nth-of-type(1) {
|
||||
left: 0;
|
||||
width: 7vw;
|
||||
height: 100%;
|
||||
}
|
||||
.dynamicFiltering > div:nth-of-type(2) {
|
||||
left: 7vw;
|
||||
width: 18vw;
|
||||
height: 100%;
|
||||
}
|
||||
.dynamicFiltering > div:nth-of-type(3) {
|
||||
left: 25vw;
|
||||
width: 25vw;
|
||||
height: 100%;
|
||||
}
|
||||
.dynamicFiltering > div:nth-of-type(4) {
|
||||
left: 50vw;
|
||||
width: 25vw;
|
||||
height: 100%;
|
||||
}
|
||||
.dynamicFiltering > div:nth-of-type(5) {
|
||||
left: 75vw;
|
||||
width: 25vw;
|
||||
height: 100%;
|
||||
}
|
||||
.dynamicFiltering > div:nth-of-type(6) {
|
||||
left: 0;
|
||||
width: 50vw;
|
||||
}
|
||||
.dynamicFiltering > div:nth-of-type(7) {
|
||||
left: 50vw;
|
||||
width: 50vw;
|
||||
}
|
||||
.dynamicFiltering > div.label {
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
pointer-events: none;
|
||||
color: black;
|
||||
opacity: 0.2;
|
||||
font: 12px monospace;
|
||||
text-align: center;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background-color: transparent;
|
||||
}
|
||||
.dynamicFiltering > div.blocked {
|
||||
border-color: #fdd;
|
||||
background-color: #fdd;
|
||||
}
|
||||
.dynamicFiltering > div.ownFilter {
|
||||
border-color: #bbb;
|
||||
background-color: #bbb;
|
||||
}
|
||||
.dynamicFiltering > div.blocked.ownFilter {
|
||||
border-color: #eaa;
|
||||
background-color: #eaa;
|
||||
}
|
||||
|
@ -55,6 +55,8 @@ return {
|
||||
autoUpdate: true,
|
||||
collapseBlocked: true,
|
||||
contextMenuEnabled: true,
|
||||
dynamicFilteringSelfie: '',
|
||||
dynamicFilteringEnabled: false,
|
||||
experimentalEnabled: false,
|
||||
externalLists: defaultExternalLists,
|
||||
logRequests: false,
|
||||
|
@ -34,6 +34,18 @@ var µb = µBlock;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var getDynamicFilterResults = function(scope) {
|
||||
return [
|
||||
µb.netFilteringEngine.matchDynamicFilters(scope, 'inline-script', true),
|
||||
µb.netFilteringEngine.matchDynamicFilters(scope, 'script', true),
|
||||
µb.netFilteringEngine.matchDynamicFilters(scope, 'script', false),
|
||||
µb.netFilteringEngine.matchDynamicFilters(scope, 'sub_frame', true),
|
||||
µb.netFilteringEngine.matchDynamicFilters(scope, 'sub_frame', false)
|
||||
];
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var getStats = function(request) {
|
||||
var r = {
|
||||
globalBlockedRequestCount: µb.localSettings.blockedRequestCount,
|
||||
@ -44,7 +56,11 @@ var getStats = function(request) {
|
||||
pageAllowedRequestCount: 0,
|
||||
netFilteringSwitch: false,
|
||||
cosmeticFilteringSwitch: false,
|
||||
logRequests: µb.userSettings.logRequests
|
||||
logRequests: µb.userSettings.logRequests,
|
||||
dynamicFilteringEnabled: µb.userSettings.dynamicFilteringEnabled,
|
||||
dynamicFilterResults: {
|
||||
'/': getDynamicFilterResults('*')
|
||||
}
|
||||
};
|
||||
var pageStore = µb.pageStoreFromTabId(request.tabId);
|
||||
if ( pageStore ) {
|
||||
@ -53,6 +69,7 @@ var getStats = function(request) {
|
||||
r.pageBlockedRequestCount = pageStore.perLoadBlockedRequestCount;
|
||||
r.pageAllowedRequestCount = pageStore.perLoadAllowedRequestCount;
|
||||
r.netFilteringSwitch = pageStore.getNetFilteringSwitch();
|
||||
r.dynamicFilterResults['.'] = getDynamicFilterResults(r.pageHostname);
|
||||
}
|
||||
return r;
|
||||
};
|
||||
@ -70,6 +87,13 @@ var onMessage = function(request, sender, callback) {
|
||||
var response;
|
||||
|
||||
switch ( request.what ) {
|
||||
case 'gotoPick':
|
||||
// Picker launched from popup: clear context menu args
|
||||
µb.contextMenuClientX = -1;
|
||||
µb.contextMenuClientY = -1;
|
||||
µb.elementPickerExec(request.tabId);
|
||||
break;
|
||||
|
||||
case 'stats':
|
||||
response = getStats(request);
|
||||
break;
|
||||
@ -83,11 +107,12 @@ var onMessage = function(request, sender, callback) {
|
||||
µb.updateBadgeAsync(request.tabId);
|
||||
break;
|
||||
|
||||
case 'gotoPick':
|
||||
// Picker launched from popup: clear context menu args
|
||||
µb.contextMenuClientX = -1;
|
||||
µb.contextMenuClientY = -1;
|
||||
µb.elementPickerExec(request.tabId);
|
||||
case 'toggleDynamicFilter':
|
||||
µb.toggleDynamicFilter(request);
|
||||
response = { '/': getDynamicFilterResults('*') };
|
||||
if ( request.pageHostname ) {
|
||||
response['.'] = getDynamicFilterResults(request.pageHostname);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -66,18 +66,14 @@ var typeNameToTypeValue = {
|
||||
};
|
||||
|
||||
const BlockAnyTypeAnyParty = BlockAction | AnyType | AnyParty;
|
||||
const BlockAnyType1stParty = BlockAction | AnyType | FirstParty;
|
||||
const BlockAnyType3rdParty = BlockAction | AnyType | ThirdParty;
|
||||
const BlockAnyType = BlockAction | AnyType;
|
||||
const BlockAnyParty = BlockAction | AnyParty;
|
||||
|
||||
const AllowAnyTypeAnyParty = AllowAction | AnyType | AnyParty;
|
||||
const AllowAnyType1stParty = AllowAction | AnyType | FirstParty;
|
||||
const AllowAnyType3rdParty = AllowAction | AnyType | ThirdParty;
|
||||
const AllowAnyType = AllowAction | AnyType;
|
||||
const AllowAnyParty = AllowAction | AnyParty;
|
||||
|
||||
var pageHostname = '';
|
||||
var pageHostname = ''; // short-lived register
|
||||
|
||||
var reIgnoreEmpty = /^\s+$/;
|
||||
var reIgnoreComment = /^\[|^!/;
|
||||
@ -842,7 +838,7 @@ FilterManyWildcardsHostname.fromSelfie = function(s) {
|
||||
var FilterBucket = function(a, b) {
|
||||
this.promoted = 0;
|
||||
this.vip = 16;
|
||||
this.f = null;
|
||||
this.f = null; // short-lived register
|
||||
this.filters = [];
|
||||
if ( a !== undefined ) {
|
||||
this.filters[0] = a;
|
||||
@ -1107,7 +1103,7 @@ FilterParser.prototype.parseOptType = function(raw, not) {
|
||||
// `popup` is a special type, it cannot be set for filters intended
|
||||
// for real net request types. The test is safe since there is no
|
||||
// such thing as a filter using `~popup`.
|
||||
if ( typeNameToTypeValue[k] > typeNameToTypeValue['other'] ) {
|
||||
if ( typeNameToTypeValue[k] > typeNameToTypeValue.other ) {
|
||||
continue;
|
||||
}
|
||||
this.types.push(typeNameToTypeValue[k]);
|
||||
@ -1296,6 +1292,7 @@ FilterContainer.prototype.reset = function() {
|
||||
this.duplicates = Object.create(null);
|
||||
this.blockedAnyPartyHostnames.reset();
|
||||
this.blocked3rdPartyHostnames.reset();
|
||||
this.dynamicFilters = {};
|
||||
this.filterParser.reset();
|
||||
};
|
||||
|
||||
@ -1633,6 +1630,190 @@ FilterContainer.prototype.addToCategory = function(category, tokenKey, filter) {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Dynamic filters
|
||||
|
||||
// Bits:
|
||||
// 0: inline script blocked
|
||||
// 1: inline script allowed
|
||||
// 2: first-party script blocked
|
||||
// 3: first-party script allowed
|
||||
// 4: third-party script blocked
|
||||
// 5: third-party script allowed
|
||||
// 6: first-party frame blocked
|
||||
// 7: first-party frame allowed
|
||||
// 8: third-party frame blocked
|
||||
// 9: third-party frame allowed
|
||||
//
|
||||
// I chose separate bits for blocked/unblocked as I want to have an "undefined"
|
||||
// state, which will be used to inherit from wider-scoped filters.
|
||||
//
|
||||
// undefined: 0x00
|
||||
// blocked: 0x01
|
||||
// allowed: 0x02
|
||||
// unused: 0x03
|
||||
|
||||
FilterContainer.prototype.dynamicFilterBitOffsets = {};
|
||||
FilterContainer.prototype.dynamicFilterBitOffsets[FirstParty | typeNameToTypeValue['inline-script']] = 0;
|
||||
FilterContainer.prototype.dynamicFilterBitOffsets[FirstParty | typeNameToTypeValue.script] = 2;
|
||||
FilterContainer.prototype.dynamicFilterBitOffsets[ThirdParty | typeNameToTypeValue.script] = 4;
|
||||
FilterContainer.prototype.dynamicFilterBitOffsets[FirstParty | typeNameToTypeValue.sub_frame] = 6;
|
||||
FilterContainer.prototype.dynamicFilterBitOffsets[ThirdParty | typeNameToTypeValue.sub_frame] = 8;
|
||||
FilterContainer.prototype.dynamicFiltersMagicId = 'numrebvoacir';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
FilterContainer.prototype.dynamicFilterSet = function(hostname, requestType, firstParty, value) {
|
||||
if ( typeNameToTypeValue.hasOwnProperty(requestType) === false ) {
|
||||
return false;
|
||||
}
|
||||
var party = firstParty ? FirstParty : ThirdParty;
|
||||
var categoryKey = party | typeNameToTypeValue[requestType];
|
||||
if ( this.dynamicFilterBitOffsets.hasOwnProperty(categoryKey) === false ) {
|
||||
return false;
|
||||
}
|
||||
var bitOffset = this.dynamicFilterBitOffsets[categoryKey];
|
||||
var oldFilter = this.dynamicFilters[hostname] || 0;
|
||||
var newFilter = (oldFilter & ~(0x0003 << bitOffset)) | (value << bitOffset);
|
||||
if ( newFilter === oldFilter ) {
|
||||
return false;
|
||||
}
|
||||
if ( newFilter === 0 ) {
|
||||
delete this.dynamicFilters[hostname];
|
||||
} else {
|
||||
this.dynamicFilters[hostname] = newFilter;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
FilterContainer.prototype.dynamicFilterBlock = function(hostname, requestType, firstParty) {
|
||||
if ( typeof hostname !== 'string' || hostname === '' ) {
|
||||
return false;
|
||||
}
|
||||
var result = this.matchDynamicFilters(hostname, requestType, firstParty);
|
||||
if ( result !== '' && result.slice(0, 2) !== '@@' ) {
|
||||
return false;
|
||||
}
|
||||
this.dynamicFilterSet(hostname, requestType, firstParty, 0x00);
|
||||
result = this.matchDynamicFilters(hostname, requestType, firstParty);
|
||||
if ( result !== '' && result.slice(0, 2) !== '@@' ) {
|
||||
return true;
|
||||
}
|
||||
this.dynamicFilterSet(hostname, requestType, firstParty, 0x01);
|
||||
return true;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
FilterContainer.prototype.dynamicFilterUnblock = function(hostname, requestType, firstParty) {
|
||||
if ( typeof hostname !== 'string' || hostname === '' ) {
|
||||
return false;
|
||||
}
|
||||
var result = this.matchDynamicFilters(hostname, requestType, firstParty);
|
||||
if ( result === '' || result.slice(0, 2) === '@@' ) {
|
||||
return false;
|
||||
}
|
||||
this.dynamicFilterSet(hostname, requestType, firstParty, 0x00);
|
||||
result = this.matchDynamicFilters(hostname, requestType, firstParty);
|
||||
if ( result === '' || result.slice(0, 2) === '@@' ) {
|
||||
return true;
|
||||
}
|
||||
this.dynamicFilterSet(hostname, requestType, firstParty, 0x02);
|
||||
return true;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
FilterContainer.prototype.dynamicFilterStateToType = {
|
||||
0x0001: '',
|
||||
0x0002: '@@',
|
||||
0x0004: '',
|
||||
0x0008: '@@',
|
||||
0x0010: '',
|
||||
0x0020: '@@',
|
||||
0x0040: '',
|
||||
0x0080: '@@',
|
||||
0x0100: '',
|
||||
0x0200: '@@'
|
||||
};
|
||||
|
||||
FilterContainer.prototype.dynamicFilterStateToOption = {
|
||||
0x0001: '$inline-script,important',
|
||||
0x0002: '$inline-script',
|
||||
0x0004: '$~third-party,script,important',
|
||||
0x0008: '$~third-party,script',
|
||||
0x0010: '$third-party,script,important',
|
||||
0x0020: '$third-party,script',
|
||||
0x0040: '$~third-party,subdocument,important',
|
||||
0x0080: '$~third-party,subdocument',
|
||||
0x0100: '$third-party,subdocument,important',
|
||||
0x0200: '$third-party,subdocument'
|
||||
};
|
||||
|
||||
FilterContainer.prototype.matchDynamicFilters = function(hostname, requestType, firstParty) {
|
||||
var party = firstParty ? FirstParty : ThirdParty;
|
||||
if ( typeNameToTypeValue.hasOwnProperty(requestType) === false ) {
|
||||
return '';
|
||||
}
|
||||
var categoryKey = party | typeNameToTypeValue[requestType];
|
||||
if ( this.dynamicFilterBitOffsets.hasOwnProperty(categoryKey) === false ) {
|
||||
return '';
|
||||
}
|
||||
var bitOffset = this.dynamicFilterBitOffsets[categoryKey];
|
||||
var bitMask = 0x0003 << bitOffset;
|
||||
var bitState, pos;
|
||||
for ( ;; ) {
|
||||
if ( this.dynamicFilters.hasOwnProperty(hostname) !== false ) {
|
||||
bitState = this.dynamicFilters[hostname] & bitMask;
|
||||
if ( bitState !== 0 ) {
|
||||
if ( hostname !== '*' ) {
|
||||
hostname = '||' + hostname + '^';
|
||||
}
|
||||
return this.dynamicFilterStateToType[bitState] +
|
||||
hostname +
|
||||
this.dynamicFilterStateToOption[bitState];
|
||||
}
|
||||
}
|
||||
pos = hostname.indexOf('.');
|
||||
if ( pos === -1 ) {
|
||||
if ( hostname === '*' ) {
|
||||
return '';
|
||||
}
|
||||
hostname = '*';
|
||||
} else {
|
||||
hostname = hostname.slice(pos + 1);
|
||||
}
|
||||
}
|
||||
// unreachable
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
||||
FilterContainer.prototype.selfieFromDynamicFilters = function() {
|
||||
var bin = {
|
||||
magicId: this.dynamicFiltersMagicId,
|
||||
filters: this.dynamicFilters
|
||||
};
|
||||
return JSON.stringify(bin);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
FilterContainer.prototype.dynamicFiltersFromSelfie = function(selfie) {
|
||||
if ( selfie === '' ) {
|
||||
return;
|
||||
}
|
||||
var bin = JSON.parse(selfie);
|
||||
if ( bin.magicId !== this.dynamicFiltersMagicId ) {
|
||||
return;
|
||||
}
|
||||
this.dynamicFilters = bin.filters;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Since the addition of the `important` evaluation, this means it is now
|
||||
// likely that the url will have to be scanned more than once. So this is
|
||||
// to ensure we do it once only, and reuse results.
|
||||
@ -1766,6 +1947,14 @@ FilterContainer.prototype.matchStringExactType = function(pageDetails, requestUR
|
||||
var party = requestHostname.slice(-pageDomain.length) === pageDomain ?
|
||||
FirstParty :
|
||||
ThirdParty;
|
||||
|
||||
// Evaluate dynamic filters first. "Block" dynamic filters are always
|
||||
// "important", they override everything else.
|
||||
var bf = this.matchDynamicFilters(requestHostname, requestType, party === FirstParty);
|
||||
if ( bf !== '' && bf.slice(0, 2) !== '@@' ) {
|
||||
return bf;
|
||||
}
|
||||
|
||||
var type = typeNameToTypeValue[requestType];
|
||||
var categories = this.categories;
|
||||
var buckets = this.buckets;
|
||||
@ -1783,7 +1972,7 @@ FilterContainer.prototype.matchStringExactType = function(pageDetails, requestUR
|
||||
// Test against important block filters
|
||||
buckets[2] = categories[this.makeCategoryKey(BlockAnyParty | Important | type)];
|
||||
buckets[3] = categories[this.makeCategoryKey(BlockAction | Important | type | party)];
|
||||
var bf = this.matchTokens(url);
|
||||
bf = this.matchTokens(url);
|
||||
if ( bf !== false ) {
|
||||
return bf.toString();
|
||||
}
|
||||
@ -1851,6 +2040,13 @@ FilterContainer.prototype.matchString = function(pageDetails, requestURL, reques
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate dynamic filters first. "Block" dynamic filters are always
|
||||
// "important", they override everything else.
|
||||
var bf = this.matchDynamicFilters(requestHostname, requestType, party === FirstParty);
|
||||
if ( bf !== '' && bf.slice(0, 2) !== '@@' ) {
|
||||
return bf;
|
||||
}
|
||||
|
||||
// This will be used by hostname-based filters
|
||||
pageHostname = pageDetails.pageHostname || '';
|
||||
|
||||
@ -1870,7 +2066,7 @@ FilterContainer.prototype.matchString = function(pageDetails, requestURL, reques
|
||||
buckets[1] = categories[this.makeCategoryKey(BlockAnyType | Important | party)];
|
||||
buckets[2] = categories[this.makeCategoryKey(BlockAnyParty | Important | type)];
|
||||
buckets[3] = categories[this.makeCategoryKey(BlockAction | Important | type | party)];
|
||||
var bf = this.matchTokens(url);
|
||||
bf = this.matchTokens(url);
|
||||
if ( bf !== false ) {
|
||||
return bf.toString() + '$important';
|
||||
}
|
||||
|
@ -425,6 +425,14 @@ PageStore.prototype.setRequestFlags = function(requestURL, targetBits, valueBits
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
PageStore.prototype.recordResult = function(requestType, requestURL, result) {
|
||||
if ( collapsibleRequestTypes.indexOf(requestType) !== -1 || µb.userSettings.logRequests ) {
|
||||
this.netFilteringCache.add(requestURL, result, requestType, 0);
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// false: not blocked
|
||||
// true: blocked
|
||||
|
||||
|
74
js/popup.js
74
js/popup.js
@ -29,6 +29,7 @@
|
||||
/******************************************************************************/
|
||||
|
||||
var stats;
|
||||
var reResultParser = /^(@@)?(\*|\|\|([^$^]+)\^)\$(.+)$/;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
@ -47,6 +48,34 @@ var formatNumber = function(count) {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var syncDynamicFilter = function(scope, i, result) {
|
||||
var el = uDom('[data-scope="' + scope + '"] > div:nth-of-type(' + i + ')');
|
||||
var matches = reResultParser.exec(result) || [];
|
||||
var blocked = matches.length !== 0 && matches[1] !== '@@';
|
||||
el.toggleClass('blocked', blocked);
|
||||
var ownFilter = matches[3] !== undefined && matches[3] === stats.pageHostname;
|
||||
el.toggleClass('ownFilter', ownFilter);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var syncAllDynamicFilters = function() {
|
||||
var scopes = ['.', '/'];
|
||||
var scope, results, i;
|
||||
while ( scope = scopes.pop() ) {
|
||||
if ( stats.dynamicFilterResults.hasOwnProperty(scope) === false ) {
|
||||
continue;
|
||||
}
|
||||
results = stats.dynamicFilterResults[scope];
|
||||
i = 5;
|
||||
while ( i-- ) {
|
||||
syncDynamicFilter(scope, i + 1, results[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var renderStats = function() {
|
||||
if ( !stats ) {
|
||||
return;
|
||||
@ -102,12 +131,12 @@ var renderStats = function() {
|
||||
'%</span>'
|
||||
);
|
||||
}
|
||||
uDom('#total-blocked').html(html.join(''));
|
||||
|
||||
uDom('#switch .fa').toggleClass(
|
||||
'off',
|
||||
stats.pageURL === '' || !stats.netFilteringSwitch
|
||||
);
|
||||
syncAllDynamicFilters();
|
||||
|
||||
uDom('#total-blocked').html(html.join(''));
|
||||
uDom('#switch .fa').toggleClass('off', stats.pageURL === '' || !stats.netFilteringSwitch);
|
||||
uDom('#dynamicFilteringToggler').toggleClass('on', stats.dynamicFilteringEnabled);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
@ -185,11 +214,46 @@ var renderHeader = function() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var onDynamicFilterClicked = function(ev) {
|
||||
var elScope = uDom(ev.currentTarget);
|
||||
var scope = elScope.attr('data-scope') === '/' ? '*' : stats.pageHostname;
|
||||
var elFilter = uDom(ev.target);
|
||||
var onDynamicFilterChanged = function(details) {
|
||||
stats.dynamicFilterResults = details;
|
||||
syncAllDynamicFilters();
|
||||
};
|
||||
messaging.ask({
|
||||
what: 'toggleDynamicFilter',
|
||||
hostname: scope,
|
||||
requestType: elFilter.attr('data-type'),
|
||||
firstParty: elFilter.attr('data-first-party') !== null,
|
||||
block: elFilter.hasClassName('blocked') === false,
|
||||
pageHostname: stats.pageHostname
|
||||
}, onDynamicFilterChanged);
|
||||
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var toggleDynamicFiltering = function() {
|
||||
var el = uDom('#dynamicFilteringToggler');
|
||||
el.toggleClass('on');
|
||||
messaging.tell({
|
||||
what: 'userSettings',
|
||||
name: 'dynamicFilteringEnabled',
|
||||
value: el.hasClassName('on')
|
||||
});
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var installEventHandlers = function() {
|
||||
uDom('h1,h2,h3,h4').on('click', gotoDashboard);
|
||||
uDom('#switch .fa').on('click', toggleNetFilteringSwitch);
|
||||
uDom('#gotoLog').on('click', gotoStats);
|
||||
uDom('#gotoPick').on('click', gotoPick);
|
||||
uDom('#dynamicFilteringToggler').on('click', toggleDynamicFiltering);
|
||||
uDom('.dynamicFiltering').on('click', 'div', onDynamicFilterClicked);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -661,13 +661,14 @@
|
||||
µb.loadWhitelist(onWhitelistReady);
|
||||
return;
|
||||
}
|
||||
µb.assets.autoUpdate = µb.userSettings.autoUpdate;
|
||||
µb.loadPublicSuffixList(onPSLReady);
|
||||
};
|
||||
|
||||
// User settings are in memory
|
||||
var onUserSettingsReady = function(settings) {
|
||||
µb.assets.autoUpdate = settings.autoUpdate;
|
||||
µb.contextMenu.toggle(settings.contextMenuEnabled);
|
||||
µb.netFilteringEngine.dynamicFiltersFromSelfie(settings.dynamicFilteringSelfie);
|
||||
µb.fromSelfie(onSelfieReady);
|
||||
µb.mirrors.toggle(settings.experimentalEnabled);
|
||||
};
|
||||
|
@ -320,6 +320,11 @@ var onHeadersReceived = function(details) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Record request
|
||||
if ( result !== '' ) {
|
||||
pageStore.recordResult('script', details.url, result);
|
||||
}
|
||||
|
||||
// Blocked
|
||||
pageStore.perLoadBlockedRequestCount++;
|
||||
µb.localSettings.blockedRequestCount++;
|
||||
@ -327,7 +332,7 @@ var onHeadersReceived = function(details) {
|
||||
|
||||
details.responseHeaders.push({
|
||||
'name': 'Content-Security-Policy',
|
||||
'value': "script-src *"
|
||||
'value': "script-src 'unsafe-eval' *"
|
||||
});
|
||||
|
||||
return { 'responseHeaders': details.responseHeaders };
|
||||
|
15
js/ublock.js
15
js/ublock.js
@ -238,7 +238,7 @@
|
||||
return type;
|
||||
}
|
||||
var ext = path.slice(pos) + '.';
|
||||
if ( '.eot.ttf.otf.svg.woff.woff2.'.indexOf(ext) !== -1 ) {
|
||||
if ( '.css.eot.ttf.otf.svg.woff.woff2.'.indexOf(ext) !== -1 ) {
|
||||
return 'stylesheet';
|
||||
}
|
||||
if ( '.ico.png.gif.jpg.jpeg.'.indexOf(ext) !== -1 ) {
|
||||
@ -255,3 +255,16 @@
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.toggleDynamicFilter = function(details) {
|
||||
var changed = false;
|
||||
if ( details.block ) {
|
||||
changed = this.netFilteringEngine.dynamicFilterBlock(details.hostname, details.requestType, details.firstParty);
|
||||
} else {
|
||||
changed = this.netFilteringEngine.dynamicFilterUnblock(details.hostname, details.requestType, details.firstParty);
|
||||
}
|
||||
if ( changed ) {
|
||||
this.userSettings.dynamicFilteringSelfie = this.netFilteringEngine.selfieFromDynamicFilters();
|
||||
this.XAL.keyValSetOne('dynamicFilteringSelfie', this.userSettings.dynamicFilteringSelfie);
|
||||
}
|
||||
};
|
||||
|
@ -59,6 +59,14 @@ exports.injectScript = function(id, details) {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
exports.keyValSetOne = function(key, val) {
|
||||
var bin = {};
|
||||
bin[key] = val;
|
||||
chrome.storage.local.set(bin);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
return exports;
|
||||
|
||||
/******************************************************************************/
|
||||
|
22
popup.html
22
popup.html
@ -24,6 +24,28 @@
|
||||
<p id="total-blocked">?</p>
|
||||
</div>
|
||||
|
||||
<div id="dynamicFilteringToggler" class="fa on"></div>
|
||||
|
||||
<div id="dynamicFilteringContainer">
|
||||
<div class="dynamicFiltering local" data-scope=".">
|
||||
<div data-first-party data-type="inline-script"></div>
|
||||
<div data-first-party data-type="script"></div>
|
||||
<div data-type="script"></div>
|
||||
<div data-first-party data-type="sub_frame"></div>
|
||||
<div data-type="sub_frame"></div>
|
||||
<div class="label"><script></div>
|
||||
<div class="label"><iframe></div>
|
||||
</div>
|
||||
<div class="dynamicFiltering global" data-scope="/">
|
||||
<div data-first-party data-type="inline-script"></div>
|
||||
<div data-first-party data-type="script"></div>
|
||||
<div data-type="script"></div>
|
||||
<div data-first-party data-type="sub_frame"></div>
|
||||
<div data-type="sub_frame"></div>
|
||||
<div class="label"><script></div>
|
||||
<div class="label"><iframe></div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="js/udom.js"></script>
|
||||
<script src="js/i18n.js"></script>
|
||||
<script src="js/messaging-client.js"></script>
|
||||
|
Loading…
Reference in New Issue
Block a user