mirror of https://github.com/gorhill/uBlock.git
Add widget to control selector depth to element picker
Further iterating on the work done in following commit:
- 1268f0ae43
This commit adds a new widget to the element picker to
control the depth of a cosmetic filter selector. The
new widget is essentially just another way of selecting
the depth, which is still controllable through picking
one of the cosmetic filters in the list of candidates.
This commit is contained in:
parent
6f7801d433
commit
260f762c83
|
@ -94,7 +94,7 @@ html#ublock0-epicker,
|
||||||
margin: 0;
|
margin: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: 2px;
|
padding: 2px 2px 1em 2px;
|
||||||
resize: none;
|
resize: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
|
@ -112,63 +112,35 @@ html#ublock0-epicker,
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
justify-content: center;
|
justify-content: space-evenly;
|
||||||
}
|
}
|
||||||
#resultsetSpecificity {
|
#resultsetModifiers.hide > * {
|
||||||
display: inline-flex;
|
|
||||||
pointer-events: auto;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
#resultsetSpecificity.hide {
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
#resultsetSpecificity [data-specificity] {
|
.resultsetModifier {
|
||||||
|
border: 1px solid white;
|
||||||
|
border-bottom: 0;
|
||||||
|
display: inline-flex;
|
||||||
|
height: 100%;
|
||||||
|
pointer-events: auto;
|
||||||
|
position: relative;
|
||||||
|
width: 32%;
|
||||||
|
}
|
||||||
|
.resultsetModifier span {
|
||||||
background-color: var(--button-surface);
|
background-color: var(--button-surface);
|
||||||
border: 0;
|
border: 0;
|
||||||
border-left: 1px solid white;
|
border-left: 1px solid white;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 1.2em;
|
height: 100%;
|
||||||
width: 1.5em;
|
width: 12.5%;
|
||||||
}
|
}
|
||||||
#resultsetSpecificity[data-specificity="0"] [data-specificity="0"],
|
.resultsetModifier span:first-of-type {
|
||||||
#resultsetSpecificity[data-specificity="1"] [data-specificity="0"],
|
border-left: 0;
|
||||||
#resultsetSpecificity[data-specificity="1"] [data-specificity="1"],
|
}
|
||||||
#resultsetSpecificity[data-specificity="2"] [data-specificity="0"],
|
.resultsetModifier span.active {
|
||||||
#resultsetSpecificity[data-specificity="2"] [data-specificity="1"],
|
|
||||||
#resultsetSpecificity[data-specificity="2"] [data-specificity="2"],
|
|
||||||
#resultsetSpecificity[data-specificity="3"] [data-specificity="0"],
|
|
||||||
#resultsetSpecificity[data-specificity="3"] [data-specificity="1"],
|
|
||||||
#resultsetSpecificity[data-specificity="3"] [data-specificity="2"],
|
|
||||||
#resultsetSpecificity[data-specificity="3"] [data-specificity="3"],
|
|
||||||
#resultsetSpecificity[data-specificity="4"] [data-specificity="0"],
|
|
||||||
#resultsetSpecificity[data-specificity="4"] [data-specificity="1"],
|
|
||||||
#resultsetSpecificity[data-specificity="4"] [data-specificity="2"],
|
|
||||||
#resultsetSpecificity[data-specificity="4"] [data-specificity="3"],
|
|
||||||
#resultsetSpecificity[data-specificity="4"] [data-specificity="4"],
|
|
||||||
#resultsetSpecificity[data-specificity="5"] [data-specificity="0"],
|
|
||||||
#resultsetSpecificity[data-specificity="5"] [data-specificity="1"],
|
|
||||||
#resultsetSpecificity[data-specificity="5"] [data-specificity="2"],
|
|
||||||
#resultsetSpecificity[data-specificity="5"] [data-specificity="3"],
|
|
||||||
#resultsetSpecificity[data-specificity="5"] [data-specificity="4"],
|
|
||||||
#resultsetSpecificity[data-specificity="5"] [data-specificity="5"],
|
|
||||||
#resultsetSpecificity[data-specificity="6"] [data-specificity="0"],
|
|
||||||
#resultsetSpecificity[data-specificity="6"] [data-specificity="1"],
|
|
||||||
#resultsetSpecificity[data-specificity="6"] [data-specificity="2"],
|
|
||||||
#resultsetSpecificity[data-specificity="6"] [data-specificity="3"],
|
|
||||||
#resultsetSpecificity[data-specificity="6"] [data-specificity="4"],
|
|
||||||
#resultsetSpecificity[data-specificity="6"] [data-specificity="5"],
|
|
||||||
#resultsetSpecificity[data-specificity="6"] [data-specificity="6"],
|
|
||||||
#resultsetSpecificity[data-specificity="7"] [data-specificity="0"],
|
|
||||||
#resultsetSpecificity[data-specificity="7"] [data-specificity="1"],
|
|
||||||
#resultsetSpecificity[data-specificity="7"] [data-specificity="2"],
|
|
||||||
#resultsetSpecificity[data-specificity="7"] [data-specificity="3"],
|
|
||||||
#resultsetSpecificity[data-specificity="7"] [data-specificity="4"],
|
|
||||||
#resultsetSpecificity[data-specificity="7"] [data-specificity="5"],
|
|
||||||
#resultsetSpecificity[data-specificity="7"] [data-specificity="6"],
|
|
||||||
#resultsetSpecificity[data-specificity="7"] [data-specificity="7"] {
|
|
||||||
background-color: var(--button-active-surface);
|
background-color: var(--button-active-surface);
|
||||||
}
|
}
|
||||||
#resultsetSpecificity input {
|
.resultsetModifier input {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -183,7 +155,6 @@ html#ublock0-epicker,
|
||||||
background-color: #aaa;
|
background-color: #aaa;
|
||||||
color: white;
|
color: white;
|
||||||
min-width: 2.2em;
|
min-width: 2.2em;
|
||||||
padding: 2px 0;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
#ublock0-epicker section.invalidFilter #resultsetCount {
|
#ublock0-epicker section.invalidFilter #resultsetCount {
|
||||||
|
@ -228,7 +199,7 @@ html#ublock0-epicker,
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
#ublock0-epicker #candidateFilters .changeFilter li.active {
|
#ublock0-epicker #candidateFilters .changeFilter li.active {
|
||||||
border: 1px dotted gray;
|
border: 1px dotted var(--blue-50);
|
||||||
}
|
}
|
||||||
#ublock0-epicker #candidateFilters .changeFilter li:hover {
|
#ublock0-epicker #candidateFilters .changeFilter li:hover {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
|
|
@ -62,6 +62,7 @@ let netFilterCandidates = [];
|
||||||
let cosmeticFilterCandidates = [];
|
let cosmeticFilterCandidates = [];
|
||||||
let computedCandidateSlot = 0;
|
let computedCandidateSlot = 0;
|
||||||
let computedCandidate = '';
|
let computedCandidate = '';
|
||||||
|
let needBody = false;
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
@ -77,6 +78,26 @@ const filterFromTextarea = function() {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
const renderRange = function(id, value, invert = false) {
|
||||||
|
const cells = $storAll(`#${id} span`);
|
||||||
|
const input = $stor(`#${id} input`);
|
||||||
|
const max = parseInt(input.max, 10);
|
||||||
|
if ( typeof value !== 'number' ) {
|
||||||
|
value = parseInt(input.value, 10);
|
||||||
|
}
|
||||||
|
if ( invert ) {
|
||||||
|
value = max - value;
|
||||||
|
}
|
||||||
|
input.value = value;
|
||||||
|
for ( let i = 0, n = cells.length; i < n; i++ ) {
|
||||||
|
cells[i].classList.toggle(
|
||||||
|
'active', Math.round(i * max / (n - 1)) <= value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
const userFilterFromCandidate = function(filter) {
|
const userFilterFromCandidate = function(filter) {
|
||||||
if ( filter === '' || filter === '!' ) { return; }
|
if ( filter === '' || filter === '!' ) { return; }
|
||||||
|
|
||||||
|
@ -131,24 +152,8 @@ const candidateFromFilterChoice = function(filterChoice) {
|
||||||
|
|
||||||
$stor(`#cosmeticFilters li:nth-of-type(${slot+1})`)
|
$stor(`#cosmeticFilters li:nth-of-type(${slot+1})`)
|
||||||
.classList.add('active');
|
.classList.add('active');
|
||||||
|
renderRange('resultsetDepth', slot, true);
|
||||||
// Modifier means "target broadly". Hence:
|
renderRange('resultsetSpecificity');
|
||||||
// - Do not compute exact path.
|
|
||||||
// - Discard narrowing directives.
|
|
||||||
// - Remove the id if one or more classes exist
|
|
||||||
// TODO: should remove tag name too? ¯\_(ツ)_/¯
|
|
||||||
if ( filterChoice.broad ) {
|
|
||||||
filter = filter.replace(/:nth-of-type\(\d+\)/, '');
|
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/162
|
|
||||||
// Mind escaped periods: they do not denote a class identifier.
|
|
||||||
if ( filter.charAt(2) === '#' ) {
|
|
||||||
const pos = filter.search(/[^\\]\./);
|
|
||||||
if ( pos !== -1 ) {
|
|
||||||
filter = '##' + filter.slice(pos + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
const specificity = [
|
const specificity = [
|
||||||
0b0000, // remove hierarchy; remove id, nth-of-type, attribute values
|
0b0000, // remove hierarchy; remove id, nth-of-type, attribute values
|
||||||
|
@ -159,12 +164,7 @@ const candidateFromFilterChoice = function(filterChoice) {
|
||||||
0b1100, // remove id, nth-of-type, attribute values
|
0b1100, // remove id, nth-of-type, attribute values
|
||||||
0b1110, // remove id, nth-of-type
|
0b1110, // remove id, nth-of-type
|
||||||
0b1111, // keep all = most specific
|
0b1111, // keep all = most specific
|
||||||
][
|
][ parseInt($stor('#resultsetSpecificity input').value, 10) ];
|
||||||
parseInt(
|
|
||||||
$id('resultsetSpecificity').getAttribute('data-specificity'),
|
|
||||||
10
|
|
||||||
)
|
|
||||||
];
|
|
||||||
|
|
||||||
// Return path: the target element, then all siblings prepended
|
// Return path: the target element, then all siblings prepended
|
||||||
const paths = [];
|
const paths = [];
|
||||||
|
@ -222,6 +222,15 @@ const candidateFromFilterChoice = function(filterChoice) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
needBody &&
|
||||||
|
paths.length !== 0 &&
|
||||||
|
paths[0].startsWith('#') === false &&
|
||||||
|
(specificity & 0b1100) !== 0
|
||||||
|
) {
|
||||||
|
paths.unshift('body > ');
|
||||||
|
}
|
||||||
|
|
||||||
computedCandidate = `##${paths.join('')}`;
|
computedCandidate = `##${paths.join('')}`;
|
||||||
|
|
||||||
return computedCandidate;
|
return computedCandidate;
|
||||||
|
@ -359,7 +368,7 @@ const onCandidateChanged = function() {
|
||||||
$id('resultsetCount').textContent = 'E';
|
$id('resultsetCount').textContent = 'E';
|
||||||
$id('create').setAttribute('disabled', '');
|
$id('create').setAttribute('disabled', '');
|
||||||
}
|
}
|
||||||
$id('resultsetSpecificity').classList.toggle(
|
$id('resultsetModifiers').classList.toggle(
|
||||||
'hide',
|
'hide',
|
||||||
taCandidate.value === '' || taCandidate.value !== computedCandidate
|
taCandidate.value === '' || taCandidate.value !== computedCandidate
|
||||||
);
|
);
|
||||||
|
@ -420,16 +429,26 @@ const onQuitClicked = function() {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
const onSpecificityChanged = function(ev) {
|
const onDepthChanged = function() {
|
||||||
const { target } = ev;
|
const input = $stor('#resultsetDepth input');
|
||||||
$id('resultsetSpecificity').setAttribute('data-specificity', target.value);
|
const max = parseInt(input.max, 10);
|
||||||
if ( taCandidate.value === computedCandidate ) {
|
const value = parseInt(input.value, 10);
|
||||||
|
taCandidate.value = candidateFromFilterChoice({
|
||||||
|
filters: cosmeticFilterCandidates,
|
||||||
|
slot: max - value,
|
||||||
|
});
|
||||||
|
onCandidateChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
const onSpecificityChanged = function() {
|
||||||
|
if ( taCandidate.value !== computedCandidate ) { return; }
|
||||||
taCandidate.value = candidateFromFilterChoice({
|
taCandidate.value = candidateFromFilterChoice({
|
||||||
filters: cosmeticFilterCandidates,
|
filters: cosmeticFilterCandidates,
|
||||||
slot: computedCandidateSlot,
|
slot: computedCandidateSlot,
|
||||||
});
|
});
|
||||||
onCandidateChanged();
|
onCandidateChanged();
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -473,8 +492,8 @@ const onStartMoving = (( ) => {
|
||||||
|
|
||||||
const move = ( ) => {
|
const move = ( ) => {
|
||||||
timer = undefined;
|
timer = undefined;
|
||||||
let r1 = Math.min(Math.max(r0 - mx1 + mx0, 4), rMax);
|
const r1 = Math.min(Math.max(r0 - mx1 + mx0, 4), rMax);
|
||||||
let b1 = Math.min(Math.max(b0 - my1 + my0, 4), bMax);
|
const b1 = Math.min(Math.max(b0 - my1 + my0, 4), bMax);
|
||||||
dialog.style.setProperty('right', `${r1}px`, 'important');
|
dialog.style.setProperty('right', `${r1}px`, 'important');
|
||||||
dialog.style.setProperty('bottom', `${b1}px`, 'important');
|
dialog.style.setProperty('bottom', `${b1}px`, 'important');
|
||||||
};
|
};
|
||||||
|
@ -612,6 +631,13 @@ const showDialog = function(details) {
|
||||||
const { netFilters, cosmeticFilters, filter } = details;
|
const { netFilters, cosmeticFilters, filter } = details;
|
||||||
|
|
||||||
netFilterCandidates = netFilters;
|
netFilterCandidates = netFilters;
|
||||||
|
|
||||||
|
needBody =
|
||||||
|
cosmeticFilters.length !== 0 &&
|
||||||
|
cosmeticFilters[cosmeticFilters.length - 1] === '##body';
|
||||||
|
if ( needBody ) {
|
||||||
|
cosmeticFilters.pop();
|
||||||
|
}
|
||||||
cosmeticFilterCandidates = cosmeticFilters;
|
cosmeticFilterCandidates = cosmeticFilters;
|
||||||
|
|
||||||
// https://github.com/gorhill/uBlock/issues/738
|
// https://github.com/gorhill/uBlock/issues/738
|
||||||
|
@ -625,6 +651,11 @@ const showDialog = function(details) {
|
||||||
populateCandidates(netFilters, '#netFilters');
|
populateCandidates(netFilters, '#netFilters');
|
||||||
populateCandidates(cosmeticFilters, '#cosmeticFilters');
|
populateCandidates(cosmeticFilters, '#cosmeticFilters');
|
||||||
|
|
||||||
|
const depthInput = $stor('#resultsetDepth input');
|
||||||
|
depthInput.max = cosmeticFilters.length - 1;
|
||||||
|
depthInput.value = depthInput.max;
|
||||||
|
onDepthChanged();
|
||||||
|
|
||||||
dialog.querySelector('ul').style.display =
|
dialog.querySelector('ul').style.display =
|
||||||
netFilters.length || cosmeticFilters.length ? '' : 'none';
|
netFilters.length || cosmeticFilters.length ? '' : 'none';
|
||||||
dialog.querySelector('#create').disabled = true;
|
dialog.querySelector('#create').disabled = true;
|
||||||
|
@ -682,6 +713,8 @@ const startPicker = function() {
|
||||||
|
|
||||||
if ( pickerRoot.classList.contains('zap') ) { return; }
|
if ( pickerRoot.classList.contains('zap') ) { return; }
|
||||||
|
|
||||||
|
onSpecificityChanged();
|
||||||
|
|
||||||
taCandidate.addEventListener('input', onCandidateChanged);
|
taCandidate.addEventListener('input', onCandidateChanged);
|
||||||
$id('preview').addEventListener('click', onPreviewClicked);
|
$id('preview').addEventListener('click', onPreviewClicked);
|
||||||
$id('create').addEventListener('click', onCreateClicked);
|
$id('create').addEventListener('click', onCreateClicked);
|
||||||
|
@ -690,6 +723,7 @@ const startPicker = function() {
|
||||||
$id('toolbar').addEventListener('mousedown', onStartMoving);
|
$id('toolbar').addEventListener('mousedown', onStartMoving);
|
||||||
$id('toolbar').addEventListener('touchstart', onStartMoving);
|
$id('toolbar').addEventListener('touchstart', onStartMoving);
|
||||||
$id('candidateFilters').addEventListener('click', onCandidateClicked);
|
$id('candidateFilters').addEventListener('click', onCandidateClicked);
|
||||||
|
$stor('#resultsetDepth input').addEventListener('input', onDepthChanged);
|
||||||
$stor('#resultsetSpecificity input').addEventListener('input', onSpecificityChanged);
|
$stor('#resultsetSpecificity input').addEventListener('input', onSpecificityChanged);
|
||||||
staticFilteringParser = new vAPI.StaticFilteringParser({ interactive: true });
|
staticFilteringParser = new vAPI.StaticFilteringParser({ interactive: true });
|
||||||
};
|
};
|
||||||
|
|
|
@ -529,12 +529,8 @@ const filtersFrom = function(x, y) {
|
||||||
// uses `nth-of-type`.
|
// uses `nth-of-type`.
|
||||||
let i = cosmeticFilterCandidates.length;
|
let i = cosmeticFilterCandidates.length;
|
||||||
if ( i !== 0 ) {
|
if ( i !== 0 ) {
|
||||||
const selector = cosmeticFilterCandidates[i-1];
|
const selector = cosmeticFilterCandidates[i-1].slice(2);
|
||||||
if (
|
if ( safeQuerySelectorAll(document.body, selector).length > 1 ) {
|
||||||
selector.indexOf(':nth-of-type(') !== -1 &&
|
|
||||||
safeQuerySelectorAll(document.body, selector).length > 1 ||
|
|
||||||
safeQuerySelectorAll(document, cosmeticFilterCandidates.join(' > ')).length > 1
|
|
||||||
) {
|
|
||||||
cosmeticFilterCandidates.push('##body');
|
cosmeticFilterCandidates.push('##body');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,18 +15,31 @@
|
||||||
<textarea lang="en" dir="ltr" spellcheck="false"></textarea>
|
<textarea lang="en" dir="ltr" spellcheck="false"></textarea>
|
||||||
<div>
|
<div>
|
||||||
<span id="resultsetModifiers">
|
<span id="resultsetModifiers">
|
||||||
<span id="resultsetSpecificity" data-specificity="6">
|
<span id="resultsetDepth" class="resultsetModifier">
|
||||||
<span data-specificity="0"></span>
|
<span></span>
|
||||||
<span data-specificity="1"></span>
|
<span></span>
|
||||||
<span data-specificity="2"></span>
|
<span></span>
|
||||||
<span data-specificity="3"></span>
|
<span></span>
|
||||||
<span data-specificity="4"></span>
|
<span></span>
|
||||||
<span data-specificity="5"></span>
|
<span></span>
|
||||||
<span data-specificity="6"></span>
|
<span></span>
|
||||||
<span data-specificity="7"></span>
|
<span></span>
|
||||||
<input type="range" min="0" max="7" value="6"></span>
|
<input type="range" min="0" max="7" value="7">
|
||||||
</span>
|
</span>
|
||||||
<span id="resultsetCount"></span></div>
|
<span id="resultsetSpecificity" class="resultsetModifier">
|
||||||
|
<span></span>
|
||||||
|
<span></span>
|
||||||
|
<span></span>
|
||||||
|
<span></span>
|
||||||
|
<span></span>
|
||||||
|
<span></span>
|
||||||
|
<span></span>
|
||||||
|
<span></span>
|
||||||
|
<input type="range" min="0" max="7" value="6">
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span id="resultsetCount"></span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="toolbar">
|
<div id="toolbar">
|
||||||
<div>
|
<div>
|
||||||
|
|
Loading…
Reference in New Issue