this fixes #5

This commit is contained in:
gorhill 2014-08-02 11:40:27 -04:00
parent cc69d0c2d4
commit bee017034a
12 changed files with 223 additions and 153 deletions

View file

@ -612,10 +612,7 @@ FilterContainer.prototype.addFilterEntry = function(filterDict, hash, f) {
/******************************************************************************/ /******************************************************************************/
FilterContainer.prototype.retrieveGenericSelectors = function(tabHostname, request) { FilterContainer.prototype.retrieveGenericSelectors = function(request) {
if ( !tabHostname || µb.getCosmeticFilteringSwitch(tabHostname) !== true ) {
return;
}
if ( µb.userSettings.parseAllABPHideFilters !== true ) { if ( µb.userSettings.parseAllABPHideFilters !== true ) {
return; return;
} }
@ -670,10 +667,7 @@ FilterContainer.prototype.retrieveGenericSelectors = function(tabHostname, reque
/******************************************************************************/ /******************************************************************************/
FilterContainer.prototype.retrieveDomainSelectors = function(tabHostname, request) { FilterContainer.prototype.retrieveDomainSelectors = function(request) {
if ( !tabHostname || µb.getCosmeticFilteringSwitch(tabHostname) !== true ) {
return;
}
if ( µb.userSettings.parseAllABPHideFilters !== true ) { if ( µb.userSettings.parseAllABPHideFilters !== true ) {
return; return;
} }

View file

@ -36,7 +36,8 @@ return {
logBlockedRequests: false, logBlockedRequests: false,
logAllowedRequests: false, logAllowedRequests: false,
parseAllABPHideFilters: true, parseAllABPHideFilters: true,
netExceptionList: {}, netExceptionList: {}, // TODO: remove once all users are up to date
netWhitelist: '',
showIconBadge: true showIconBadge: true
}, },
localSettings: { localSettings: {
@ -70,6 +71,8 @@ return {
remoteBlacklists: { remoteBlacklists: {
}, },
netWhitelist: {},
netWhitelistModifyTime: 0,
pageStores: {}, pageStores: {},
storageQuota: chrome.storage.local.QUOTA_BYTES, storageQuota: chrome.storage.local.QUOTA_BYTES,

View file

@ -420,6 +420,7 @@ var messaging = (function(name){
}); });
})(); })();
/******************************************************************************/
/******************************************************************************/ /******************************************************************************/
// https://github.com/gorhill/uBlock/issues/7 // https://github.com/gorhill/uBlock/issues/7
@ -459,13 +460,19 @@ var messaging = (function(name){
// - Elements which resource URL changes // - Elements which resource URL changes
var onResourceLoaded = function(ev) { var onResourceLoaded = function(ev) {
var target = ev.target; var target = ev.target;
if ( !target || !target.src ) { if ( !target || !target.src ) { return; }
return; if ( target.tagName.toLowerCase() !== 'iframe' ) { return; }
} var onAnswerReceived = function(details) {
var tag = target.tagName.toLowerCase(); if ( details.blocked ) {
if ( tag !== 'img' && tag !== 'iframe' ) { hideOne(target, details.collapse);
return; }
} };
messaging.ask({ what: 'blockedRequest', url: target.src }, onAnswerReceived);
};
var onResourceFailed = function(ev) {
var target = ev.target;
if ( !target || !target.src ) { return; }
if ( target.tagName.toLowerCase() !== 'img' ) { return; }
var onAnswerReceived = function(details) { var onAnswerReceived = function(details) {
if ( details.blocked ) { if ( details.blocked ) {
hideOne(target, details.collapse); hideOne(target, details.collapse);
@ -474,7 +481,7 @@ var messaging = (function(name){
messaging.ask({ what: 'blockedRequest', url: target.src }, onAnswerReceived); messaging.ask({ what: 'blockedRequest', url: target.src }, onAnswerReceived);
}; };
document.addEventListener('load', onResourceLoaded, true); document.addEventListener('load', onResourceLoaded, true);
document.addEventListener('error', onResourceLoaded, true); document.addEventListener('error', onResourceFailed, true);
})(); })();
/******************************************************************************/ /******************************************************************************/

View file

@ -19,7 +19,7 @@
Home: https://github.com/gorhill/uBlock Home: https://github.com/gorhill/uBlock
*/ */
/* global chrome, µBlock */ /* global chrome, µBlock, YaMD5 */
/******************************************************************************/ /******************************************************************************/
@ -49,7 +49,7 @@ var getStats = function(request) {
r.pageHostname = pageStore.pageHostname; r.pageHostname = pageStore.pageHostname;
r.pageBlockedRequestCount = pageStore.perLoadBlockedRequestCount; r.pageBlockedRequestCount = pageStore.perLoadBlockedRequestCount;
r.pageAllowedRequestCount = pageStore.perLoadAllowedRequestCount; r.pageAllowedRequestCount = pageStore.perLoadAllowedRequestCount;
r.netFilteringSwitch = µb.getNetFilteringSwitch(pageStore.pageHostname); r.netFilteringSwitch = pageStore.getNetFilteringSwitch();
} }
return r; return r;
}; };
@ -73,7 +73,8 @@ var onMessage = function(request, sender, callback) {
case 'toggleNetFiltering': case 'toggleNetFiltering':
µBlock.toggleNetFilteringSwitch( µBlock.toggleNetFilteringSwitch(
request.hostname, request.url,
request.scope,
request.state request.state
); );
µBlock.updateBadgeAsync(request.tabId); µBlock.updateBadgeAsync(request.tabId);
@ -100,6 +101,8 @@ var onMessage = function(request, sender, callback) {
(function() { (function() {
var µb = µBlock;
var onMessage = function(request, sender, callback) { var onMessage = function(request, sender, callback) {
// Async // Async
switch ( request.what ) { switch ( request.what ) {
@ -112,23 +115,24 @@ var onMessage = function(request, sender, callback) {
var pageStore; var pageStore;
if ( sender && sender.tab ) { if ( sender && sender.tab ) {
pageStore = µBlock.pageStoreFromTabId(sender.tab.id); pageStore = µb.pageStoreFromTabId(sender.tab.id);
} }
var tabHostname = pageStore ? pageStore.pageHostname : '';
switch ( request.what ) { switch ( request.what ) {
case 'retrieveDomainCosmeticSelectors': case 'retrieveDomainCosmeticSelectors':
response = µBlock.abpHideFilters.retrieveDomainSelectors(tabHostname, request); if ( pageStore && pageStore.getNetFilteringSwitch() ) {
response = µb.abpHideFilters.retrieveDomainSelectors(request);
}
break; break;
default: default:
return µBlock.messaging.defaultHandler(request, sender, callback); return µb.messaging.defaultHandler(request, sender, callback);
} }
callback(response); callback(response);
}; };
µBlock.messaging.listen('contentscript-start.js', onMessage); µb.messaging.listen('contentscript-start.js', onMessage);
})(); })();
@ -138,6 +142,8 @@ var onMessage = function(request, sender, callback) {
(function() { (function() {
var µb = µBlock;
var onMessage = function(request, sender, callback) { var onMessage = function(request, sender, callback) {
// Async // Async
switch ( request.what ) { switch ( request.what ) {
@ -150,18 +156,19 @@ var onMessage = function(request, sender, callback) {
var pageStore; var pageStore;
if ( sender && sender.tab ) { if ( sender && sender.tab ) {
pageStore = µBlock.pageStoreFromTabId(sender.tab.id); pageStore = µb.pageStoreFromTabId(sender.tab.id);
} }
var tabHostname = pageStore ? pageStore.pageHostname : '';
switch ( request.what ) { switch ( request.what ) {
case 'retrieveGenericCosmeticSelectors': case 'retrieveGenericCosmeticSelectors':
response = µBlock.abpHideFilters.retrieveGenericSelectors(tabHostname, request); if ( pageStore && pageStore.getNetFilteringSwitch() ) {
response = µb.abpHideFilters.retrieveGenericSelectors(request);
}
break; break;
case 'blockedRequests': case 'blockedRequests':
response = { response = {
collapse: µBlock.userSettings.collapseBlocked, collapse: µb.userSettings.collapseBlocked,
blockedRequests: pageStore ? pageStore.blockedRequests : {} blockedRequests: pageStore ? pageStore.blockedRequests : {}
}; };
break; break;
@ -169,19 +176,19 @@ var onMessage = function(request, sender, callback) {
// Check a single request // Check a single request
case 'blockedRequest': case 'blockedRequest':
response = { response = {
collapse: µBlock.userSettings.collapseBlocked, collapse: µb.userSettings.collapseBlocked,
blocked: pageStore && pageStore.blockedRequests[request.url] blocked: pageStore && pageStore.blockedRequests[request.url]
}; };
break; break;
default: default:
return µBlock.messaging.defaultHandler(request, sender, callback); return µb.messaging.defaultHandler(request, sender, callback);
} }
callback(response); callback(response);
}; };
µBlock.messaging.listen('contentscript-end.js', onMessage); µb.messaging.listen('contentscript-end.js', onMessage);
})(); })();
@ -352,11 +359,11 @@ var onMessage = function(request, sender, callback) {
switch ( request.what ) { switch ( request.what ) {
case 'getWhitelist': case 'getWhitelist':
response = µb.userSettings.netExceptionList; response = µb.stringFromWhitelist(µb.netWhitelist);
break; break;
case 'setWhitelist': case 'setWhitelist':
µb.userSettings.netExceptionList = request.whitelist; µb.netWhitelist = µb.whitelistFromString(request.whitelist);
µb.saveWhitelist(); µb.saveWhitelist();
break; break;

View file

@ -111,6 +111,8 @@ PageStore.prototype.init = function(tabId, pageURL) {
this.pageHostname = µb.URI.hostnameFromURI(pageURL); this.pageHostname = µb.URI.hostnameFromURI(pageURL);
this.pageDomain = µb.URI.domainFromHostname(this.pageHostname); this.pageDomain = µb.URI.domainFromHostname(this.pageHostname);
this.frames = disposeFrameStores(this.frames); this.frames = disposeFrameStores(this.frames);
this.netFiltering = true;
this.netFilteringReadTime = 0;
this.perLoadBlockedRequestCount = 0; this.perLoadBlockedRequestCount = 0;
this.perLoadAllowedRequestCount = 0; this.perLoadAllowedRequestCount = 0;
this.blockedRequests = {}; this.blockedRequests = {};
@ -122,16 +124,9 @@ PageStore.prototype.init = function(tabId, pageURL) {
/******************************************************************************/ /******************************************************************************/
PageStore.prototype.reuse = function(pageURL) { PageStore.prototype.reuse = function(pageURL) {
this.previousPageURL = this.pageURL; var previousPageURL = this.pageURL;
this.pageURL = pageURL; this.init(this.tabId, pageURL);
this.pageHostname = µb.URI.hostnameFromURI(pageURL); this.previousPageURL = previousPageURL;
this.pageDomain = µb.URI.domainFromHostname(this.pageHostname);
this.frames = disposeFrameStores(this.frames);
this.perLoadBlockedRequestCount = 0;
this.perLoadAllowedRequestCount = 0;
this.blockedRequests = {};
this.allowedRequests = {};
this.disposeTime = 0;
return this; return this;
}; };
@ -169,6 +164,16 @@ PageStore.prototype.getFrame = function(frameId) {
/******************************************************************************/ /******************************************************************************/
PageStore.prototype.getNetFilteringSwitch = function() {
if ( this.netFilteringReadTime < µb.netWhitelistModifyTime ) {
this.netFiltering = µb.getNetFilteringSwitch(this.pageURL, this.pageDomain);
this.netFilteringReadTime = Date.now();
}
return this.netFiltering;
};
/******************************************************************************/
PageStore.prototype.recordRequest = function(type, url, reason) { PageStore.prototype.recordRequest = function(type, url, reason) {
var blocked = reason !== false && reason.slice(0, 2) !== '@@'; var blocked = reason !== false && reason.slice(0, 2) !== '@@';
@ -212,13 +217,13 @@ PageStore.prototype.updateBadge = function() {
// https://github.com/gorhill/uBlock/issues/19 // https://github.com/gorhill/uBlock/issues/19
// TODO: need to check with µb object to see whether tab still exists. // TODO: need to check with µb object to see whether tab still exists.
var netFilteringSwitch = µb.getNetFilteringSwitch(this.pageHostname); var netFiltering = this.getNetFilteringSwitch();
var iconPath = netFilteringSwitch ? 'img/browsericons/icon19.png' : 'img/browsericons/icon19-off.png'; var iconPath = netFiltering ? 'img/browsericons/icon19.png' : 'img/browsericons/icon19-off.png';
chrome.browserAction.setIcon({ tabId: this.tabId, path: iconPath }); chrome.browserAction.setIcon({ tabId: this.tabId, path: iconPath });
var iconStr = ''; var iconStr = '';
if ( µb.userSettings.showIconBadge && netFilteringSwitch && this.perLoadBlockedRequestCount ) { if ( µb.userSettings.showIconBadge && netFiltering && this.perLoadBlockedRequestCount ) {
iconStr = this.perLoadBlockedRequestCount.toLocaleString(); iconStr = this.perLoadBlockedRequestCount.toLocaleString();
} }
chrome.browserAction.setBadgeText({ chrome.browserAction.setBadgeText({

View file

@ -134,14 +134,15 @@ chrome.tabs.query({ active: true, currentWindow: true }, onTabsReceived);
/******************************************************************************/ /******************************************************************************/
var handleNetFilteringSwitch = function() { var toggleNetFilteringSwitch = function(ev) {
if ( !stats || !stats.pageURL ) { if ( !stats || !stats.pageURL ) {
return; return;
} }
var off = uDom(this).toggleClass('off').hasClassName('off'); var off = uDom(this).toggleClass('off').hasClassName('off');
messaging.tell({ messaging.tell({
what: 'toggleNetFiltering', what: 'toggleNetFiltering',
hostname: stats.pageHostname, url: stats.pageURL,
scope: ev.ctrlKey || ev.metaKey ? 'page' : '',
state: !off, state: !off,
tabId: stats.tabId tabId: stats.tabId
}); });
@ -186,7 +187,7 @@ var renderHeader = function() {
var installEventHandlers = function() { var installEventHandlers = function() {
uDom('h1,h2,h3,h4').on('click', gotoDashboard); uDom('h1,h2,h3,h4').on('click', gotoDashboard);
uDom('#switch .fa').on('click', handleNetFilteringSwitch); uDom('#switch .fa').on('click', toggleNetFilteringSwitch);
uDom('#gotoLog').on('click', gotoStats); uDom('#gotoLog').on('click', gotoStats);
uDom('#gotoPick').on('click', gotoPick); uDom('#gotoPick').on('click', gotoPick);
}; };

View file

@ -72,7 +72,22 @@
µBlock.loadUserSettings = function() { µBlock.loadUserSettings = function() {
var settingsLoaded = function(store) { var settingsLoaded = function(store) {
µBlock.userSettings = store; var µb = µBlock;
// Backward compatibility after fix to #5
// TODO: remove once all users are up to date with latest version.
if ( store.netExceptionList ) {
if ( store.netWhitelist === '' ) {
store.netWhitelist = Object.keys(store.netExceptionList).join('\n');
if ( store.netWhitelist !== '' ) {
chrome.storage.local.set({ 'netWhitelist': store.netWhitelist });
}
}
delete store.netExceptionList;
chrome.storage.local.remove('netExceptionList');
}
µb.userSettings = store;
µb.netWhitelist = µb.whitelistFromString(store.netWhitelist);
µb.netWhitelistModifyTime = Date.now();
}; };
chrome.storage.local.get(this.userSettings, settingsLoaded); chrome.storage.local.get(this.userSettings, settingsLoaded);
@ -81,10 +96,12 @@
/******************************************************************************/ /******************************************************************************/
µBlock.saveWhitelist = function() { µBlock.saveWhitelist = function() {
var bin = { 'netExceptionList': this.userSettings.netExceptionList }; this.userSettings.netWhitelist = this.stringFromWhitelist(this.netWhitelist);
var bin = { 'netWhitelist': this.userSettings.netWhitelist };
chrome.storage.local.set(bin, function() { chrome.storage.local.set(bin, function() {
µBlock.getBytesInUse(); µBlock.getBytesInUse();
}); });
this.netWhitelistModifyTime = Date.now();
}; };
/******************************************************************************/ /******************************************************************************/

View file

@ -26,13 +26,13 @@
(function(){ (function(){
// When the DOM content of root frame is loaded, this means the tab // When the DOM content of root frame is loaded, this means the tab
// content has changed. // content has changed.
function onDOMContentLoaded(details) { function onNavigationCommitted(details) {
if ( details.frameId !== 0 ) { if ( details.frameId !== 0 ) {
return; return;
} }
µBlock.updateBadgeAsync(details.tabId); µBlock.bindTabToPageStats(details.tabId, details.url);
} }
chrome.webNavigation.onDOMContentLoaded.addListener(onDOMContentLoaded); chrome.webNavigation.onCommitted.addListener(onNavigationCommitted);
// It may happen the URL in the tab changes, while the page's document // It may happen the URL in the tab changes, while the page's document
// stays the same (for instance, Google Maps). Without this listener, // stays the same (for instance, Google Maps). Without this listener,
@ -41,15 +41,10 @@
if ( !tab.url || tab.url === '' ) { if ( !tab.url || tab.url === '' ) {
return; return;
} }
var µb = µBlock; if ( !changeInfo.url ) {
if ( !changeInfo.url || !µb.pageStores[tabId] ) {
return; return;
} }
// If URL is unsupported scheme, unbind tab µBlock.bindTabToPageStats(tabId, changeInfo.url);
if ( changeInfo.url && changeInfo.url.slice(0, 4) !== 'http' ) {
µb.unbindTabFromPageStats(tabId);
}
µb.updateBadgeAsync(tabId);
} }
chrome.tabs.onUpdated.addListener(onTabUpdated); chrome.tabs.onUpdated.addListener(onTabUpdated);
@ -95,7 +90,7 @@
// Create an entry for the tab if it doesn't exist. // Create an entry for the tab if it doesn't exist.
µBlock.bindTabToPageStats = function(tabId, pageURL) { µBlock.bindTabToPageStats = function(tabId, pageURL, context) {
this.updateBadgeAsync(tabId); this.updateBadgeAsync(tabId);
// https://github.com/gorhill/httpswitchboard/issues/303 // https://github.com/gorhill/httpswitchboard/issues/303
@ -108,18 +103,17 @@
return null; return null;
} }
//console.debug('µBlock> bindTabToPageStats(%d, "%s")', tabId, pageURL);
// Reuse page store if one exists: this allows to guess if a tab is // Reuse page store if one exists: this allows to guess if a tab is
// a popup. // a popup.
var pageStore = this.pageStores[tabId]; var pageStore = this.pageStores[tabId];
if ( pageStore ) {
pageStore.reuse(pageURL);
} else {
pageStore = this.PageStore.factory(tabId, pageURL);
}
this.pageStores[tabId] = pageStore; if ( pageStore ) {
if ( pageURL !== pageStore.pageURL || context === 'beforeRequest' ) {
pageStore.reuse(pageURL);
}
} else {
pageStore = this.pageStores[tabId] = this.PageStore.factory(tabId, pageURL);
}
return pageStore; return pageStore;
}; };

View file

@ -46,7 +46,7 @@ var onBeforeRequest = function(details) {
// Special handling for root document. // Special handling for root document.
if ( requestType === 'main_frame' && details.parentFrameId === -1 ) { if ( requestType === 'main_frame' && details.parentFrameId === -1 ) {
µb.bindTabToPageStats(tabId, requestURL); µb.bindTabToPageStats(tabId, requestURL, 'beforeRequest');
return; return;
} }
@ -79,7 +79,7 @@ var onBeforeRequest = function(details) {
//} //}
var reason = false; var reason = false;
if ( µb.getNetFilteringSwitch(pageStore.pageHostname) ) { if ( pageStore.getNetFilteringSwitch() ) {
reason = µb.abpFilters.matchString(requestContext, requestURL, requestType, requestHostname); reason = µb.abpFilters.matchString(requestContext, requestURL, requestType, requestHostname);
} }
// Record what happened. // Record what happened.
@ -167,7 +167,7 @@ var onBeforeSendHeaders = function(details) {
// a page store from a URL. Have to keep in mind the same URL can appear // a page store from a URL. Have to keep in mind the same URL can appear
// in multiple tabs. // in multiple tabs.
var reason = false; var reason = false;
if ( µb.getNetFilteringSwitch(pageStore.pageHostname) ) { if ( pageStore.getNetFilteringSwitch() ) {
reason = µb.abpFilters.matchStringExactType( reason = µb.abpFilters.matchStringExactType(
pageDetails, pageDetails,
requestURL, requestURL,

View file

@ -19,18 +19,43 @@
Home: https://github.com/gorhill/uBlock Home: https://github.com/gorhill/uBlock
*/ */
/* global chrome, µBlock */ /* global µBlock */
/******************************************************************************/ /******************************************************************************/
µBlock.getNetFilteringSwitch = function(hostname) { µBlock.getNetFilteringSwitch = function(url, domain) {
var netExceptionList = this.userSettings.netExceptionList; var keyHostname = this.URI.hostnameFromURI(url);
if ( netExceptionList[hostname] !== undefined ) { var pos = url.indexOf('#');
var keyURL = pos !== -1 ? url.slice(0, pos) : url;
// The caller may provide an already known domain -- convenient to reduce
// overhead of extracting a domain from the url
if ( domain === undefined ) {
domain = this.URI.domainFromHostname(keyHostname);
}
if ( !domain ) {
return false; return false;
} }
var hostnames = this.URI.parentHostnamesFromHostname(hostname);
while ( hostname = hostnames.shift() ) { var exceptions = this.netWhitelist[domain];
if ( netExceptionList[hostname] !== undefined ) { if ( !exceptions ) {
return true;
}
var i = exceptions.length;
var exception;
while ( i-- ) {
exception = exceptions[i];
if ( exception.indexOf('/') !== -1 ) {
if ( exception.slice(-1) === '*' ) {
exception = exception.slice(0, -1);
if ( keyURL.slice(0, exception.length) === exception ) {
return false;
}
} else if ( keyURL === exception ) {
return false;
}
} else if ( keyHostname.slice(-exception.length) === exception ) {
return false; return false;
} }
} }
@ -39,58 +64,112 @@
/******************************************************************************/ /******************************************************************************/
µBlock.toggleNetFilteringSwitch = function(hostname, newState) { µBlock.toggleNetFilteringSwitch = function(url, scope, newState) {
var currentState = this.getNetFilteringSwitch(hostname); var keyHostname = this.URI.hostnameFromURI(url);
var pos = url.indexOf('#');
var keyURL = pos !== -1 ? url.slice(0, pos) : url;
var key = scope === 'page' ? keyURL : keyHostname;
// The caller may provide an already known domain -- convenient to reduce
// overhead of extracting a domain from `key`
var domain = this.URI.domainFromHostname(keyHostname);
if ( !domain ) {
return false;
}
var currentState = this.getNetFilteringSwitch(url, domain);
if ( newState === undefined ) { if ( newState === undefined ) {
newState = !currentState; newState = !currentState;
} }
if ( newState === currentState ) { if ( newState === currentState ) {
return currentState; return currentState;
} }
var netExceptionList = this.userSettings.netExceptionList;
var netWhitelist = this.netWhitelist;
var exceptions = netWhitelist[domain];
if ( !exceptions ) {
exceptions = netWhitelist[domain] = [];
}
// Add to exception list // Add to exception list
if ( !newState ) { if ( !newState ) {
netExceptionList[hostname] = true; exceptions.push(key);
this.saveExceptionList(); this.saveWhitelist();
return true; return true;
} }
// Remove from exception list // Remove from exception list
var hostnames = this.URI.allHostnamesFromHostname(hostname); var i = exceptions.length;
while ( hostname = hostnames.shift() ) { var exception;
if ( netExceptionList[hostname] !== undefined ) { while ( i-- ) {
delete netExceptionList[hostname]; exception = exceptions[i];
if ( exception.indexOf('/') !== -1 ) {
if ( exception.slice(-1) === '*' ) {
exception = exception.slice(0, -1);
if ( keyURL.slice(0, exception.length) === exception ) {
exceptions.splice(i, 1);
}
} else if ( keyURL === exception ) {
exceptions.splice(i, 1);
}
} else if ( keyHostname.slice(-exception.length) === exception ) {
exceptions.splice(i, 1);
} }
} }
this.saveExceptionList(); if ( exceptions.length === 0 ) {
return false; delete netWhitelist[domain];
}
this.saveWhitelist();
return true;
}; };
/******************************************************************************/ /******************************************************************************/
// For now we will use the net exception list // For now we will use the net exception list
µBlock.getCosmeticFilteringSwitch = function(hostname) { µBlock.getCosmeticFilteringSwitch = function(url, domain) {
var netExceptionList = this.userSettings.netExceptionList; return this.getNetFilteringSwitch(url, domain);
if ( netExceptionList[hostname] !== undefined ) {
return false;
}
var hostnames = this.URI.parentHostnamesFromHostname(hostname);
while ( hostname = hostnames.shift() ) {
if ( netExceptionList[hostname] !== undefined ) {
return false;
}
}
return true;
}; };
/******************************************************************************/ /******************************************************************************/
µBlock.saveExceptionList = function() { µBlock.stringFromWhitelist = function(exceptions) {
chrome.storage.local.set({ var r = {};
'netExceptionList': this.userSettings.netExceptionList var i, bucket;
}); for ( var domain in exceptions ) {
if ( exceptions.hasOwnProperty(domain) === false ) {
continue;
}
bucket = exceptions[domain];
for ( i = 0; i < bucket.length; i++ ) {
r[bucket[i]] = true;
}
}
return Object.keys(r).sort(function(a,b){return a.localeCompare(b);}).join('\n');
};
/******************************************************************************/
µBlock.whitelistFromString = function(s) {
var exceptions = {};
var lines = s.split(/[\n\r]+/);
var line, domain, bucket;
for ( var i = 0; i < lines.length; i++ ) {
line = lines[i].trim();
domain = line.indexOf('/') !== -1 ?
this.URI.domainFromURI(line) :
this.URI.domainFromHostname(line);
if ( !domain ) {
continue;
}
bucket = exceptions[domain];
if ( bucket === undefined ) {
exceptions[domain] = [line];
} else {
bucket.push(line);
}
}
return exceptions;
}; };
/******************************************************************************/ /******************************************************************************/

View file

@ -34,62 +34,25 @@ messaging.start('whitelist.js');
var cachedWhitelist = ''; var cachedWhitelist = '';
// Could make it more fancy if needed. But speed... It's a compromise. // Could make it more fancy if needed. But speed... It's a compromise.
var reBadHostname = /[\x00-\x08\x0b\x0c\x0e-\x1f\x21-\x2c\x2f\x3a-\x40\x5b-\x60\x7b-\x7e]/; var reUnwantedChars = /[\x00-\x09\x0b\x0c\x0e-\x1f!"#$'()<>{}|\\^\[\]`~]/;
/******************************************************************************/
var validateHostname = function(s) {
var hn = punycode.toASCII(s).toLowerCase();
if ( reBadHostname.test(hn) ) {
return '';
}
return hn;
};
var whitelistFromString = function(s) {
var whitelist = {};
var items = s.split(/\s+/);
var item;
for ( var i = 0; i < items.length; i++ ) {
item = validateHostname(items[i]);
if ( item !== '' ) {
whitelist[item] = true;
}
}
return whitelist;
};
var stringFromWhitelist = function(whitelist) {
var s = [];
var items = Object.keys(whitelist);
for ( var i = 0; i < items.length; i++ ) {
s.push(punycode.toUnicode(items[i]));
}
return s.sort(function(a, b) { return a.localeCompare(b); }).join('\n');
};
/******************************************************************************/
var badWhitelist = function(s) {
return reBadHostname.test(s);
};
/******************************************************************************/ /******************************************************************************/
var whitelistChanged = function() { var whitelistChanged = function() {
var s = uDom('#whitelist').val().trim(); var s = uDom('#whitelist').val().trim();
var bad = reUnwantedChars.test(s);
uDom('#whitelistApply').prop( uDom('#whitelistApply').prop(
'disabled', 'disabled',
s === cachedWhitelist s === cachedWhitelist || bad
); );
uDom('#whitelist').toggleClass('bad', badWhitelist(s)); uDom('#whitelist').toggleClass('bad', bad);
}; };
/******************************************************************************/ /******************************************************************************/
function renderWhitelist() { var renderWhitelist = function() {
var onRead = function(whitelist) { var onRead = function(whitelist) {
cachedWhitelist = stringFromWhitelist(whitelist); cachedWhitelist = whitelist;
uDom('#whitelist').val(cachedWhitelist); uDom('#whitelist').val(cachedWhitelist);
}; };
messaging.ask({ what: 'getWhitelist' }, onRead); messaging.ask({ what: 'getWhitelist' }, onRead);
@ -140,7 +103,7 @@ var whitelistApplyHandler = function() {
cachedWhitelist = uDom('#whitelist').val().trim(); cachedWhitelist = uDom('#whitelist').val().trim();
var request = { var request = {
what: 'setWhitelist', what: 'setWhitelist',
whitelist: whitelistFromString(cachedWhitelist) whitelist: cachedWhitelist
}; };
messaging.tell(request); messaging.tell(request);
whitelistChanged(); whitelistChanged();

View file

@ -2,7 +2,7 @@
"manifest_version": 2, "manifest_version": 2,
"name": "__MSG_extName__", "name": "__MSG_extName__",
"short_name": "µBlock", "short_name": "µBlock",
"version": "0.3.1.3", "version": "0.3.2.0",
"description": "__MSG_extShortDesc__", "description": "__MSG_extShortDesc__",
"icons": { "icons": {
"16": "img/icon_16.png", "16": "img/icon_16.png",