mirror of
https://github.com/gorhill/uBlock.git
synced 2024-09-04 10:09:38 +02:00
fix #2264
This commit is contained in:
parent
251bbe0f43
commit
6e458dca5c
@ -5,12 +5,36 @@ div > p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
#whitelist {
|
||||
box-sizing: border-box;
|
||||
border: 1px solid gray;
|
||||
height: 60vh;
|
||||
text-align: left;
|
||||
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;
|
||||
white-space: pre;
|
||||
width: 100%;
|
||||
}
|
||||
#whitelist.bad {
|
||||
background-color: #fee;
|
||||
}
|
||||
#whitelist textarea + div {
|
||||
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();
|
||||
break;
|
||||
|
||||
case 'validateWhitelistString':
|
||||
response = µb.validateWhitelistString(request.raw);
|
||||
break;
|
||||
|
||||
case 'writeHiddenSettings':
|
||||
µb.hiddenSettingsFromString(request.content);
|
||||
break;
|
||||
|
@ -194,9 +194,7 @@ var matchBucket = function(url, hostname, bucket, start) {
|
||||
|
||||
µBlock.whitelistFromString = function(s) {
|
||||
var whitelist = Object.create(null),
|
||||
reInvalidHostname = /[^a-z0-9.\-\[\]:]/,
|
||||
reHostnameExtractor = /([a-z0-9\[][a-z0-9.\-]*[a-z0-9\]])(?::[\d*]+)?\/(?:[^\x00-\x20\/]|$)[^\x00-\x20]*$/,
|
||||
lines = s.split(/[\n\r]+/),
|
||||
lineIter = new this.LineIterator(s),
|
||||
line, matches, key, directive, re;
|
||||
|
||||
// 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.
|
||||
directiveToRegexpMap.clear();
|
||||
|
||||
for ( var i = 0; i < lines.length; i++ ) {
|
||||
line = lines[i].trim();
|
||||
while ( !lineIter.eot() ) {
|
||||
line = lineIter.next().trim();
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/171
|
||||
// Skip empty lines
|
||||
if ( line === '' ) {
|
||||
@ -228,7 +227,7 @@ var matchBucket = function(url, hostname, bucket, start) {
|
||||
}
|
||||
}
|
||||
// Regex-based (ensure it is valid)
|
||||
else if ( line.startsWith('/') && line.endsWith('/') ) {
|
||||
else if ( line.length > 2 && line.startsWith('/') && line.endsWith('/') ) {
|
||||
key = '//';
|
||||
directive = line;
|
||||
try {
|
||||
@ -267,6 +266,28 @@ var matchBucket = function(url, hostname, bucket, start) {
|
||||
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 cachedWhitelist = '';
|
||||
|
||||
// Could make it more fancy if needed. But speed... It's a compromise.
|
||||
var reUnwantedChars = /[\x00-\x09\x0b\x0c\x0e-\x1f!"'()<>{}|`~]/;
|
||||
var messaging = vAPI.messaging,
|
||||
cachedWhitelist = '';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var whitelistChanged = function() {
|
||||
var textarea = uDom.nodeFromId('whitelist');
|
||||
var s = textarea.value.trim();
|
||||
var changed = s === cachedWhitelist;
|
||||
var bad = reUnwantedChars.test(s);
|
||||
uDom.nodeFromId('whitelistApply').disabled = changed || bad;
|
||||
uDom.nodeFromId('whitelistRevert').disabled = changed;
|
||||
textarea.classList.toggle('bad', bad);
|
||||
var getTextareaNode = function() {
|
||||
var me = getTextareaNode,
|
||||
node = me.theNode;
|
||||
if ( node === undefined ) {
|
||||
node = me.theNode = uDom.nodeFromSelector('#whitelist textarea');
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
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 onRead = function(whitelist) {
|
||||
cachedWhitelist = whitelist.trim();
|
||||
uDom.nodeFromId('whitelist').value = cachedWhitelist + '\n';
|
||||
getTextareaNode().value = cachedWhitelist + '\n';
|
||||
whitelistChanged();
|
||||
};
|
||||
messaging.send('dashboard', { what: 'getWhitelist' }, onRead);
|
||||
@ -62,8 +100,8 @@ var renderWhitelist = function() {
|
||||
|
||||
var handleImportFilePicker = function() {
|
||||
var fileReaderOnLoadHandler = function() {
|
||||
var textarea = uDom('#whitelist');
|
||||
textarea.val([textarea.val(), this.result].join('\n').trim());
|
||||
var textarea = getTextareaNode();
|
||||
textarea.value = [textarea.value.trim(), this.result.trim()].join('\n').trim();
|
||||
whitelistChanged();
|
||||
};
|
||||
var file = this.files[0];
|
||||
@ -92,10 +130,8 @@ var startImportFilePicker = function() {
|
||||
/******************************************************************************/
|
||||
|
||||
var exportWhitelistToFile = function() {
|
||||
var val = uDom('#whitelist').val().trim();
|
||||
if ( val === '' ) {
|
||||
return;
|
||||
}
|
||||
var val = getTextareaNode().value.trim();
|
||||
if ( val === '' ) { return; }
|
||||
var filename = vAPI.i18n('whitelistExportFilename')
|
||||
.replace('{{datetime}}', uBlockDashboard.dateNowToSensibleString())
|
||||
.replace(/ +/g, '_');
|
||||
@ -108,7 +144,7 @@ var exportWhitelistToFile = function() {
|
||||
/******************************************************************************/
|
||||
|
||||
var applyChanges = function() {
|
||||
cachedWhitelist = uDom.nodeFromId('whitelist').value.trim();
|
||||
cachedWhitelist = getTextareaNode().value.trim();
|
||||
var request = {
|
||||
what: 'setWhitelist',
|
||||
whitelist: cachedWhitelist
|
||||
@ -117,21 +153,21 @@ var applyChanges = function() {
|
||||
};
|
||||
|
||||
var revertChanges = function() {
|
||||
uDom.nodeFromId('whitelist').value = cachedWhitelist + '\n';
|
||||
getTextareaNode().value = cachedWhitelist + '\n';
|
||||
whitelistChanged();
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var getCloudData = function() {
|
||||
return uDom.nodeFromId('whitelist').value;
|
||||
return getTextareaNode().value;
|
||||
};
|
||||
|
||||
var setCloudData = function(data, append) {
|
||||
if ( typeof data !== 'string' ) {
|
||||
return;
|
||||
}
|
||||
var textarea = uDom.nodeFromId('whitelist');
|
||||
var textarea = getTextareaNode();
|
||||
if ( append ) {
|
||||
data = uBlockDashboard.mergeNewLines(textarea.value.trim(), data);
|
||||
}
|
||||
@ -147,7 +183,7 @@ self.cloud.onPull = setCloudData;
|
||||
uDom('#importWhitelistFromFile').on('click', startImportFilePicker);
|
||||
uDom('#importFilePicker').on('change', handleImportFilePicker);
|
||||
uDom('#exportWhitelistToFile').on('click', exportWhitelistToFile);
|
||||
uDom('#whitelist').on('input', whitelistChanged);
|
||||
uDom('#whitelist textarea').on('input', whitelistChanged);
|
||||
uDom('#whitelistApply').on('click', applyChanges);
|
||||
uDom('#whitelistRevert').on('click', revertChanges);
|
||||
|
||||
|
@ -17,7 +17,10 @@
|
||||
<p>
|
||||
<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>
|
||||
<p><textarea id="whitelist" dir="auto" spellcheck="false"></textarea>
|
||||
<p><section id="whitelist">
|
||||
<textarea dir="auto" spellcheck="false"></textarea>
|
||||
<div>E</div>
|
||||
</section>
|
||||
<p>
|
||||
<button id="importWhitelistFromFile" class="custom" data-i18n="whitelistImport"></button> 
|
||||
<button id="exportWhitelistToFile" class="custom" data-i18n="whitelistExport"></button>
|
||||
|
Loading…
Reference in New Issue
Block a user