mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-11 09:31:01 +01:00
add ability to filter out rules in "My rules" pane
This commit is contained in:
parent
4f2d071137
commit
6871d9aed4
5 changed files with 140 additions and 57 deletions
|
@ -34,7 +34,7 @@ body {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
margin: 0.5em 0;
|
margin: 0.5em 0;
|
||||||
}
|
}
|
||||||
#diff .ruleFilter {
|
#ruleFilter {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
body[dir="ltr"] #revertButton:after {
|
body[dir="ltr"] #revertButton:after {
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>uBlock — Dynamic filtering rules</title>
|
<title>uBlock — Dynamic filtering rules</title>
|
||||||
<link rel="stylesheet" type="text/css" href="lib/codemirror/lib/codemirror.css">
|
<link rel="stylesheet" type="text/css" href="lib/codemirror/lib/codemirror.css">
|
||||||
<link rel="stylesheet" type="text/css" href="lib/codemirror/addon/dialog/dialog.css">
|
|
||||||
<link rel="stylesheet" type="text/css" href="lib/codemirror/addon/merge/merge.css">
|
<link rel="stylesheet" type="text/css" href="lib/codemirror/addon/merge/merge.css">
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="css/common.css">
|
<link rel="stylesheet" type="text/css" href="css/common.css">
|
||||||
|
@ -33,7 +32,7 @@
|
||||||
<button type="button" class="custom" id="importButton" data-i18n="rulesImport"></button>
|
<button type="button" class="custom" id="importButton" data-i18n="rulesImport"></button>
|
||||||
<button type="button" class="custom" id="editSaveButton" data-i18n="rulesEditSave"></button>
|
<button type="button" class="custom" id="editSaveButton" data-i18n="rulesEditSave"></button>
|
||||||
</div>
|
</div>
|
||||||
<!-- TO BE IMPLEMENTED: <div class="ruleFilter"><span class="fa"></span> <input type="text" size="32"></div> -->
|
<div id="ruleFilter"><span class="fa"></span> <input type="text" size="32"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="codeMirrorContainer codeMirrorMergeContainer"></div>
|
<div class="codeMirrorContainer codeMirrorMergeContainer"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
|
|
||||||
var searchWidgetHtml =
|
var searchWidgetHtml =
|
||||||
'<div class="cm-search-widget">' +
|
'<div class="cm-search-widget">' +
|
||||||
'<span class="fa"></span> ' +
|
'<span class="fa"></span> ' +
|
||||||
'<span>' +
|
'<span>' +
|
||||||
'<input type="text" size="32">' +
|
'<input type="text" size="32">' +
|
||||||
'<span class="cm-search-widget-count">' +
|
'<span class="cm-search-widget-count">' +
|
||||||
|
|
|
@ -36,6 +36,7 @@ var mergeView = new CodeMirror.MergeView(
|
||||||
{
|
{
|
||||||
allowEditingOriginals: true,
|
allowEditingOriginals: true,
|
||||||
connect: 'align',
|
connect: 'align',
|
||||||
|
inputStyle: 'contenteditable',
|
||||||
lineNumbers: true,
|
lineNumbers: true,
|
||||||
lineWrapping: false,
|
lineWrapping: false,
|
||||||
origLeft: '',
|
origLeft: '',
|
||||||
|
@ -47,46 +48,111 @@ mergeView.editor().setOption('styleActiveLine', true);
|
||||||
mergeView.editor().setOption('lineNumbers', false);
|
mergeView.editor().setOption('lineNumbers', false);
|
||||||
mergeView.leftOriginal().setOption('readOnly', 'nocursor');
|
mergeView.leftOriginal().setOption('readOnly', 'nocursor');
|
||||||
|
|
||||||
var cleanToken = 0;
|
var unfilteredRules = {
|
||||||
|
orig: { doc: mergeView.leftOriginal(), rules: [] },
|
||||||
|
edit: { doc: mergeView.editor(), rules: [] }
|
||||||
|
};
|
||||||
|
|
||||||
|
var cleanEditToken = 0;
|
||||||
var cleanEditText = '';
|
var cleanEditText = '';
|
||||||
|
|
||||||
var differ;
|
var differ;
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// Borrowed from...
|
||||||
|
// https://github.com/codemirror/CodeMirror/blob/3e1bb5fff682f8f6cbfaef0e56c61d62403d4798/addon/search/search.js#L22
|
||||||
|
// ... and modified as needed.
|
||||||
|
|
||||||
|
var updateOverlay = (function() {
|
||||||
|
var reFilter;
|
||||||
|
var mode = {
|
||||||
|
token: function(stream) {
|
||||||
|
if ( reFilter !== undefined ) {
|
||||||
|
reFilter.lastIndex = stream.pos;
|
||||||
|
var match = reFilter.exec(stream.string);
|
||||||
|
if ( match !== null ) {
|
||||||
|
if ( match.index === stream.pos ) {
|
||||||
|
stream.pos += match[0].length || 1;
|
||||||
|
return 'searching';
|
||||||
|
}
|
||||||
|
stream.pos = match.index;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stream.skipToEnd();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return function(filter) {
|
||||||
|
reFilter = typeof filter === 'string' && filter !== '' ?
|
||||||
|
new RegExp(filter.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi') :
|
||||||
|
undefined;
|
||||||
|
return mode;
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
// Incrementally update text in a CodeMirror editor for best user experience:
|
// Incrementally update text in a CodeMirror editor for best user experience:
|
||||||
// - Scroll position preserved
|
// - Scroll position preserved
|
||||||
// - Minimum amount of text updated
|
// - Minimum amount of text updated
|
||||||
|
|
||||||
var rulesToDoc = function(doc, rules) {
|
var rulesToDoc = function(clearHistory) {
|
||||||
if ( doc.getValue() === '' || rules.length === 0 ) {
|
for ( var key in unfilteredRules ) {
|
||||||
doc.setValue(rules.length !== 0 ? rules.join('\n') : '');
|
if ( unfilteredRules.hasOwnProperty(key) === false ) { continue; }
|
||||||
return;
|
var doc = unfilteredRules[key].doc;
|
||||||
}
|
var rules = filterRules(key);
|
||||||
if ( differ === undefined ) { differ = new diff_match_patch(); }
|
if ( doc.lineCount() === 1 && doc.getValue() === '' || rules.length === 0 ) {
|
||||||
var beforeText = doc.getValue();
|
doc.setValue(rules.length !== 0 ? rules.join('\n') : '');
|
||||||
var afterText = rules.join('\n');
|
continue;
|
||||||
var diffs = differ.diff_main(beforeText, afterText);
|
}
|
||||||
doc.startOperation();
|
if ( differ === undefined ) { differ = new diff_match_patch(); }
|
||||||
var i = diffs.length,
|
var beforeText = doc.getValue();
|
||||||
iedit = beforeText.length;
|
var afterText = rules.join('\n');
|
||||||
while ( i-- ) {
|
var diffs = differ.diff_main(beforeText, afterText);
|
||||||
var diff = diffs[i];
|
doc.startOperation();
|
||||||
if ( diff[0] === 0 ) {
|
var i = diffs.length,
|
||||||
|
iedit = beforeText.length;
|
||||||
|
while ( i-- ) {
|
||||||
|
var diff = diffs[i];
|
||||||
|
if ( diff[0] === 0 ) {
|
||||||
|
iedit -= diff[1].length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var end = doc.posFromIndex(iedit);
|
||||||
|
if ( diff[0] === 1 ) {
|
||||||
|
doc.replaceRange(diff[1], end, end);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* diff[0] === -1 */
|
||||||
iedit -= diff[1].length;
|
iedit -= diff[1].length;
|
||||||
continue;
|
var beg = doc.posFromIndex(iedit);
|
||||||
|
doc.replaceRange('', beg, end);
|
||||||
}
|
}
|
||||||
var end = doc.posFromIndex(iedit);
|
doc.endOperation();
|
||||||
if ( diff[0] === 1 ) {
|
|
||||||
doc.replaceRange(diff[1], end, end);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* diff[0] === -1 */
|
|
||||||
iedit -= diff[1].length;
|
|
||||||
var beg = doc.posFromIndex(iedit);
|
|
||||||
doc.replaceRange('', beg, end);
|
|
||||||
}
|
}
|
||||||
doc.endOperation();
|
cleanEditText = mergeView.editor().getValue().trim();
|
||||||
|
cleanEditToken = mergeView.editor().changeGeneration();
|
||||||
|
if ( clearHistory ) {
|
||||||
|
mergeView.editor().clearHistory();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var filterRules = function(key) {
|
||||||
|
var rules = unfilteredRules[key].rules;
|
||||||
|
var filter = uDom('#ruleFilter input').val();
|
||||||
|
if ( filter !== '' ) {
|
||||||
|
rules = rules.slice();
|
||||||
|
var i = rules.length;
|
||||||
|
while ( i-- ) {
|
||||||
|
if ( rules[i].indexOf(filter) === -1 ) {
|
||||||
|
rules.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rules;
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -98,18 +164,16 @@ var renderRules = (function() {
|
||||||
details.hnSwitches.sort();
|
details.hnSwitches.sort();
|
||||||
details.permanentRules.sort();
|
details.permanentRules.sort();
|
||||||
details.sessionRules.sort();
|
details.sessionRules.sort();
|
||||||
var orig = details.hnSwitches.concat(details.permanentRules),
|
unfilteredRules.orig.rules =
|
||||||
edit = details.hnSwitches.concat(details.sessionRules);
|
details.hnSwitches.concat(details.permanentRules);
|
||||||
rulesToDoc(mergeView.leftOriginal(), orig);
|
unfilteredRules.edit.rules =
|
||||||
rulesToDoc(mergeView.editor(), edit);
|
details.hnSwitches.concat(details.sessionRules);
|
||||||
cleanEditText = mergeView.editor().getValue().trim();
|
rulesToDoc(firstVisit);
|
||||||
if ( firstVisit ) {
|
if ( firstVisit ) {
|
||||||
mergeView.editor().clearHistory();
|
|
||||||
firstVisit = false;
|
firstVisit = false;
|
||||||
mergeView.editor().execCommand('goNextDiff');
|
mergeView.editor().execCommand('goNextDiff');
|
||||||
}
|
}
|
||||||
cleanToken = mergeView.editor().changeGeneration();
|
onTextChanged(true);
|
||||||
onChange(true);
|
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
@ -157,19 +221,14 @@ mergeView.options.revertChunk = function(
|
||||||
{ line: toStart.line, ch: 0 },
|
{ line: toStart.line, ch: 0 },
|
||||||
{ line: toEnd.line, ch: 0 }
|
{ line: toEnd.line, ch: 0 }
|
||||||
);
|
);
|
||||||
applyDiff(from === mv.editor(), toAdd, toRemove);
|
applyDiff(from === mv.editor(), toAdd, toRemove, renderRules);
|
||||||
to.replaceRange(toAdd, toStart, toEnd);
|
|
||||||
cleanToken = mergeView.editor().changeGeneration();
|
|
||||||
cleanEditText = mergeView.editor().getValue().trim();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
function handleImportFilePicker() {
|
function handleImportFilePicker() {
|
||||||
var fileReaderOnLoadHandler = function() {
|
var fileReaderOnLoadHandler = function() {
|
||||||
if ( typeof this.result !== 'string' || this.result === '' ) {
|
if ( typeof this.result !== 'string' || this.result === '' ) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/757
|
// https://github.com/chrisaljoudi/uBlock/issues/757
|
||||||
// Support RequestPolicy rule syntax
|
// Support RequestPolicy rule syntax
|
||||||
var result = this.result;
|
var result = this.result;
|
||||||
|
@ -217,41 +276,64 @@ function exportUserRulesToFile() {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
/*
|
var onFilterChanged = (function() {
|
||||||
var onFilter = (function() {
|
var timer,
|
||||||
var timer;
|
overlay = null,
|
||||||
|
last = '';
|
||||||
|
|
||||||
var process = function() {
|
var process = function() {
|
||||||
timer = undefined;
|
timer = undefined;
|
||||||
|
if ( mergeView.editor().isClean(cleanEditToken) === false ) { return; }
|
||||||
|
if ( overlay !== null ) {
|
||||||
|
mergeView.leftOriginal().removeOverlay(overlay);
|
||||||
|
mergeView.editor().removeOverlay(overlay);
|
||||||
|
overlay = null;
|
||||||
|
}
|
||||||
|
var filter = uDom('#ruleFilter input').val();
|
||||||
|
if ( filter === last ) { return; }
|
||||||
|
last = filter;
|
||||||
|
|
||||||
|
if ( filter !== '' ) {
|
||||||
|
overlay = updateOverlay(filter);
|
||||||
|
mergeView.leftOriginal().addOverlay(overlay);
|
||||||
|
mergeView.editor().addOverlay(overlay);
|
||||||
|
}
|
||||||
|
rulesToDoc(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
return function() {
|
return function() {
|
||||||
if ( timer !== undefined ) { clearTimeout(timer); }
|
if ( timer !== undefined ) { clearTimeout(timer); }
|
||||||
timer = vAPI.setTimeout(process, 577);
|
timer = vAPI.setTimeout(process, 773);
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
*/
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var onChange = (function() {
|
var onTextChanged = (function() {
|
||||||
var timer;
|
var timer;
|
||||||
|
|
||||||
var process = function(now) {
|
var process = function(now) {
|
||||||
timer = undefined;
|
timer = undefined;
|
||||||
var isClean = mergeView.editor().isClean(cleanToken);
|
var isClean = mergeView.editor().isClean(cleanEditToken);
|
||||||
var diff = document.getElementById('diff');
|
var diff = document.getElementById('diff');
|
||||||
if (
|
if (
|
||||||
now &&
|
now &&
|
||||||
isClean === false &&
|
isClean === false &&
|
||||||
mergeView.editor().getValue().trim() === cleanEditText
|
mergeView.editor().getValue().trim() === cleanEditText
|
||||||
) {
|
) {
|
||||||
cleanToken = mergeView.editor().changeGeneration();
|
cleanEditToken = mergeView.editor().changeGeneration();
|
||||||
isClean = true;
|
isClean = true;
|
||||||
}
|
}
|
||||||
diff.classList.toggle('editing', isClean === false);
|
diff.classList.toggle('editing', isClean === false);
|
||||||
diff.classList.toggle('dirty', mergeView.leftChunks().length !== 0);
|
diff.classList.toggle('dirty', mergeView.leftChunks().length !== 0);
|
||||||
CodeMirror.commands.save = isClean ? undefined : editSaveHandler;
|
var input = document.querySelector('#ruleFilter input');
|
||||||
|
if ( isClean ) {
|
||||||
|
input.removeAttribute('disabled');
|
||||||
|
CodeMirror.commands.save = undefined;
|
||||||
|
} else {
|
||||||
|
input.setAttribute('disabled', '');
|
||||||
|
CodeMirror.commands.save = editSaveHandler;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return function(now) {
|
return function(now) {
|
||||||
|
@ -308,7 +390,7 @@ var editSaveHandler = function() {
|
||||||
var editor = mergeView.editor();
|
var editor = mergeView.editor();
|
||||||
var editText = editor.getValue().trim();
|
var editText = editor.getValue().trim();
|
||||||
if ( editText === cleanEditText ) {
|
if ( editText === cleanEditText ) {
|
||||||
onChange(true);
|
onTextChanged(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ( differ === undefined ) { differ = new diff_match_patch(); }
|
if ( differ === undefined ) { differ = new diff_match_patch(); }
|
||||||
|
@ -354,9 +436,10 @@ uDom('#exportButton').on('click', exportUserRulesToFile);
|
||||||
uDom('#revertButton').on('click', revertAllHandler);
|
uDom('#revertButton').on('click', revertAllHandler);
|
||||||
uDom('#commitButton').on('click', commitAllHandler);
|
uDom('#commitButton').on('click', commitAllHandler);
|
||||||
uDom('#editSaveButton').on('click', editSaveHandler);
|
uDom('#editSaveButton').on('click', editSaveHandler);
|
||||||
|
uDom('#ruleFilter input').on('input', onFilterChanged);
|
||||||
|
|
||||||
// https://groups.google.com/forum/#!topic/codemirror/UQkTrt078Vs
|
// https://groups.google.com/forum/#!topic/codemirror/UQkTrt078Vs
|
||||||
mergeView.editor().on('updateDiff', function() { onChange(); });
|
mergeView.editor().on('updateDiff', function() { onTextChanged(); });
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
|
1
src/lib/codemirror/addon/merge/merge.js
vendored
1
src/lib/codemirror/addon/merge/merge.js
vendored
|
@ -664,6 +664,7 @@
|
||||||
|
|
||||||
function getChunks(diff) {
|
function getChunks(diff) {
|
||||||
var chunks = [];
|
var chunks = [];
|
||||||
|
if (!diff.length) return chunks;
|
||||||
var startEdit = 0, startOrig = 0;
|
var startEdit = 0, startOrig = 0;
|
||||||
var edit = Pos(0, 0), orig = Pos(0, 0);
|
var edit = Pos(0, 0), orig = Pos(0, 0);
|
||||||
for (var i = 0; i < diff.length; ++i) {
|
for (var i = 0; i < diff.length; ++i) {
|
||||||
|
|
Loading…
Reference in a new issue