code review

This commit is contained in:
gorhill 2014-09-09 10:53:47 -04:00
parent d4789499ac
commit b2d78bcc16
3 changed files with 107 additions and 95 deletions

View File

@ -10,15 +10,15 @@
<body> <body>
<button id="buttonApply" class="reloadAll" data-i18n="3pApplyChanges"></button> <button id="buttonApply" class="custom reloadAll disabled" data-i18n="3pApplyChanges"></button>
<ul id="options"> <ul id="options">
<li><input type="checkbox" id="autoUpdate"><label data-i18n="3pAutoUpdatePrompt1" for="autoUpdate"></label> <li><input type="checkbox" id="autoUpdate"><label data-i18n="3pAutoUpdatePrompt1" for="autoUpdate"></label>
<button class="reloadAll" id="buttonUpdate" data-i18n="3pUpdateNow"></button> <button class="custom reloadAll disabled" id="buttonUpdate" data-i18n="3pUpdateNow"></button>
<button id="buttonPurgeAll" data-i18n="3pPurgeAll"></button> <button id="buttonPurgeAll" class="custom disabled" data-i18n="3pPurgeAll"></button>
<li><input type="checkbox" id="parseCosmeticFilters"><label data-i18n="3pParseAllABPHideFiltersPrompt1" for="parseCosmeticFilters"></label> <li><input type="checkbox" id="parseCosmeticFilters"><label data-i18n="3pParseAllABPHideFiltersPrompt1" for="parseCosmeticFilters"></label>
<button class="whatisthis"></button> <button class="whatisthis"></button>
<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><p id="listsOfBlockedHostsPrompt"></p>
</ul> </ul>
<ul id="lists"> <ul id="lists">
</ul> </ul>
@ -29,7 +29,7 @@
<p style="margin: 0.25em 0 0 0"><button id="externalListsApply" disabled="true" data-i18n="3pExternalListsApply"></button></p> <p style="margin: 0.25em 0 0 0"><button id="externalListsApply" disabled="true" data-i18n="3pExternalListsApply"></button></p>
</div> </div>
<div id="loadingOverlay"></div> <div id="busyOverlay"></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>

View File

@ -2,6 +2,12 @@ ul {
padding: 0; padding: 0;
list-style-type: none; list-style-type: none;
} }
ul#options {
margin-top: 0;
}
ul#options li {
margin-bottom: 0.5em;
}
ul#lists { ul#lists {
margin: 0.5em 0 0 0; margin: 0.5em 0 0 0;
padding-__MSG_@@bidi_end_edge__: 0em; padding-__MSG_@@bidi_end_edge__: 0em;
@ -33,40 +39,41 @@ li.listDetails > a:nth-of-type(2) {
opacity: 0.5; opacity: 0.5;
} }
/* I designed the button with: http://charliepark.org/bootstrap_buttons/ */ /* I designed the button with: http://charliepark.org/bootstrap_buttons/ */
button { button.custom {
border: 1px solid transparent;
border-radius: 3px;
border-color: #dddddd #dddddd hsl(36, 0%, 85%);
padding: 5px; padding: 5px;
background-color: hsl(36, 0%, 72%); border: 1px solid transparent;
background-repeat: repeat-x;
background-image: linear-gradient(#f2f2f2, #dddddd);
color: #aaa;
}
button.enabled {
border-color: #80b3ff #80b3ff hsl(216, 100%, 75%); border-color: #80b3ff #80b3ff hsl(216, 100%, 75%);
border-radius: 3px;
background-color: hsl(216, 100%, 75%); background-color: hsl(216, 100%, 75%);
background-image: linear-gradient(#a8cbff, #80b3ff); background-image: linear-gradient(#a8cbff, #80b3ff);
background-repeat: repeat-x;
color: #222; color: #222;
cursor: pointer; cursor: pointer;
opacity: 0.8; opacity: 0.8;
} }
button.reloadAll.enabled { button.custom.disabled {
border-color: #dddddd #dddddd hsl(36, 0%, 85%);
background-color: hsl(36, 0%, 72%);
background-image: linear-gradient(#f2f2f2, #dddddd);
color: #aaa;
pointer-events: none;
}
button.custom:hover {
opacity: 1.0;
}
button.custom.reloadAll:not(.disabled) {
border-color: #ffcc7f #ffcc7f hsl(36, 100%, 73%); border-color: #ffcc7f #ffcc7f hsl(36, 100%, 73%);
background-color: hsl(36, 100%, 75%); background-color: hsl(36, 100%, 75%);
background-image: linear-gradient(#ffdca8, #ffcc7f); background-image: linear-gradient(#ffdca8, #ffcc7f);
} }
button.enabled:hover {
opacity: 1.0;
}
#buttonApply { #buttonApply {
display: none;
position: fixed; position: fixed;
display: initial;
top: 1em; top: 1em;
__MSG_@@bidi_end_edge__: 1em; __MSG_@@bidi_end_edge__: 1em;
} }
#buttonApply.enabled { #buttonApply.disabled {
display: initial; display: none;
} }
span.status { span.status {
margin: 0; margin: 0;
@ -100,7 +107,7 @@ span.obsolete {
height: 8em; height: 8em;
white-space: nowrap; white-space: nowrap;
} }
body #loadingOverlay { body #busyOverlay {
position: fixed; position: fixed;
top: 0; top: 0;
right: 0; right: 0;
@ -112,6 +119,6 @@ body #loadingOverlay {
display: none; display: none;
z-index: 1000; z-index: 1000;
} }
body.loading #loadingOverlay { body.busy #busyOverlay {
display: block; display: block;
} }

View File

@ -35,8 +35,8 @@ var cacheWasPurged = false;
var needUpdate = false; var needUpdate = false;
var hasCachedContent = false; var hasCachedContent = false;
var reExternalAsset = /^https?:\/\/[a-z0-9]+/; var re3rdPartyExternalAsset = /^https?:\/\/[a-z0-9]+/;
var reRepo3rdPartyAsset = /^assets\/thirdparties\/([^\/]+)/; var re3rdPartyRepoAsset = /^assets\/thirdparties\/([^\/]+)/;
/******************************************************************************/ /******************************************************************************/
@ -45,7 +45,6 @@ messaging.start('3p-filters.js');
var onMessage = function(msg) { var onMessage = function(msg) {
switch ( msg.what ) { switch ( msg.what ) {
case 'loadUbiquitousBlacklistCompleted': case 'loadUbiquitousBlacklistCompleted':
uDom('body').toggleClass('loading', false);
renderBlacklists(); renderBlacklists();
break; break;
@ -73,6 +72,8 @@ var renderNumber = function(value) {
// TODO: get rid of background page dependencies // TODO: get rid of background page dependencies
var renderBlacklists = function() { var renderBlacklists = function() {
uDom('body').toggleClass('busy', true);
var µb = getµb(); var µb = getµb();
// Assemble a pretty blacklist name if possible // Assemble a pretty blacklist name if possible
@ -91,7 +92,7 @@ var renderBlacklists = function() {
if ( blacklistHref.indexOf('assets/thirdparties/') !== 0 ) { if ( blacklistHref.indexOf('assets/thirdparties/') !== 0 ) {
return ''; return '';
} }
var matches = reRepo3rdPartyAsset.exec(blacklistHref); var matches = re3rdPartyRepoAsset.exec(blacklistHref);
if ( matches === null || matches.length !== 2 ) { if ( matches === null || matches.length !== 2 ) {
return ''; return '';
} }
@ -110,12 +111,68 @@ var renderBlacklists = function() {
return html.join(''); return html.join('');
}; };
var listStatsTemplate = chrome.i18n.getMessage('3pListsOfBlockedHostsPerListStats');
var purgeButtontext = chrome.i18n.getMessage('3pExternalListPurge'); var purgeButtontext = chrome.i18n.getMessage('3pExternalListPurge');
var updateButtontext = chrome.i18n.getMessage('3pExternalListNew'); var updateButtontext = chrome.i18n.getMessage('3pExternalListNew');
var obsoleteButtontext = chrome.i18n.getMessage('3pExternalListObsolete'); var obsoleteButtontext = chrome.i18n.getMessage('3pExternalListObsolete');
var liTemplate = [
'<li class="listDetails">',
'<input type="checkbox" {{checked}}>',
' ',
'<a href="{{URL}}" type="text/plain">',
'{{name}}',
'\u200E</a>',
'{{homeURL}}',
': ',
'<span class="dim">',
chrome.i18n.getMessage('3pListsOfBlockedHostsPerListStats'),
'</span>'
].join('');
var htmlFromBranch = function(groupKey, listKeys, lists) { var htmlFromLeaf = function(listKey) {
var html = [];
var list = listDetails.available[listKey];
var li = liTemplate
.replace('{{checked}}', list.off ? '' : 'checked')
.replace('{{URL}}', encodeURI(listKey))
.replace('{{name}}', htmlFromListName(list.title, listKey))
.replace('{{homeURL}}', htmlFromHomeURL(listKey))
.replace('{{used}}', !list.off && !isNaN(+list.entryUsedCount) ? renderNumber(list.entryUsedCount) : '0')
.replace('{{total}}', !isNaN(+list.entryCount) ? renderNumber(list.entryCount) : '?');
html.push(li);
// https://github.com/gorhill/uBlock/issues/104
var asset = listDetails.cache[listKey];
if ( asset === undefined ) {
return html.join('\n');
}
// Update status
if ( list.off !== true ) {
var obsolete = asset.repoObsolete ||
asset.cacheObsolete ||
asset.cached !== true && re3rdPartyExternalAsset.test(listKey);
if ( obsolete ) {
html.push(
'&ensp;',
'<span class="status obsolete">',
asset.repoObsolete ? updateButtontext : obsoleteButtontext,
'</span>'
);
needUpdate = true;
}
}
// In cache
if ( asset.cached ) {
html.push(
'&ensp;',
'<span class="status purge">',
purgeButtontext,
'</span>'
);
hasCachedContent = true;
}
return html.join('\n');
};
var htmlFromBranch = function(groupKey, listKeys) {
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)),
@ -125,63 +182,10 @@ var renderBlacklists = function() {
return html.join(''); return html.join('');
} }
listKeys.sort(function(a, b) { listKeys.sort(function(a, b) {
return lists[a].title.localeCompare(lists[b].title); return listDetails.available[a].title.localeCompare(listDetails.available[b].title);
}); });
var listEntryTemplate = [
'<li class="listDetails">',
'<input type="checkbox" {{checked}}>',
' ',
'<a href="{{URL}}" type="text/plain">',
'{{name}}',
'\u200E</a>',
'{{homeURL}}',
': ',
'<span class="dim">',
listStatsTemplate,
'</span>'
].join('');
var listKey, list, listEntry, entryDetails, obsolete;
for ( var i = 0; i < listKeys.length; i++ ) { for ( var i = 0; i < listKeys.length; i++ ) {
listKey = listKeys[i]; html.push(htmlFromLeaf(listKeys[i]));
list = lists[listKey];
listEntry = listEntryTemplate
.replace('{{checked}}', list.off ? '' : 'checked')
.replace('{{URL}}', encodeURI(listKey))
.replace('{{name}}', htmlFromListName(list.title, listKey))
.replace('{{homeURL}}', htmlFromHomeURL(listKey))
.replace('{{used}}', !list.off && !isNaN(+list.entryUsedCount) ? renderNumber(list.entryUsedCount) : '0')
.replace('{{total}}', !isNaN(+list.entryCount) ? renderNumber(list.entryCount) : '?');
html.push(listEntry);
// https://github.com/gorhill/uBlock/issues/104
entryDetails = listDetails.cache[listKey];
if ( entryDetails === undefined ) {
continue;
}
// Update status
if ( list.off !== true ) {
obsolete = entryDetails.repoObsolete ||
entryDetails.cacheObsolete ||
entryDetails.cached !== true && reExternalAsset.test(listKey);
if ( obsolete ) {
html.push(
'&ensp;',
'<span class="status obsolete">',
entryDetails.repoObsolete ? updateButtontext : obsoleteButtontext,
'</span>'
);
needUpdate = true;
}
}
// In cache
if ( entryDetails.cached ) {
html.push(
'&ensp;',
'<span class="status purge">',
purgeButtontext,
'</span>'
);
hasCachedContent = true;
}
} }
html.push('</ul>'); html.push('</ul>');
return html.join(''); return html.join('');
@ -207,14 +211,15 @@ var renderBlacklists = function() {
}; };
var onListsReceived = function(details) { var onListsReceived = function(details) {
// Before all, set context vars
listDetails = details; listDetails = details;
cosmeticSwitch = details.cosmetic; cosmeticSwitch = details.cosmetic;
needUpdate = false; needUpdate = false;
hasCachedContent = false; hasCachedContent = false;
var lists = details.available; // Visually split the filter lists in purpose-based groups
var html = []; var html = [];
var groups = groupsFromLists(lists); var groups = groupsFromLists(details.available);
var groupKey, i; var groupKey, i;
var groupKeys = [ var groupKeys = [
'default', 'default',
@ -228,14 +233,14 @@ var renderBlacklists = function() {
]; ];
for ( i = 0; i < groupKeys.length; i++ ) { for ( i = 0; i < groupKeys.length; i++ ) {
groupKey = groupKeys[i]; groupKey = groupKeys[i];
html.push(htmlFromBranch(groupKey, groups[groupKey], lists)); html.push(htmlFromBranch(groupKey, groups[groupKey]));
delete groups[groupKey]; delete groups[groupKey];
} }
// For all groups not covered above (if any left) // For all groups not covered above (if any left)
groupKeys = Object.keys(groups); groupKeys = Object.keys(groups);
for ( i = 0; i < groupKeys.length; i++ ) { for ( i = 0; i < groupKeys.length; i++ ) {
groupKey = groupKeys[i]; groupKey = groupKeys[i];
html.push(htmlFromBranch(groupKey, groups[groupKey], lists)); html.push(htmlFromBranch(groupKey, groups[groupKey]));
delete groups[groupKey]; delete groups[groupKey];
} }
@ -307,9 +312,10 @@ var listsContentChanged = 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 updateWidgets = function() { var updateWidgets = function() {
uDom('#buttonApply').toggleClass('enabled', listsSelectionChanged()); uDom('#buttonApply').toggleClass('disabled', !listsSelectionChanged());
uDom('#buttonUpdate').toggleClass('enabled', listsContentChanged()); uDom('#buttonUpdate').toggleClass('disabled', !listsContentChanged());
uDom('#buttonPurgeAll').toggleClass('enabled', hasCachedContent); uDom('#buttonPurgeAll').toggleClass('disabled', !hasCachedContent);
uDom('body').toggleClass('busy', false);
}; };
/******************************************************************************/ /******************************************************************************/
@ -356,9 +362,9 @@ var onPurgeClicked = function() {
/******************************************************************************/ /******************************************************************************/
var reloadAll = function(update) { var reloadAll = function(update) {
// Loading may take a while when resoruces are fetched from remote // Loading may take a while when resources are fetched from remote
// servers. We do not want the user to force reload while we are reloading. // servers. We do not want the user to force reload while we are reloading.
uDom('body').toggleClass('loading', true); uDom('body').toggleClass('busy', true);
// Reload blacklists // Reload blacklists
messaging.tell({ messaging.tell({
@ -465,7 +471,6 @@ var externalListsApplyHandler = function() {
/******************************************************************************/ /******************************************************************************/
uDom.onLoad(function() { uDom.onLoad(function() {
// Handle user interaction
uDom('#autoUpdate').on('change', autoUpdateCheckboxChanged); uDom('#autoUpdate').on('change', autoUpdateCheckboxChanged);
uDom('#parseCosmeticFilters').on('change', cosmeticSwitchChanged); uDom('#parseCosmeticFilters').on('change', cosmeticSwitchChanged);
uDom('#buttonApply').on('click', buttonApplyHandler); uDom('#buttonApply').on('click', buttonApplyHandler);