From 881e8111d87b45b3dc9f01a7f59bad20b25a313a Mon Sep 17 00:00:00 2001 From: gorhill Date: Tue, 6 Jan 2015 11:44:06 -0500 Subject: [PATCH] "advanced user" flag + rearranging a bit dashboard --- src/_locales/en/messages.json | 4 ++ src/about.html | 10 --- src/css/common.css | 4 +- src/css/popup.css | 45 +------------- src/dashboard.html | 2 +- src/js/about.js | 93 ---------------------------- src/js/background.js | 1 + src/js/dashboard.js | 2 +- src/js/messaging.js | 21 ++++--- src/js/pagestore.js | 10 +-- src/js/popup.js | 24 +++++--- src/js/settings.js | 113 ++++++++++++++++++++++++++++++++-- src/js/storage.js | 5 +- src/settings.html | 13 ++++ 14 files changed, 169 insertions(+), 178 deletions(-) diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 7039432f5..bdf681359 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -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 (About<\/a>)", + "description":"English: " + }, "settingsExperimentalPrompt":{ "message":"Enable experimental features (About<\/a>)", "description":"English: Enable experimental features" diff --git a/src/about.html b/src/about.html index 9413ab921..77a8361ea 100644 --- a/src/about.html +++ b/src/about.html @@ -22,16 +22,6 @@ -
- -
-

- - -

-

-

- diff --git a/src/css/common.css b/src/css/common.css index 0fd5e8096..93fcd65db 100644 --- a/src/css/common.css +++ b/src/css/common.css @@ -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%; diff --git a/src/css/popup.css b/src/css/popup.css index cb0ac5e61..5d67f4974 100644 --- a/src/css/popup.css +++ b/src/css/popup.css @@ -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; - } \ No newline at end of file diff --git a/src/dashboard.html b/src/dashboard.html index 4c36f6270..ac7e5a653 100644 --- a/src/dashboard.html +++ b/src/dashboard.html @@ -11,11 +11,11 @@
+ -
diff --git a/src/js/about.js b/src/js/about.js index 2e2c5c722..66155c657 100644 --- a/src/js/about.js +++ b/src/js/about.js @@ -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); diff --git a/src/js/background.js b/src/js/background.js index 4a98ab101..4306d65b9 100644 --- a/src/js/background.js +++ b/src/js/background.js @@ -52,6 +52,7 @@ var defaultExternalLists = [ return { userSettings: { + advancedUserEnabled: false, autoUpdate: true, collapseBlocked: true, contextMenuEnabled: true, diff --git a/src/js/dashboard.js b/src/js/dashboard.js index 6779f2735..ba916e2ca 100644 --- a/src/js/dashboard.js +++ b/src/js/dashboard.js @@ -59,7 +59,7 @@ uDom.onLoad(function() { } } if ( !tab ) { - tab = '3p-filters'; + tab = 'settings'; } loadDashboardPanel(tab + '.html', q); uDom('.tabButton').on('click', onTabClickHandler); diff --git a/src/js/messaging.js b/src/js/messaging.js index aa95a7e0f..90ec132d4 100644 --- a/src/js/messaging.js +++ b/src/js/messaging.js @@ -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); /******************************************************************************/ diff --git a/src/js/pagestore.js b/src/js/pagestore.js index 24cb3ecb4..f5f52bf7e 100644 --- a/src/js/pagestore.js +++ b/src/js/pagestore.js @@ -615,10 +615,12 @@ 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. - var df = µb.dynamicNetFilteringEngine.clearRegisters(); - df.evaluateCellZY(context.rootHostname, context.requestHostname, context.requestType); - if ( df.mustBlockOrAllow() ) { - result = df.toFilterString(); + 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 diff --git a/src/js/popup.js b/src/js/popup.js index 0d706bbe8..48775f499 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -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 + // - `http` or `https` scheme uDom('#gotoLog').toggleClass('enabled', isHTTP); // Conditions for element picker: - // - `http` or `https` scheme - uDom('#gotoPick').toggleClass( - 'enabled', - isHTTP - ); + // - `http` or `https` scheme + uDom('#gotoPick').toggleClass('enabled', isHTTP); var or = vAPI.i18n('popupOr'); var blocked = popupData.pageBlockedRequestCount; @@ -289,15 +290,15 @@ var renderPopup = function() { '%' ); } + 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({ diff --git a/src/js/settings.js b/src/js/settings.js index acd162508..cf9981b2f 100644 --- a/src/js/settings.js +++ b/src/js/settings.js @@ -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); }); + +/******************************************************************************/ + +})(); diff --git a/src/js/storage.js b/src/js/storage.js index 044ec8625..b98a67cdc 100644 --- a/src/js/storage.js +++ b/src/js/storage.js @@ -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); diff --git a/src/settings.html b/src/settings.html index 242370e09..fa5fb1e2b 100644 --- a/src/settings.html +++ b/src/settings.html @@ -8,6 +8,7 @@