1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-10-06 09:37:12 +02:00

this fixes #6

This commit is contained in:
gorhill 2014-07-25 16:12:20 -04:00
parent a71b9b4712
commit fe372e9a11
13 changed files with 374 additions and 176 deletions

View File

@ -12,16 +12,23 @@ div > p:first-child {
div > p:last-child { div > p:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
body > ul {
margin: 0.5em 0 0 0;
padding-left: 1em;
}
ul { ul {
padding: 0; padding: 0;
list-style-type: none; list-style-type: none;
} }
ul > li { ul > li {
margin: 0.5em 0 3px 0; margin: 0.5em 0 0 0;
padding: 0; padding: 0;
font-size: 15px; font-size: 15px;
list-style-type: none; list-style-type: none;
} }
ul > li > ul {
margin: 0.25em 0 0 0;
}
ul > li > ul > li { ul > li > ul > li {
font-size: 14px; font-size: 14px;
margin: 0 0 0 1em; margin: 0 0 0 1em;
@ -35,12 +42,18 @@ ul > li > ul > li {
height: 16em; height: 16em;
white-space: nowrap; white-space: nowrap;
} }
#externalLists {
font-size: smaller;
width: 48em;
height: 8em;
white-space: nowrap;
}
</style> </style>
</head> </head>
<body> <body>
<ul id="options" style="margin:0.5em 0 0 0;padding-left:1em;list-style-type:none"> <ul id="options">
<li><button id="blacklistsApply" disabled="true" data-i18n="3pApplyChanges"></button> <li><button id="blacklistsApply" disabled="true" data-i18n="3pApplyChanges"></button>
<li style="margin-top:0.75em"><input type="checkbox" id="parseAllABPHideFilters"><label data-i18n="3pParseAllABPHideFiltersPrompt1"></label> <li style="margin-top:0.75em"><input type="checkbox" id="parseAllABPHideFilters"><label data-i18n="3pParseAllABPHideFiltersPrompt1"></label>
<span class="dim" id="3pParseAllABPHideFiltersPrompt2"></span> <span class="dim" id="3pParseAllABPHideFiltersPrompt2"></span>
@ -48,9 +61,15 @@ ul > li > ul > li {
<div class="whatisthis-expandable para" data-i18n="3pParseAllABPHideFiltersInfo"></div> <div class="whatisthis-expandable para" data-i18n="3pParseAllABPHideFiltersInfo"></div>
<li style="margin-top:0.75em"><p id="listsOfBlockedHostsPrompt"></p> <li style="margin-top:0.75em"><p id="listsOfBlockedHostsPrompt"></p>
</ul> </ul>
<ul id="lists" style="margin:0.5em 0 0 0;padding-left:1em;list-style-type:none"> <ul id="lists">
</ul> </ul>
<div style="margin: 2em 0 0 2em">
<p data-i18n="3pExternalListsHint" style="margin: 0 0 0.25em 0; font-size: 13px;"></p>
<textarea id="externalLists"></textarea>
<p style="margin: 0.25em 0 0 0"><button id="externalListsApply" disabled="true" data-i18n="3pExternalListsApply"></button></p>
</div>
<script src="js/udom.js"></script> <script src="js/udom.js"></script>
<script src="js/i18n.js"></script> <script src="js/i18n.js"></script>
<script src="js/dashboard-common.js"></script> <script src="js/dashboard-common.js"></script>

View File

@ -131,6 +131,18 @@
"message":"Regions, languages", "message":"Regions, languages",
"description":"English: Regions, languages" "description":"English: Regions, languages"
}, },
"3pGroupCustom":{
"message":"Custom",
"description":"English: Custom"
},
"3pExternalListsHint":{
"message":"One URL per line. Lines prefixed with &lsquo;!&rsquo; will be ignored. Invalid URLs will be silently ignored.",
"description":"English: One URL per line. Lines prefixed with &lsquo;!&rsquo; will be ignored. Invalid URLs will be silently ignored."
},
"3pExternalListsApply":{
"message":"Apply",
"description":"English: Apply"
},
"1pFormatHint":{ "1pFormatHint":{
"message":"One filter per line. A filter can be a plain hostname, or an Adblock Plus-compatible filter. Lines prefixed with &lsquo;!&rsquo; will be ignored.", "message":"One filter per line. A filter can be a plain hostname, or an Adblock Plus-compatible filter. Lines prefixed with &lsquo;!&rsquo; will be ignored.",
"description":"English: One filter per line. A filter can be a plain hostname, or an Adblock Plus-compatible filter. Lines prefixed with &lsquo;!&rsquo; will be ignored." "description":"English: One filter per line. A filter can be a plain hostname, or an Adblock Plus-compatible filter. Lines prefixed with &lsquo;!&rsquo; will be ignored."

View File

@ -24,6 +24,7 @@
www.zerohedge.com##.similar-box www.zerohedge.com##.similar-box
# https://github.com/gorhill/uBlock/issues/57 # https://github.com/gorhill/uBlock/issues/57
# https://github.com/gorhill/uBlock/issues/98
# New filter class: entity filters, where # New filter class: entity filters, where
# entity = domain minus public suffix # entity = domain minus public suffix
# The following filters were taken out of EasyList and given an entity name, # The following filters were taken out of EasyList and given an entity name,

View File

@ -48,7 +48,7 @@ a {
display: none; display: none;
border: 1px dotted black; border: 1px dotted black;
background-color: #F8F8F8; background-color: #F8F8F8;
font-size: 90%; font-size: 13px;
} }
.whatisthis-expandable > p { .whatisthis-expandable > p {
margin-top: 1em; margin-top: 1em;

View File

@ -28,12 +28,13 @@
/******************************************************************************/ /******************************************************************************/
var userListName = chrome.i18n.getMessage('1pPageName'); var userListName = chrome.i18n.getMessage('1pPageName');
var selectedBlacklistsHash = ''; var listDetails = {};
var listURLPrefix = 'asset-viewer.html?url='; var parseCosmeticFilters = true;
var externalLists = '';
/******************************************************************************/ /******************************************************************************/
messaging.start('lists.js'); messaging.start('3p-filters.js');
var onMessage = function(msg) { var onMessage = function(msg) {
switch ( msg.what ) { switch ( msg.what ) {
@ -67,8 +68,6 @@ var renderNumber = function(value) {
var renderBlacklists = function() { var renderBlacklists = function() {
// empty list first // empty list first
uDom('#lists .listDetails').remove();
var µb = getµb(); var µb = getµb();
uDom('#listsOfBlockedHostsPrompt').text( uDom('#listsOfBlockedHostsPrompt').text(
@ -111,19 +110,22 @@ var renderBlacklists = function() {
var listStatsTemplate = chrome.i18n.getMessage('3pListsOfBlockedHostsPerListStats'); var listStatsTemplate = chrome.i18n.getMessage('3pListsOfBlockedHostsPerListStats');
var htmlFromBranch = function(groupKey, listKeys, lists) { var htmlFromBranch = function(groupKey, listKeys, lists) {
listKeys.sort(function(a, b) {
return lists[a].title.localeCompare(lists[b].title);
});
var html = [ var html = [
'<li>', '<li>',
chrome.i18n.getMessage('3pGroup' + groupKey.charAt(0).toUpperCase() + groupKey.slice(1)), chrome.i18n.getMessage('3pGroup' + groupKey.charAt(0).toUpperCase() + groupKey.slice(1)),
'<ul>' '<ul>'
]; ];
if ( !listKeys ) {
return html.join('');
}
listKeys.sort(function(a, b) {
return lists[a].title.localeCompare(lists[b].title);
});
var listEntryTemplate = [ var listEntryTemplate = [
'<li class="listDetails">', '<li class="listDetails">',
'<input type="checkbox" {{checked}}>', '<input type="checkbox" {{checked}}>',
'&thinsp;', '&thinsp;',
'<a href="', listURLPrefix, '{{URL}}" type="text/plain">', '<a href="{{URL}}" type="text/plain">',
'{{name}}', '{{name}}',
'</a>', '</a>',
': ', ': ',
@ -140,7 +142,7 @@ var renderBlacklists = function() {
.replace('{{URL}}', encodeURI(listKey)) .replace('{{URL}}', encodeURI(listKey))
.replace('{{name}}', htmlFromListName(list.title, listKey)) .replace('{{name}}', htmlFromListName(list.title, listKey))
.replace('{{used}}', !list.off && !isNaN(+list.entryUsedCount) ? renderNumber(list.entryUsedCount) : '0') .replace('{{used}}', !list.off && !isNaN(+list.entryUsedCount) ? renderNumber(list.entryUsedCount) : '0')
.replace('{{total}}', !isNaN(+list.entryCount) ? renderNumber(list.entryCount) : '?') .replace('{{total}}', !isNaN(+list.entryCount) ? renderNumber(list.entryCount) : '?');
html.push(listEntry); html.push(listEntry);
} }
html.push('</ul>'); html.push('</ul>');
@ -164,58 +166,84 @@ var renderBlacklists = function() {
return groups; return groups;
}; };
var html = []; var onListsReceived = function(details) {
var groups = groupsFromLists(µb.remoteBlacklists); listDetails = details;
var groupKey;
var groupKeys = [
'default',
'ads',
'privacy',
'malware',
'social',
'multipurpose',
'regions'
];
for ( var i = 0; i < groupKeys.length; i++ ) {
groupKey = groupKeys[i];
html.push(htmlFromBranch(groupKey, groups[groupKey], µb.remoteBlacklists));
delete groups[groupKey];
}
// For all groups not covered above (if any left)
groupKeys = Object.keys(groups);
for ( var i = 0; i < groupKeys.length; i++ ) {
groupKey = groupKeys[i];
html.push(htmlFromBranch(groupKey, groups[groupKey], µb.remoteBlacklists));
delete groups[groupKey];
}
uDom('#lists').html(html.join('')); var lists = details.available;
uDom('#parseAllABPHideFilters').prop('checked', µb.userSettings.parseAllABPHideFilters === true); var html = [];
uDom('#ubiquitousParseAllABPHideFiltersPrompt2').text( var groups = groupsFromLists(lists);
chrome.i18n.getMessage("listsParseAllABPHideFiltersPrompt2") var groupKey, i;
.replace('{{abpHideFilterCount}}', renderNumber(µb.abpHideFilters.getFilterCount())) var groupKeys = [
); 'default',
'ads',
'privacy',
'malware',
'social',
'multipurpose',
'regions',
'custom'
];
for ( i = 0; i < groupKeys.length; i++ ) {
groupKey = groupKeys[i];
html.push(htmlFromBranch(groupKey, groups[groupKey], lists));
delete groups[groupKey];
}
// For all groups not covered above (if any left)
groupKeys = Object.keys(groups);
for ( i = 0; i < groupKeys.length; i++ ) {
groupKey = groupKeys[i];
html.push(htmlFromBranch(groupKey, groups[groupKey], lists));
delete groups[groupKey];
}
uDom('a').attr('target', '_blank'); uDom('#lists .listDetails').remove();
selectedBlacklistsHash = getSelectedBlacklistsHash(); uDom('#lists').html(html.join(''));
uDom('#parseAllABPHideFilters').prop('checked', listDetails.cosmetic === true);
uDom('#ubiquitousParseAllABPHideFiltersPrompt2').text(
chrome.i18n.getMessage("listsParseAllABPHideFiltersPrompt2")
.replace('{{abpHideFilterCount}}', renderNumber(µb.abpHideFilters.getFilterCount()))
);
uDom('a').attr('target', '_blank');
selectedBlacklistsChanged();
};
messaging.ask({ what: 'getLists' }, onListsReceived);
}; };
/******************************************************************************/ /******************************************************************************/
// Create a hash so that we know whether the selection of preset blacklists // Check whether lists need reloading.
// has changed.
var getSelectedBlacklistsHash = function() { var needToReload = function() {
var hash = ''; if ( listDetails.cosmetic !== getµb().userSettings.parseAllABPHideFilters ) {
var inputs = uDom('#lists .listDetails > input'); return true;
var i = inputs.length();
while ( i-- ) {
hash += inputs.subset(i).prop('checked').toString();
} }
// Factor in whether cosmetic filters are to be processed var availableLists = listDetails.available;
hash += uDom('#parseAllABPHideFilters').prop('checked').toString(); var currentLists = listDetails.current;
var location, availableOff, currentOff;
return hash; // This check existing entries
for ( location in availableLists ) {
if ( availableLists.hasOwnProperty(location) === false ) {
continue;
}
availableOff = availableLists[location].off === true;
currentOff = currentLists[location] === undefined || currentLists[location].off === true;
if ( availableOff !== currentOff ) {
return true;
}
}
// This check removed entries
for ( location in currentLists ) {
if ( currentLists.hasOwnProperty(location) === false ) {
continue;
}
currentOff = currentLists[location].off === true;
availableOff = availableLists[location] === undefined || availableLists[location].off === true;
if ( availableOff !== currentOff ) {
return true;
}
}
return false;
}; };
/******************************************************************************/ /******************************************************************************/
@ -223,10 +251,21 @@ var getSelectedBlacklistsHash = function() {
// This is to give a visual hint that the selection of blacklists has changed. // This is to give a visual hint that the selection of blacklists has changed.
var selectedBlacklistsChanged = function() { var selectedBlacklistsChanged = function() {
uDom('#blacklistsApply').prop( uDom('#blacklistsApply').prop('disabled', !needToReload());
'disabled', };
getSelectedBlacklistsHash() === selectedBlacklistsHash
); /******************************************************************************/
var onListCheckboxChanged = function() {
var href = uDom(this).parent().find('a').first().attr('href');
if ( typeof href !== 'string' ) {
return;
}
if ( listDetails.available[href] === undefined ) {
return;
}
listDetails.available[href].off = !this.checked;
selectedBlacklistsChanged();
}; };
/******************************************************************************/ /******************************************************************************/
@ -242,11 +281,16 @@ var onListLinkClicked = function(ev) {
/******************************************************************************/ /******************************************************************************/
var blacklistsApplyHandler = function() { var blacklistsApplyHandler = function() {
var newHash = getSelectedBlacklistsHash(); if ( !needToReload() ) {
if ( newHash === selectedBlacklistsHash ) {
return; return;
} }
// Reload blacklists // Reload blacklists
messaging.tell({
what: 'userSettings',
name: 'parseAllABPHideFilters',
value: parseCosmeticFilters
});
// Reload blacklists
var switches = []; var switches = [];
var lis = uDom('#lists .listDetails'); var lis = uDom('#lists .listDetails');
var i = lis.length(); var i = lis.length();
@ -255,8 +299,7 @@ var blacklistsApplyHandler = function() {
path = lis path = lis
.subset(i) .subset(i)
.find('a') .find('a')
.attr('href') .attr('href');
.replace(listURLPrefix, '');
switches.push({ switches.push({
location: path, location: path,
off: lis.subset(i).find('input').prop('checked') === false off: lis.subset(i).find('input').prop('checked') === false
@ -266,30 +309,61 @@ var blacklistsApplyHandler = function() {
what: 'reloadAllFilters', what: 'reloadAllFilters',
switches: switches switches: switches
}); });
uDom('#blacklistsApply').prop('disabled', true ); uDom('#blacklistsApply').prop('disabled', true);
}; };
/******************************************************************************/ /******************************************************************************/
var abpHideFiltersCheckboxChanged = function() { var abpHideFiltersCheckboxChanged = function() {
listDetails.cosmetic = this.checked;
selectedBlacklistsChanged();
};
/******************************************************************************/
var renderExternalLists = function() {
var onReceived = function(details) {
uDom('#externalLists').val(details);
externalLists = details;
};
messaging.ask({ what: 'userSettings', name: 'externalLists' }, onReceived);
};
/******************************************************************************/
var externalListsChangeHandler = function() {
uDom('#externalListsApply').prop(
'disabled',
this.value.trim() === externalLists
);
};
/******************************************************************************/
var externalListsApplyHandler = function() {
externalLists = uDom('#externalLists').val();
messaging.tell({ messaging.tell({
what: 'userSettings', what: 'userSettings',
name: 'parseAllABPHideFilters', name: 'externalLists',
value: this.checked value: externalLists
}); });
selectedBlacklistsChanged(); renderBlacklists();
uDom('#externalListsApply').prop('disabled', true);
}; };
/******************************************************************************/ /******************************************************************************/
uDom.onLoad(function() { uDom.onLoad(function() {
// Handle user interaction // Handle user interaction
uDom('#lists').on('change', '.listDetails', selectedBlacklistsChanged);
uDom('#lists').on('click', '.listDetails > a:first-child', onListLinkClicked);
uDom('#blacklistsApply').on('click', blacklistsApplyHandler);
uDom('#parseAllABPHideFilters').on('change', abpHideFiltersCheckboxChanged); uDom('#parseAllABPHideFilters').on('change', abpHideFiltersCheckboxChanged);
uDom('#blacklistsApply').on('click', blacklistsApplyHandler);
uDom('#lists').on('change', '.listDetails > input', onListCheckboxChanged);
uDom('#lists').on('click', '.listDetails > a:nth-of-type(1)', onListLinkClicked);
uDom('#externalLists').on('input', externalListsChangeHandler);
uDom('#externalListsApply').on('click', externalListsApplyHandler);
renderBlacklists(); renderBlacklists();
renderExternalLists();
}); });
/******************************************************************************/ /******************************************************************************/

View File

@ -122,7 +122,7 @@ var getUpdateList = function(callback) {
} }
}; };
µBlock.assets.getRemote('assets/checksums.txt', onRemoteChecksumsLoaded); µBlock.assets.getRepo('assets/checksums.txt', onRemoteChecksumsLoaded);
µBlock.assets.get('assets/checksums.txt', onLocalChecksumsLoaded); µBlock.assets.get('assets/checksums.txt', onLocalChecksumsLoaded);
}; };
@ -200,6 +200,9 @@ var update = function(list, callback) {
processList(); processList();
}; };
// Purge obsolete external assets
µBlock.assets.purge(/^https?:\/\/.+$/, Date.now() - µBlock.updateAssetsEvery);
if ( list ) { if ( list ) {
processList(); processList();
} else { } else {

View File

@ -146,7 +146,7 @@ var cachedAssetsManager = (function() {
}; };
var onEntries = function(entries) { var onEntries = function(entries) {
if ( entries[path] === undefined ) { if ( entries[path] === undefined ) {
entries[path] = true; entries[path] = Date.now();
bin.cached_asset_entries = entries; bin.cached_asset_entries = entries;
} }
chrome.storage.local.set(bin, onSaved); chrome.storage.local.set(bin, onSaved);
@ -154,7 +154,7 @@ var cachedAssetsManager = (function() {
getEntries(onEntries); getEntries(onEntries);
}; };
exports.remove = function(pattern) { exports.remove = function(pattern, before) {
var onEntries = function(entries) { var onEntries = function(entries) {
var keystoRemove = []; var keystoRemove = [];
var paths = Object.keys(entries); var paths = Object.keys(entries);
@ -168,6 +168,9 @@ var cachedAssetsManager = (function() {
if ( pattern instanceof RegExp && !pattern.test(path) ) { if ( pattern instanceof RegExp && !pattern.test(path) ) {
continue; continue;
} }
if ( typeof before === 'number' && entries[path] >= before ) {
continue;
}
keystoRemove.push(cachedAssetPathPrefix + path); keystoRemove.push(cachedAssetPathPrefix + path);
delete entries[path]; delete entries[path];
} }
@ -406,7 +409,9 @@ var readLocalFile = function(path, callback) {
/******************************************************************************/ /******************************************************************************/
var readRemoteFile = function(path, callback) { // Get the repository copy of a built-in asset.
var readRepoFile = function(path, callback) {
var reportBack = function(content, err) { var reportBack = function(content, err) {
var details = { var details = {
'path': path, 'path': path,
@ -416,8 +421,8 @@ var readRemoteFile = function(path, callback) {
callback(details); callback(details);
}; };
var onRemoteFileLoaded = function() { var onRepoFileLoaded = function() {
// console.log('µBlock> readRemoteFile() / onRemoteFileLoaded()'); // console.log('µBlock> readRepoFile() / onRepoFileLoaded()');
// https://github.com/gorhill/httpswitchboard/issues/263 // https://github.com/gorhill/httpswitchboard/issues/263
if ( this.status === 200 ) { if ( this.status === 200 ) {
reportBack(this.responseText); reportBack(this.responseText);
@ -427,8 +432,8 @@ var readRemoteFile = function(path, callback) {
this.onload = this.onerror = null; this.onload = this.onerror = null;
}; };
var onRemoteFileError = function(ev) { var onRepoFileError = function(ev) {
console.error('µBlock> readRemoteFile() / onRemoteFileError("%s")', path); console.error('µBlock> readRepoFile() / onRepoFileError("%s")', path);
reportBack('', 'Error'); reportBack('', 'Error');
this.onload = this.onerror = null; this.onload = this.onerror = null;
}; };
@ -436,13 +441,64 @@ var readRemoteFile = function(path, callback) {
// 'ublock=...' is to skip browser cache // 'ublock=...' is to skip browser cache
getTextFileFromURL( getTextFileFromURL(
repositoryRoot + path + '?ublock=' + Date.now(), repositoryRoot + path + '?ublock=' + Date.now(),
onRemoteFileLoaded, onRepoFileLoaded,
onRemoteFileError onRepoFileError
); );
}; };
/******************************************************************************/ /******************************************************************************/
var readExternalFile = function(path, callback) {
var reportBack = function(content, err) {
var details = {
'path': path,
'content': content
};
if ( err ) {
details.error = err;
}
callback(details);
};
var onExternalFileCached = function(details) {
this.onload = this.onerror = null;
// console.log('µBlock> onExternalFileCached()');
reportBack(details.content);
};
var onExternalFileLoaded = function() {
this.onload = this.onerror = null;
// console.log('µBlock> onExternalFileLoaded()');
cachedAssetsManager.save(path, this.responseText, onExternalFileCached);
};
var onExternalFileError = function(ev) {
console.error('µBlock> onExternalFileError() / onLocalFileError("%s")', path);
reportBack('', 'Error');
this.onload = this.onerror = null;
};
var onCachedContentLoaded = function(details) {
// console.log('µBlock> readLocalFile() / onCacheFileLoaded()');
reportBack(details.content);
};
var onCachedContentError = function(details) {
// console.error('µBlock> readLocalFile() / onCacheFileError("%s")', path);
getTextFileFromURL(details.path, onExternalFileLoaded, onExternalFileError);
};
cachedAssetsManager.load(path, onCachedContentLoaded, onCachedContentError);
};
/******************************************************************************/
var purgeCache = function(pattern, before) {
cachedAssetsManager.remove(pattern, before);
};
/******************************************************************************/
var writeLocalFile = function(path, content, callback) { var writeLocalFile = function(path, content, callback) {
cachedAssetsManager.save(path, content, callback); cachedAssetsManager.save(path, content, callback);
}; };
@ -580,7 +636,9 @@ synchronizeCache();
return { return {
'get': readLocalFile, 'get': readLocalFile,
'getRemote': readRemoteFile, 'getExternal': readExternalFile,
'getRepo': readRepoFile,
'purge': purgeCache,
'put': writeLocalFile, 'put': writeLocalFile,
'update': updateFromRemote 'update': updateFromRemote
}; };

View File

@ -32,6 +32,7 @@ return {
userSettings: { userSettings: {
collapseBlocked: true, collapseBlocked: true,
externalLists: '',
logBlockedRequests: false, logBlockedRequests: false,
logAllowedRequests: false, logAllowedRequests: false,
parseAllABPHideFilters: true, parseAllABPHideFilters: true,
@ -47,13 +48,12 @@ return {
projectServerRoot: 'https://raw.githubusercontent.com/gorhill/uBlock/master/', projectServerRoot: 'https://raw.githubusercontent.com/gorhill/uBlock/master/',
userFiltersPath: 'assets/user/filters.txt', userFiltersPath: 'assets/user/filters.txt',
// list of remote blacklist locations // permanent lists
remoteBlacklists: { permanentLists: {
// User // User
'assets/user/filters.txt': { 'assets/user/filters.txt': {
group: 'default' group: 'default'
}, },
// uBlock // uBlock
'assets/ublock/filters.txt': { 'assets/ublock/filters.txt': {
title: 'µBlock filters', title: 'µBlock filters',
@ -64,7 +64,10 @@ return {
title: 'µBlock filters - Privacy', title: 'µBlock filters - Privacy',
group: 'default' group: 'default'
} }
// 3rd-party lists fetched dynamically },
// current lists
remoteBlacklists: {
}, },
pageStores: {}, pageStores: {},

View File

@ -36,7 +36,7 @@
var InvalidCharacterError = function(message) { var InvalidCharacterError = function(message) {
this.message = message; this.message = message;
}; };
InvalidCharacterError.prototype = new Error; InvalidCharacterError.prototype = new Error();
InvalidCharacterError.prototype.name = 'InvalidCharacterError'; InvalidCharacterError.prototype.name = 'InvalidCharacterError';
if (!CSS.escape) { if (!CSS.escape) {

View File

@ -233,11 +233,28 @@ var onMessage = function(request, sender, callback) {
(function() { (function() {
var getLists = function(callback) {
var µb = µBlock;
var onReceived = function(lists) {
callback({
available: lists,
current: µb.remoteBlacklists,
cosmetic: µb.userSettings.parseAllABPHideFilters
});
};
µb.getAvailableLists(onReceived);
};
/******************************************************************************/
var onMessage = function(request, sender, callback) { var onMessage = function(request, sender, callback) {
var µb = µBlock; var µb = µBlock;
// Async // Async
switch ( request.what ) { switch ( request.what ) {
case 'getLists':
return getLists(callback);
case 'readUserUbiquitousBlockRules': case 'readUserUbiquitousBlockRules':
return µb.assets.get(µb.userFiltersPath, callback); return µb.assets.get(µb.userFiltersPath, callback);

View File

@ -138,6 +138,9 @@ function defaultHandler(request, sender, callback) {
// Async // Async
switch ( request.what ) { switch ( request.what ) {
case 'getAssetContent': case 'getAssetContent':
if ( /^https?:\/\//.test(request.url) ) {
return µBlock.assets.getExternal(request.url, callback);
}
return µBlock.assets.get(request.url, callback); return µBlock.assets.get(request.url, callback);
case 'loadUbiquitousAllowRules': case 'loadUbiquitousAllowRules':

View File

@ -154,7 +154,7 @@ PageStore.prototype.updateBadge = function() {
var iconStr = ''; var iconStr = '';
if ( µb.userSettings.showIconBadge && netFilteringSwitch && this.perLoadBlockedRequestCount ) { if ( µb.userSettings.showIconBadge && netFilteringSwitch && this.perLoadBlockedRequestCount ) {
iconStr = µb.formatCount(this.perLoadBlockedRequestCount); iconStr = this.perLoadBlockedRequestCount.toLocaleString();
} }
chrome.browserAction.setBadgeText({ chrome.browserAction.setBadgeText({
tabId: this.tabId, tabId: this.tabId,

View File

@ -124,33 +124,100 @@
/******************************************************************************/ /******************************************************************************/
µBlock.loadUbiquitousBlacklists = function() { µBlock.getAvailableLists = function(callback) {
var blacklistLoadCount; var availableLists = {};
var obsoleteBlacklists = [];
var removeObsoleteBlacklistsHandler = function(store) { // selected lists
if ( !store.remoteBlacklists ) { var onSelectedListsLoaded = function(store) {
return; var lists = store.remoteBlacklists;
} var locations = Object.keys(lists);
var location; var location;
while ( location = obsoleteBlacklists.pop() ) {
delete store.remoteBlacklists[location]; while ( location = locations.pop() ) {
if ( !availableLists[location] ) {
continue;
}
// https://github.com/gorhill/httpswitchboard/issues/218
// Transfer potentially existing list title into restored list data.
if ( lists[location].title !== availableLists[location].title ) {
lists[location].title = availableLists[location].title;
}
availableLists[location] = lists[location];
} }
chrome.storage.local.set(store);
callback(availableLists);
}; };
var removeObsoleteBlacklists = function() { // built-in lists
if ( obsoleteBlacklists.length === 0 ) { var onBuiltinListsLoaded = function(details) {
return; var location, locations;
try {
locations = JSON.parse(details.content);
} catch (e) {
locations = {};
} }
for ( location in locations ) {
if ( locations.hasOwnProperty(location) === false ) {
continue;
}
availableLists['assets/thirdparties/' + location] = locations[location];
}
// Now get user's selection of lists
chrome.storage.local.get( chrome.storage.local.get(
{ 'remoteBlacklists': µBlock.remoteBlacklists }, { 'remoteBlacklists': availableLists },
removeObsoleteBlacklistsHandler onSelectedListsLoaded
); );
}; };
// permanent lists
var location;
var lists = this.permanentLists;
for ( location in lists ) {
if ( lists.hasOwnProperty(location) === false ) {
continue;
}
availableLists[location] = lists[location];
}
// custom lists
var c;
var locations = this.userSettings.externalLists.split('\n');
for ( var i = 0; i < locations.length; i++ ) {
location = locations[i].trim();
c = location.charAt(0);
if ( location === '' || c === '!' || c === '#' ) {
continue;
}
// Coarse validation
if ( /[^0-9A-Za-z!*'();:@&=+$,\/?%#\[\]_.~-]/.test(location) ) {
continue;
}
availableLists[location] = {
title: '',
group: 'custom',
external: true
};
}
// get built-in block lists.
this.assets.get('assets/ublock/filter-lists.json', onBuiltinListsLoaded);
};
/******************************************************************************/
µBlock.loadUbiquitousBlacklists = function() {
var µb = this;
var blacklistLoadCount;
var loadBlacklistsEnd = function() {
µb.abpFilters.freeze();
µb.abpHideFilters.freeze();
µb.messaging.announce({ what: 'loadUbiquitousBlacklistCompleted' });
chrome.storage.local.set({ 'remoteBlacklists': µb.remoteBlacklists });
};
var mergeBlacklist = function(details) { var mergeBlacklist = function(details) {
var µb = µBlock;
µb.mergeUbiquitousBlacklist(details); µb.mergeUbiquitousBlacklist(details);
blacklistLoadCount -= 1; blacklistLoadCount -= 1;
if ( blacklistLoadCount === 0 ) { if ( blacklistLoadCount === 0 ) {
@ -158,97 +225,38 @@
} }
}; };
var loadBlacklistsEnd = function() { var loadBlacklistsStart = function(lists) {
µBlock.abpFilters.freeze(); µb.remoteBlacklists = lists;
µBlock.abpHideFilters.freeze();
removeObsoleteBlacklists();
µBlock.messaging.announce({ what: 'loadUbiquitousBlacklistCompleted' });
};
var loadBlacklistsStart = function(store) {
var µb = µBlock;
// rhill 2013-12-10: set all existing entries to `false`. // rhill 2013-12-10: set all existing entries to `false`.
µb.abpFilters.reset(); µb.abpFilters.reset();
µb.abpHideFilters.reset(); µb.abpHideFilters.reset();
var storedLists = store.remoteBlacklists; var locations = Object.keys(lists);
var storedListLocations = Object.keys(storedLists); blacklistLoadCount = locations.length;
blacklistLoadCount = storedListLocations.length;
if ( blacklistLoadCount === 0 ) { if ( blacklistLoadCount === 0 ) {
loadBlacklistsEnd(); loadBlacklistsEnd();
return; return;
} }
// Backward compatibility for when a list changes location
var relocations = [
{
// https://github.com/gorhill/httpswitchboard/issues/361
'bad': 'assets/thirdparties/adblock-czechoslovaklist.googlecode.com/svn/filters.txt',
'good': 'assets/thirdparties/raw.githubusercontent.com/tomasko126/easylistczechandslovak/master/filters.txt'
}
];
var relocation;
while ( relocation = relocations.pop() ) {
if ( µb.remoteBlacklists[relocation.good] && storedLists[relocation.bad] ) {
storedLists[relocation.good].off = storedLists[relocation.bad].off;
}
}
// Load each preset blacklist which is not disabled. // Load each preset blacklist which is not disabled.
var location; var location;
while ( location = storedListLocations.pop() ) { while ( location = locations.pop() ) {
// If loaded list location is not part of default list locations,
// remove its entry from local storage.
if ( !µb.remoteBlacklists[location] ) {
obsoleteBlacklists.push(location);
blacklistLoadCount -= 1;
continue;
}
// https://github.com/gorhill/httpswitchboard/issues/218
// Transfer potentially existing list title into restored list data.
if ( storedLists[location].title !== µb.remoteBlacklists[location].title ) {
storedLists[location].title = µb.remoteBlacklists[location].title;
}
// Store details of this preset blacklist
µb.remoteBlacklists[location] = storedLists[location];
// rhill 2013-12-09: // rhill 2013-12-09:
// Ignore list if disabled // Ignore list if disabled
// https://github.com/gorhill/httpswitchboard/issues/78 // https://github.com/gorhill/httpswitchboard/issues/78
if ( storedLists[location].off ) { if ( lists[location].off ) {
blacklistLoadCount -= 1; blacklistLoadCount -= 1;
continue; continue;
} }
µb.assets.get(location, mergeBlacklist); if ( /^https?:\/\/.+$/.test(location) ) {
} µb.assets.getExternal(location, mergeBlacklist);
}; } else {
µb.assets.get(location, mergeBlacklist);
var onListOfBlockListsLoaded = function(details) {
var µb = µBlock;
// Initialize built-in list of 3rd-party block lists.
var lists = JSON.parse(details.content);
for ( var location in lists ) {
if ( lists.hasOwnProperty(location) === false ) {
continue;
} }
µb.remoteBlacklists['assets/thirdparties/' + location] = lists[location];
} }
// Now get user's selection of list of block lists.
chrome.storage.local.get(
{ 'remoteBlacklists': µb.remoteBlacklists },
loadBlacklistsStart
);
}; };
// Reset list of 3rd-party block lists. this.getAvailableLists(loadBlacklistsStart);
for ( var location in this.remoteBlacklists ) {
if ( location.indexOf('assets/thirdparties/') === 0 ) {
delete this.remoteBlacklists[location];
}
}
// Get new list of 3rd-party block lists.
this.assets.get('assets/ublock/filter-lists.json', onListOfBlockListsLoaded);
}; };
/******************************************************************************/ /******************************************************************************/