1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-11-02 00:42:45 +01:00

"advanced user" flag + rearranging a bit dashboard

This commit is contained in:
gorhill 2015-01-06 11:44:06 -05:00
parent 3a5c2cfa57
commit 881e8111d8
14 changed files with 169 additions and 178 deletions

View File

@ -215,6 +215,10 @@
"message":"Make use of context menu where appropriate",
"description":"English: Make use of context menu where appropriate"
},
"settingsAdvancedUserPrompt":{
"message":"I am an advanced user (<a href='https:\/\/github.com\/gorhill\/uBlock\/wiki\/Advanced-user-features'>About<\/a>)",
"description":"English: "
},
"settingsExperimentalPrompt":{
"message":"Enable experimental features (<a href='https:\/\/github.com\/gorhill\/uBlock\/wiki\/Experimental-features'>About<\/a>)",
"description":"English: Enable experimental features"

View File

@ -22,16 +22,6 @@
</ul>
</ul>
<div style="margin:3em 0;border-top:1px solid #ccc;"></div>
<div style="margin:1em 0 0 0;">
<p><button type="button" id="export" data-i18n="aboutBackupDataButton"></button>
<button type="button" id="import" data-i18n="aboutRestoreDataButton"></button>
<input id="restoreFilePicker" type="file" accept="text/plain" class="hiddenFileInput">
<p>
<p><button type="button" id="reset" data-i18n="aboutResetDataButton"></button>
</div>
<script src="js/vapi-common.js"></script>
<script src="js/vapi-client.js"></script>
<script src="js/udom.js"></script>

View File

@ -18,14 +18,14 @@
cursor: pointer;
position: relative;
}
[data-tip]:hover:after {
body:not(.advancedUser) [data-tip]:hover:after {
background-color: #ffffee;
border: 1px solid gray;
border-radius: 3px;
box-shadow: 1px 1px 3px gray;
color: black;
content: attr(data-tip);
font: 11px sans-serif;
font: 12px sans-serif;
left: 0;
line-height: 130%;
min-width: 55%;

View File

@ -62,6 +62,7 @@ body[dir="rtl"] #panes > div:nth-of-type(2) {
}
#panes > div:nth-of-type(1) {
min-width: 150px;
padding: 4px 5px 0 5px;
}
p {
@ -115,43 +116,17 @@ p {
color: #444;
}
#dfToggler::before {
body.advancedUser #dfToggler::before {
color: gray;
content: '+\202F';
cursor: pointer;
font-size: 14px;
line-height: 14px;
}
#panes.dfEnabled #dfToggler::before {
body.advancedUser #panes.dfEnabled #dfToggler::before {
content: '\2212\202F';
}
.dynamicFiltering div > .tip {
background-color: #fffff4;
border: 1px solid #888;
border-radius: 5px;
bottom: 20%;
box-shadow: 1px 1px 2px 0 rgba(0,0,0,0.8);
display: none;
font-size: small;
left: 8%;
padding: 0.25em;
position: fixed;
right: 8%;
text-align: center;
}
.dynamicFiltering div:not(.blocked):hover > .tip:nth-of-type(1) {
display: block;
}
.dynamicFiltering div.blocked:hover > .tip:nth-of-type(2) {
display: block;
}
.dynamicFiltering div > .tip code {
background-color: #f8f8f8;
font: normal monospace;
padding: 1px 0;
}
#dynamicFilteringContainer {
border: 0;
font-size: 12px;
@ -269,17 +244,3 @@ p {
#dynamicFilteringContainer span.bRule #actionSelector > span:nth-of-type(3) {
visibility: hidden;
}
#hotspotTip {
background-color: #ffe;
border: 1px dotted #ddb;
border-radius: 5px;
height: 50vh;
opacity: 1;
padding: 4px;
position: fixed;
right: 10px;
text-align: center;
top: 25vh;
width: 20vw;
z-index: 100;
}

View File

@ -11,11 +11,11 @@
<div id="dashboard-nav">
<div id="dashboard-nav-widgets">
<span data-i18n="extName"></span>
<a class="tabButton" href="#settings.html" data-i18n="settingsPageName"></a>
<a class="tabButton" href="#3p-filters.html" data-i18n="3pPageName"></a>
<a class="tabButton" href="#1p-filters.html" data-i18n="1pPageName"></a>
<a class="tabButton" href="#dyna-rules.html" data-i18n="rulesPageName"></a>
<a class="tabButton" href="#whitelist.html" data-i18n="whitelistPageName"></a>
<a class="tabButton" href="#settings.html" data-i18n="settingsPageName"></a>
<a class="tabButton" href="#about.html" data-i18n="aboutPageName"></a>
</div>
</div>

View File

@ -33,101 +33,8 @@ var messager = vAPI.messaging.channel('about.js');
/******************************************************************************/
var exportToFile = function() {
var onUserDataReady = function(userData) {
if (!userData) {
return;
}
var now = new Date();
var filename = vAPI.i18n('aboutBackupFilename')
.replace('{{datetime}}', now.toLocaleString())
.replace(/ +/g, '_');
vAPI.download({
'url': 'data:text/plain;charset=utf-8,' + encodeURIComponent(JSON.stringify(userData, null, ' ')),
'filename': filename
});
};
messager.send({ what: 'getUserData' }, onUserDataReady);
};
/******************************************************************************/
var handleImportFilePicker = function() {
var fileReaderOnLoadHandler = function() {
var userData;
try {
userData = JSON.parse(this.result);
if ( typeof userData !== 'object' ) {
throw 'Invalid';
}
if ( typeof userData.userSettings !== 'object' ) {
throw 'Invalid';
}
if ( typeof userData.netWhitelist !== 'string' ) {
throw 'Invalid';
}
if ( typeof userData.filterLists !== 'object' ) {
throw 'Invalid';
}
}
catch (e) {
userData = undefined;
}
if ( userData === undefined ) {
window.alert(vAPI.i18n('aboutRestoreDataError'));
return;
}
var time = new Date(userData.timeStamp);
var msg = vAPI.i18n('aboutRestoreDataConfirm')
.replace('{{time}}', time.toLocaleString());
var proceed = window.confirm(msg);
if ( proceed ) {
messager.send({ what: 'restoreUserData', userData: userData });
}
};
var file = this.files[0];
if ( file === undefined || file.name === '' ) {
return;
}
if ( file.type.indexOf('text') !== 0 ) {
return;
}
var fr = new FileReader();
fr.onload = fileReaderOnLoadHandler;
fr.readAsText(file);
};
/******************************************************************************/
var startImportFilePicker = function() {
var input = document.getElementById('restoreFilePicker');
// Reset to empty string, this will ensure an change event is properly
// triggered if the user pick a file, even if it is the same as the last
// one picked.
input.value = '';
input.click();
};
/******************************************************************************/
var resetUserData = function() {
var msg = vAPI.i18n('aboutResetDataConfirm');
var proceed = window.confirm(msg);
if ( proceed ) {
messager.send({ what: 'resetUserData' });
}
};
/******************************************************************************/
var onAppDataReady = function(appData) {
uDom('#aboutNameVer').html(appData.name + ' v' + appData.version);
uDom('#export').on('click', exportToFile);
uDom('#import').on('click', startImportFilePicker);
uDom('#reset').on('click', resetUserData);
uDom('#restoreFilePicker').on('change', handleImportFilePicker);
};
messager.send({ what: 'getAppData' }, onAppDataReady);

View File

@ -52,6 +52,7 @@ var defaultExternalLists = [
return {
userSettings: {
advancedUserEnabled: false,
autoUpdate: true,
collapseBlocked: true,
contextMenuEnabled: true,

View File

@ -59,7 +59,7 @@ uDom.onLoad(function() {
}
}
if ( !tab ) {
tab = '3p-filters';
tab = 'settings';
}
loadDashboardPanel(tab + '.html', q);
uDom('.tabButton').on('click', onTabClickHandler);

View File

@ -171,17 +171,18 @@ var getDynamicFilterRules = function(srcHostname, desHostnames) {
var getStats = function(tabId) {
var r = {
advancedUserEnabled: µb.userSettings.advancedUserEnabled,
appName: vAPI.app.name,
appVersion: vAPI.app.version,
globalBlockedRequestCount: µb.localSettings.blockedRequestCount,
globalAllowedRequestCount: µb.localSettings.allowedRequestCount,
tabId: tabId,
pageURL: '',
pageBlockedRequestCount: 0,
pageAllowedRequestCount: 0,
netFilteringSwitch: false,
cosmeticFilteringSwitch: false,
dfEnabled: µb.userSettings.dynamicFilteringEnabled
dfEnabled: µb.userSettings.dynamicFilteringEnabled,
globalAllowedRequestCount: µb.localSettings.allowedRequestCount,
globalBlockedRequestCount: µb.localSettings.blockedRequestCount,
netFilteringSwitch: false,
pageURL: '',
pageAllowedRequestCount: 0,
pageBlockedRequestCount: 0,
tabId: tabId
};
var pageStore = µb.pageStoreFromTabId(tabId);
if ( pageStore ) {
@ -811,7 +812,7 @@ vAPI.messaging.listen('stats.js', onMessage);
/******************************************************************************/
/******************************************************************************/
// about.js
// settings.js
(function() {
@ -902,7 +903,7 @@ var onMessage = function(request, sender, callback) {
callback(response);
};
vAPI.messaging.listen('about.js', onMessage);
vAPI.messaging.listen('settings.js', onMessage);
/******************************************************************************/

View File

@ -615,11 +615,13 @@ PageStore.prototype.filterRequest = function(context) {
// - Evaluating dynamic filtering is much faster than static filtering
// We evaluate dynamic filtering first, and hopefully we can skip
// evaluation of static filtering.
if ( µb.userSettings.advancedUserEnabled ) {
var df = µb.dynamicNetFilteringEngine.clearRegisters();
df.evaluateCellZY(context.rootHostname, context.requestHostname, context.requestType);
if ( df.mustBlockOrAllow() ) {
result = df.toFilterString();
}
}
// Static filtering never override dynamic filtering
if ( result === '' ) {

View File

@ -117,7 +117,7 @@ var reRulekeyCompareNoise = /[^a-z0-9.]/g;
var addDynamicFilterRow = function(des) {
var row = uDom('#templates > div:nth-of-type(1)').clone();
row.descendants('[data-des]').attr('data-des', des);
row.descendants('div > span:nth-of-type(1)').text(des);
row.descendants('span:nth-of-type(1)').text(des);
var hnDetails = popupData.hostnameDict[des] || {};
var isDomain = des === hnDetails.domain;
@ -245,16 +245,17 @@ var renderPopup = function() {
var isHTTP = /^https?:\/\/[0-9a-z]/.test(popupData.pageURL);
// Condition for dynamic filtering toggler:
// - Advanced user
uDom('body').toggleClass('advancedUser', popupData.advancedUserEnabled);
// Conditions for request log:
// - `http` or `https` scheme
uDom('#gotoLog').toggleClass('enabled', isHTTP);
// Conditions for element picker:
// - `http` or `https` scheme
uDom('#gotoPick').toggleClass(
'enabled',
isHTTP
);
uDom('#gotoPick').toggleClass('enabled', isHTTP);
var or = vAPI.i18n('popupOr');
var blocked = popupData.pageBlockedRequestCount;
@ -289,15 +290,15 @@ var renderPopup = function() {
'%</span>'
);
}
uDom('#total-blocked').html(html.join(''));
// Build dynamic filtering pane only if in use
if ( popupData.dfEnabled ) {
if ( popupData.dfEnabled && popupData.advancedUserEnabled ) {
syncAllDynamicFilters();
}
uDom('#total-blocked').html(html.join(''));
uDom('#switch .fa').toggleClass('off', popupData.pageURL === '' || !popupData.netFilteringSwitch);
uDom('#panes').toggleClass('dfEnabled', popupData.dfEnabled);
uDom('#panes').toggleClass('dfEnabled', popupData.dfEnabled && popupData.advancedUserEnabled);
};
/******************************************************************************/
@ -373,6 +374,9 @@ var gotoLink = function(ev) {
/******************************************************************************/
var toggleDynamicFiltering = function(ev) {
if ( uDom('body').hasClass('advancedUser') === false ) {
return;
}
var el = uDom('#panes');
popupData.dfEnabled = !popupData.dfEnabled;
messager.send({

View File

@ -20,15 +20,105 @@
*/
/* global vAPI, uDom */
/******************************************************************************/
(function() {
'use strict';
/******************************************************************************/
uDom.onLoad(function() {
var messager = vAPI.messaging.channel('settings.js');
/******************************************************************************/
var messager = vAPI.messaging.channel('settings.js');
var exportToFile = function() {
var onUserDataReady = function(userData) {
if (!userData) {
return;
}
var now = new Date();
var filename = vAPI.i18n('aboutBackupFilename')
.replace('{{datetime}}', now.toLocaleString())
.replace(/ +/g, '_');
vAPI.download({
'url': 'data:text/plain;charset=utf-8,' + encodeURIComponent(JSON.stringify(userData, null, ' ')),
'filename': filename
});
};
messager.send({ what: 'getUserData' }, onUserDataReady);
};
/******************************************************************************/
var handleImportFilePicker = function() {
var fileReaderOnLoadHandler = function() {
var userData;
try {
userData = JSON.parse(this.result);
if ( typeof userData !== 'object' ) {
throw 'Invalid';
}
if ( typeof userData.userSettings !== 'object' ) {
throw 'Invalid';
}
if ( typeof userData.netWhitelist !== 'string' ) {
throw 'Invalid';
}
if ( typeof userData.filterLists !== 'object' ) {
throw 'Invalid';
}
}
catch (e) {
userData = undefined;
}
if ( userData === undefined ) {
window.alert(vAPI.i18n('aboutRestoreDataError'));
return;
}
var time = new Date(userData.timeStamp);
var msg = vAPI.i18n('aboutRestoreDataConfirm')
.replace('{{time}}', time.toLocaleString());
var proceed = window.confirm(msg);
if ( proceed ) {
messager.send({ what: 'restoreUserData', userData: userData });
}
};
var file = this.files[0];
if ( file === undefined || file.name === '' ) {
return;
}
if ( file.type.indexOf('text') !== 0 ) {
return;
}
var fr = new FileReader();
fr.onload = fileReaderOnLoadHandler;
fr.readAsText(file);
};
/******************************************************************************/
var startImportFilePicker = function() {
var input = document.getElementById('restoreFilePicker');
// Reset to empty string, this will ensure an change event is properly
// triggered if the user pick a file, even if it is the same as the last
// one picked.
input.value = '';
input.click();
};
/******************************************************************************/
var resetUserData = function() {
var msg = vAPI.i18n('aboutResetDataConfirm');
var proceed = window.confirm(msg);
if ( proceed ) {
messager.send({ what: 'resetUserData' });
}
};
/******************************************************************************/
@ -63,15 +153,30 @@ var onUserSettingsReceived = function(details) {
changeUserSettings('contextMenuEnabled', this.checked);
});
uDom('#advanced-user-enabled')
.prop('checked', details.advancedUserEnabled === true)
.on('change', function(){
changeUserSettings('advancedUserEnabled', this.checked);
});
uDom('#experimental-enabled')
.prop('checked', details.experimentalEnabled === true)
.on('change', function(){
changeUserSettings('experimentalEnabled', this.checked);
});
};
messager.send({ what: 'userSettings' }, onUserSettingsReceived);
uDom('#export').on('click', exportToFile);
uDom('#import').on('click', startImportFilePicker);
uDom('#reset').on('click', resetUserData);
uDom('#restoreFilePicker').on('change', handleImportFilePicker);
};
/******************************************************************************/
uDom.onLoad(function() {
messager.send({ what: 'userSettings' }, onUserSettingsReceived);
});
/******************************************************************************/
})();

View File

@ -670,11 +670,14 @@
µb.dynamicNetFilteringEngine.fromObsoleteSelfie(settings.dynamicFilteringSelfie);
µb.userSettings.dynamicFilteringString = µb.dynamicNetFilteringEngine.toString();
µb.XAL.keyvalSetOne('dynamicFilteringString', µb.userSettings.dynamicFilteringString);
// Auto-enable advanced user if there were dynamic rules
µb.userSettings.advancedUserEnabled = true;
µb.XAL.keyvalSetOne('advancedUserEnabled', true);
}
delete µb.userSettings.dynamicFilteringSelfie;
µb.XAL.keyvalRemoveOne('dynamicFilteringSelfie');
}
µb.dynamicNetFilteringEngine.fromString(µb.userSettings.dynamicFilteringString);
};
this.loadUserSettings(onUserSettingsReady);

View File

@ -8,6 +8,7 @@
<style>
ul {
list-style-type: none;
padding-left: 1em;
}
#experimental-enabled {
margin-top: 1em;
@ -21,9 +22,21 @@ ul {
<li><input id="collapse-blocked" type="checkbox"><label data-i18n="settingsCollapseBlockedPrompt" for="collapse-blocked"></label>
<li><input id="icon-badge" type="checkbox"><label data-i18n="settingsIconBadgePrompt" for="icon-badge"></label>
<li><input id="context-menu-enabled" type="checkbox"><label data-i18n="settingsContextMenuPrompt" for="context-menu-enabled"></label>
<li><input id="advanced-user-enabled" type="checkbox"><label data-i18n="settingsAdvancedUserPrompt" for="advanced-user-enabled"></label>
<li><input id="experimental-enabled" type="checkbox"><label data-i18n="settingsExperimentalPrompt" for="experimental-enabled"></label>
</ul>
<div style="margin:3em 0;border-top:1px solid #ccc;"></div>
<div style="margin:1em 0 0 1em;">
<p><button type="button" id="export" data-i18n="aboutBackupDataButton"></button>&ensp;
<button type="button" id="import" data-i18n="aboutRestoreDataButton"></button>
<input id="restoreFilePicker" type="file" accept="text/plain" class="hiddenFileInput">
<p>
<p><button type="button" id="reset" data-i18n="aboutResetDataButton"></button>
</div>
<script src="js/vapi-common.js"></script>
<script src="js/vapi-client.js"></script>
<script src="js/udom.js"></script>