From d462b50cec2884c8565a52c5fdc1d377cf691dcf Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Tue, 28 Apr 2020 11:07:00 -0400 Subject: [PATCH] Improve presentation of advanced settings page Specifically: - Fix exception being thrown when createing an empty line - Syntax-color invalid setting names - Syntax-color non-default values --- src/advanced-settings.html | 2 - src/js/advanced-settings.js | 98 +++++++++++++++++++++----- src/js/codemirror/mode/raw-settings.js | 37 ---------- src/js/messaging.js | 5 +- 4 files changed, 86 insertions(+), 56 deletions(-) delete mode 100644 src/js/codemirror/mode/raw-settings.js diff --git a/src/advanced-settings.html b/src/advanced-settings.html index 564ae99dc..5afb9a0d9 100644 --- a/src/advanced-settings.html +++ b/src/advanced-settings.html @@ -27,8 +27,6 @@ - - diff --git a/src/js/advanced-settings.js b/src/js/advanced-settings.js index 6d993e1ed..2b41f80b6 100644 --- a/src/js/advanced-settings.js +++ b/src/js/advanced-settings.js @@ -25,15 +25,49 @@ /******************************************************************************/ -(( ) => { +{ // >>>> Start of private namespace /******************************************************************************/ -const noopFunc = function(){}; - +let defaultSettings = new Map(); let beforeHash = ''; +/******************************************************************************/ + +CodeMirror.defineMode('raw-settings', function() { + let lastSetting = ''; + + return { + token: function(stream) { + if ( stream.sol() ) { + const match = stream.match(/\s*\S+/); + if ( match !== null ) { + lastSetting = match[0].trim(); + if ( defaultSettings.has(lastSetting) ) { + return 'keyword'; + } + } + lastSetting = ''; + stream.skipToEnd(); + return 'error'; + } + if ( lastSetting !== '' ) { + stream.eatSpace(); + const match = stream.match(/\S+.*$/); + if ( match !== null ) { + if ( match[0] !== defaultSettings.get(lastSetting) ) { + return 'strong'; + } + } + lastSetting = ''; + } + stream.skipToEnd(); + return null; + } + }; +}); + const cmEditor = new CodeMirror( document.getElementById('advancedSettings'), { @@ -49,7 +83,41 @@ uBlockDashboard.patchCodeMirrorEditor(cmEditor); /******************************************************************************/ const hashFromAdvancedSettings = function(raw) { - return raw.trim().replace(/\s*[\n\r]+\s*/g, '\n').replace(/[ \t]+/g, ' '); + const aa = typeof raw === 'string' + ? arrayFromString(raw) + : arrayFromObject(raw); + aa.sort((a, b) => a[0].localeCompare(b[0])); + return JSON.stringify(aa); +}; + +/******************************************************************************/ + +const arrayFromObject = function(o) { + const out = []; + for ( const k in o ) { + if ( o.hasOwnProperty(k) === false ) { continue; } + out.push([ k, `${o[k]}` ]); + } + return out; +}; + +const arrayFromString = function(s) { + const out = []; + for ( let line of s.split(/[\n\r]+/) ) { + line = line.trim(); + if ( line === '' ) { continue; } + const pos = line.indexOf(' '); + let k, v; + if ( pos !== -1 ) { + k = line.slice(0, pos); + v = line.slice(pos + 1); + } else { + k = line; + v = ''; + } + out.push([ k.trim(), v.trim() ]); + } + return out; }; /******************************************************************************/ @@ -64,7 +132,7 @@ const advancedSettingsChanged = (( ) => { const changed = hashFromAdvancedSettings(cmEditor.getValue()) !== beforeHash; uDom.nodeFromId('advancedSettingsApply').disabled = !changed; - CodeMirror.commands.save = changed ? applyChanges : noopFunc; + CodeMirror.commands.save = changed ? applyChanges : function(){}; }; return function() { @@ -78,21 +146,19 @@ cmEditor.on('changes', advancedSettingsChanged); /******************************************************************************/ const renderAdvancedSettings = async function(first) { - const raw = await vAPI.messaging.send('dashboard', { + const details = await vAPI.messaging.send('dashboard', { what: 'readHiddenSettings', }); - - beforeHash = hashFromAdvancedSettings(raw); + defaultSettings = new Map(arrayFromObject(details.default)); + beforeHash = hashFromAdvancedSettings(details.current); const pretty = []; - const lines = raw.split('\n'); + const entries = arrayFromObject(details.current); let max = 0; - for ( const line of lines ) { - const pos = line.indexOf(' '); - if ( pos > max ) { max = pos; } + for ( const [ k ] of entries ) { + if ( k.length > max ) { max = k.length; } } - for ( const line of lines ) { - const pos = line.indexOf(' '); - pretty.push(' '.repeat(max - pos) + line); + for ( const [ k, v ] of entries ) { + pretty.push(' '.repeat(max - k.length) + `${k} ${v}`); } pretty.push(''); cmEditor.setValue(pretty.join('\n')); @@ -128,4 +194,4 @@ renderAdvancedSettings(true); /******************************************************************************/ // <<<< End of private namespace -})(); +} diff --git a/src/js/codemirror/mode/raw-settings.js b/src/js/codemirror/mode/raw-settings.js deleted file mode 100644 index 34585d99c..000000000 --- a/src/js/codemirror/mode/raw-settings.js +++ /dev/null @@ -1,37 +0,0 @@ -/******************************************************************************* - - uBlock Origin - a browser extension to block requests. - Copyright (C) 2019-present Raymond Hill - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see {http://www.gnu.org/licenses/}. - - Home: https://github.com/gorhill/uBlock -*/ - -/* global CodeMirror */ - -'use strict'; - -CodeMirror.defineMode("raw-settings", function() { - return { - token: function(stream) { - if ( stream.sol() ) { - stream.match(/\s*\S+/); - return 'keyword'; - } - stream.skipToEnd(); - return null; - } - }; -}); diff --git a/src/js/messaging.js b/src/js/messaging.js index 92c897917..1561346bd 100644 --- a/src/js/messaging.js +++ b/src/js/messaging.js @@ -1163,7 +1163,10 @@ const onMessage = function(request, sender, callback) { break; case 'readHiddenSettings': - response = µb.stringFromHiddenSettings(); + response = { + current: µb.hiddenSettings, + default: µb.hiddenSettingsDefault, + }; break; case 'restoreUserData':