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
This commit is contained in:
Raymond Hill 2020-04-28 11:07:00 -04:00
parent 578594bbd7
commit d462b50cec
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
4 changed files with 86 additions and 56 deletions

View File

@ -27,8 +27,6 @@
<script src="lib/codemirror/lib/codemirror.js"></script>
<script src="lib/codemirror/addon/selection/active-line.js"></script>
<script src="js/codemirror/mode/raw-settings.js"></script>
<script src="js/vapi.js"></script>
<script src="js/vapi-common.js"></script>
<script src="js/vapi-client.js"></script>

View File

@ -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
})();
}

View File

@ -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;
}
};
});

View File

@ -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':