mirror of https://github.com/gorhill/uBlock.git
fix #2264
This commit is contained in:
parent
251bbe0f43
commit
6e458dca5c
|
@ -5,12 +5,36 @@ div > p:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
#whitelist {
|
#whitelist {
|
||||||
box-sizing: border-box;
|
border: 1px solid gray;
|
||||||
height: 60vh;
|
height: 60vh;
|
||||||
|
margin: 0;
|
||||||
|
padding: 1px;
|
||||||
|
position: relative;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
#whitelist.invalid {
|
||||||
|
border-color: red;
|
||||||
|
}
|
||||||
|
#whitelist textarea {
|
||||||
|
border: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0.4em;
|
||||||
|
resize: none;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
#whitelist.bad {
|
#whitelist textarea + div {
|
||||||
background-color: #fee;
|
background-color: red;
|
||||||
}
|
bottom: 0;
|
||||||
|
color: white;
|
||||||
|
display: none;
|
||||||
|
padding: 2px 4px;
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
#whitelist.invalid textarea + div {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
|
@ -1011,6 +1011,10 @@ var onMessage = function(request, sender, callback) {
|
||||||
response = getRules();
|
response = getRules();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'validateWhitelistString':
|
||||||
|
response = µb.validateWhitelistString(request.raw);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'writeHiddenSettings':
|
case 'writeHiddenSettings':
|
||||||
µb.hiddenSettingsFromString(request.content);
|
µb.hiddenSettingsFromString(request.content);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -194,9 +194,7 @@ var matchBucket = function(url, hostname, bucket, start) {
|
||||||
|
|
||||||
µBlock.whitelistFromString = function(s) {
|
µBlock.whitelistFromString = function(s) {
|
||||||
var whitelist = Object.create(null),
|
var whitelist = Object.create(null),
|
||||||
reInvalidHostname = /[^a-z0-9.\-\[\]:]/,
|
lineIter = new this.LineIterator(s),
|
||||||
reHostnameExtractor = /([a-z0-9\[][a-z0-9.\-]*[a-z0-9\]])(?::[\d*]+)?\/(?:[^\x00-\x20\/]|$)[^\x00-\x20]*$/,
|
|
||||||
lines = s.split(/[\n\r]+/),
|
|
||||||
line, matches, key, directive, re;
|
line, matches, key, directive, re;
|
||||||
|
|
||||||
// Comment bucket must always be ready to be used.
|
// Comment bucket must always be ready to be used.
|
||||||
|
@ -205,8 +203,9 @@ var matchBucket = function(url, hostname, bucket, start) {
|
||||||
// New set of directives, scrap cached data.
|
// New set of directives, scrap cached data.
|
||||||
directiveToRegexpMap.clear();
|
directiveToRegexpMap.clear();
|
||||||
|
|
||||||
for ( var i = 0; i < lines.length; i++ ) {
|
while ( !lineIter.eot() ) {
|
||||||
line = lines[i].trim();
|
line = lineIter.next().trim();
|
||||||
|
|
||||||
// https://github.com/gorhill/uBlock/issues/171
|
// https://github.com/gorhill/uBlock/issues/171
|
||||||
// Skip empty lines
|
// Skip empty lines
|
||||||
if ( line === '' ) {
|
if ( line === '' ) {
|
||||||
|
@ -228,7 +227,7 @@ var matchBucket = function(url, hostname, bucket, start) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Regex-based (ensure it is valid)
|
// Regex-based (ensure it is valid)
|
||||||
else if ( line.startsWith('/') && line.endsWith('/') ) {
|
else if ( line.length > 2 && line.startsWith('/') && line.endsWith('/') ) {
|
||||||
key = '//';
|
key = '//';
|
||||||
directive = line;
|
directive = line;
|
||||||
try {
|
try {
|
||||||
|
@ -267,6 +266,28 @@ var matchBucket = function(url, hostname, bucket, start) {
|
||||||
return whitelist;
|
return whitelist;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
µBlock.validateWhitelistString = function(s) {
|
||||||
|
var lineIter = new this.LineIterator(s), line;
|
||||||
|
while ( !lineIter.eot() ) {
|
||||||
|
line = lineIter.next().trim();
|
||||||
|
if ( line === '' ) { continue; }
|
||||||
|
if ( line.startsWith('#') ) { continue; } // Comment
|
||||||
|
if ( line.indexOf('/') === -1 ) { // Plain hostname
|
||||||
|
if ( reInvalidHostname.test(line) ) { return false; }
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( line.length > 2 && line.startsWith('/') && line.endsWith('/') ) { // Regex-based
|
||||||
|
try { new RegExp(line.slice(1, -1)); } catch(ex) { return false; }
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( reHostnameExtractor.test(line) === false ) { return false; } // URL
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
var reInvalidHostname = /[^a-z0-9.\-\[\]:]/,
|
||||||
|
reHostnameExtractor = /([a-z0-9\[][a-z0-9.\-]*[a-z0-9\]])(?::[\d*]+)?\/(?:[^\x00-\x20\/]|$)[^\x00-\x20]*$/;
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -29,30 +29,68 @@
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var messaging = vAPI.messaging;
|
var messaging = vAPI.messaging,
|
||||||
var cachedWhitelist = '';
|
cachedWhitelist = '';
|
||||||
|
|
||||||
// Could make it more fancy if needed. But speed... It's a compromise.
|
|
||||||
var reUnwantedChars = /[\x00-\x09\x0b\x0c\x0e-\x1f!"'()<>{}|`~]/;
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var whitelistChanged = function() {
|
var getTextareaNode = function() {
|
||||||
var textarea = uDom.nodeFromId('whitelist');
|
var me = getTextareaNode,
|
||||||
var s = textarea.value.trim();
|
node = me.theNode;
|
||||||
var changed = s === cachedWhitelist;
|
if ( node === undefined ) {
|
||||||
var bad = reUnwantedChars.test(s);
|
node = me.theNode = uDom.nodeFromSelector('#whitelist textarea');
|
||||||
uDom.nodeFromId('whitelistApply').disabled = changed || bad;
|
}
|
||||||
uDom.nodeFromId('whitelistRevert').disabled = changed;
|
return node;
|
||||||
textarea.classList.toggle('bad', bad);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var setErrorNodeHorizontalOffset = function(px) {
|
||||||
|
var me = setErrorNodeHorizontalOffset,
|
||||||
|
offset = me.theOffset || 0;
|
||||||
|
if ( px === offset ) { return; }
|
||||||
|
var node = me.theNode;
|
||||||
|
if ( node === undefined ) {
|
||||||
|
node = me.theNode = uDom.nodeFromSelector('#whitelist textarea + div');
|
||||||
|
}
|
||||||
|
node.style.right = px + 'px';
|
||||||
|
me.theOffset = px;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var whitelistChanged = (function() {
|
||||||
|
var changedWhitelist, changed, timer;
|
||||||
|
|
||||||
|
var updateUI = function(good) {
|
||||||
|
uDom.nodeFromId('whitelistApply').disabled = changed || !good;
|
||||||
|
uDom.nodeFromId('whitelistRevert').disabled = changed;
|
||||||
|
uDom.nodeFromId('whitelist').classList.toggle('invalid', !good);
|
||||||
|
};
|
||||||
|
|
||||||
|
var validate = function() {
|
||||||
|
timer = undefined;
|
||||||
|
messaging.send(
|
||||||
|
'dashboard',
|
||||||
|
{ what: 'validateWhitelistString', raw: changedWhitelist },
|
||||||
|
updateUI
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return function() {
|
||||||
|
changedWhitelist = getTextareaNode().value.trim();
|
||||||
|
changed = changedWhitelist === cachedWhitelist;
|
||||||
|
if ( timer !== undefined ) { clearTimeout(timer); }
|
||||||
|
timer = vAPI.setTimeout(validate, 251);
|
||||||
|
var textarea = getTextareaNode();
|
||||||
|
setErrorNodeHorizontalOffset(textarea.offsetWidth - textarea.clientWidth);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var renderWhitelist = function() {
|
var renderWhitelist = function() {
|
||||||
var onRead = function(whitelist) {
|
var onRead = function(whitelist) {
|
||||||
cachedWhitelist = whitelist.trim();
|
cachedWhitelist = whitelist.trim();
|
||||||
uDom.nodeFromId('whitelist').value = cachedWhitelist + '\n';
|
getTextareaNode().value = cachedWhitelist + '\n';
|
||||||
whitelistChanged();
|
whitelistChanged();
|
||||||
};
|
};
|
||||||
messaging.send('dashboard', { what: 'getWhitelist' }, onRead);
|
messaging.send('dashboard', { what: 'getWhitelist' }, onRead);
|
||||||
|
@ -62,8 +100,8 @@ var renderWhitelist = function() {
|
||||||
|
|
||||||
var handleImportFilePicker = function() {
|
var handleImportFilePicker = function() {
|
||||||
var fileReaderOnLoadHandler = function() {
|
var fileReaderOnLoadHandler = function() {
|
||||||
var textarea = uDom('#whitelist');
|
var textarea = getTextareaNode();
|
||||||
textarea.val([textarea.val(), this.result].join('\n').trim());
|
textarea.value = [textarea.value.trim(), this.result.trim()].join('\n').trim();
|
||||||
whitelistChanged();
|
whitelistChanged();
|
||||||
};
|
};
|
||||||
var file = this.files[0];
|
var file = this.files[0];
|
||||||
|
@ -92,10 +130,8 @@ var startImportFilePicker = function() {
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var exportWhitelistToFile = function() {
|
var exportWhitelistToFile = function() {
|
||||||
var val = uDom('#whitelist').val().trim();
|
var val = getTextareaNode().value.trim();
|
||||||
if ( val === '' ) {
|
if ( val === '' ) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
var filename = vAPI.i18n('whitelistExportFilename')
|
var filename = vAPI.i18n('whitelistExportFilename')
|
||||||
.replace('{{datetime}}', uBlockDashboard.dateNowToSensibleString())
|
.replace('{{datetime}}', uBlockDashboard.dateNowToSensibleString())
|
||||||
.replace(/ +/g, '_');
|
.replace(/ +/g, '_');
|
||||||
|
@ -108,7 +144,7 @@ var exportWhitelistToFile = function() {
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var applyChanges = function() {
|
var applyChanges = function() {
|
||||||
cachedWhitelist = uDom.nodeFromId('whitelist').value.trim();
|
cachedWhitelist = getTextareaNode().value.trim();
|
||||||
var request = {
|
var request = {
|
||||||
what: 'setWhitelist',
|
what: 'setWhitelist',
|
||||||
whitelist: cachedWhitelist
|
whitelist: cachedWhitelist
|
||||||
|
@ -117,21 +153,21 @@ var applyChanges = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
var revertChanges = function() {
|
var revertChanges = function() {
|
||||||
uDom.nodeFromId('whitelist').value = cachedWhitelist + '\n';
|
getTextareaNode().value = cachedWhitelist + '\n';
|
||||||
whitelistChanged();
|
whitelistChanged();
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var getCloudData = function() {
|
var getCloudData = function() {
|
||||||
return uDom.nodeFromId('whitelist').value;
|
return getTextareaNode().value;
|
||||||
};
|
};
|
||||||
|
|
||||||
var setCloudData = function(data, append) {
|
var setCloudData = function(data, append) {
|
||||||
if ( typeof data !== 'string' ) {
|
if ( typeof data !== 'string' ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var textarea = uDom.nodeFromId('whitelist');
|
var textarea = getTextareaNode();
|
||||||
if ( append ) {
|
if ( append ) {
|
||||||
data = uBlockDashboard.mergeNewLines(textarea.value.trim(), data);
|
data = uBlockDashboard.mergeNewLines(textarea.value.trim(), data);
|
||||||
}
|
}
|
||||||
|
@ -147,7 +183,7 @@ self.cloud.onPull = setCloudData;
|
||||||
uDom('#importWhitelistFromFile').on('click', startImportFilePicker);
|
uDom('#importWhitelistFromFile').on('click', startImportFilePicker);
|
||||||
uDom('#importFilePicker').on('change', handleImportFilePicker);
|
uDom('#importFilePicker').on('change', handleImportFilePicker);
|
||||||
uDom('#exportWhitelistToFile').on('click', exportWhitelistToFile);
|
uDom('#exportWhitelistToFile').on('click', exportWhitelistToFile);
|
||||||
uDom('#whitelist').on('input', whitelistChanged);
|
uDom('#whitelist textarea').on('input', whitelistChanged);
|
||||||
uDom('#whitelistApply').on('click', applyChanges);
|
uDom('#whitelistApply').on('click', applyChanges);
|
||||||
uDom('#whitelistRevert').on('click', revertChanges);
|
uDom('#whitelistRevert').on('click', revertChanges);
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,10 @@
|
||||||
<p>
|
<p>
|
||||||
<button id="whitelistApply" class="custom important" type="button" disabled="true" data-i18n="whitelistApply"></button> 
|
<button id="whitelistApply" class="custom important" type="button" disabled="true" data-i18n="whitelistApply"></button> 
|
||||||
<button id="whitelistRevert" class="custom" type="button" disabled="true" data-i18n="genericRevert"></button>
|
<button id="whitelistRevert" class="custom" type="button" disabled="true" data-i18n="genericRevert"></button>
|
||||||
<p><textarea id="whitelist" dir="auto" spellcheck="false"></textarea>
|
<p><section id="whitelist">
|
||||||
|
<textarea dir="auto" spellcheck="false"></textarea>
|
||||||
|
<div>E</div>
|
||||||
|
</section>
|
||||||
<p>
|
<p>
|
||||||
<button id="importWhitelistFromFile" class="custom" data-i18n="whitelistImport"></button> 
|
<button id="importWhitelistFromFile" class="custom" data-i18n="whitelistImport"></button> 
|
||||||
<button id="exportWhitelistToFile" class="custom" data-i18n="whitelistExport"></button>
|
<button id="exportWhitelistToFile" class="custom" data-i18n="whitelistExport"></button>
|
||||||
|
|
Loading…
Reference in New Issue