mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-07 03:12:33 +01:00
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;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
padding: 2px;
|
||||
padding: 2px 2px 1em 2px;
|
||||
resize: none;
|
||||
width: 100%;
|
||||
word-break: break-all;
|
||||
@ -112,63 +112,35 @@ html#ublock0-epicker,
|
||||
align-items: flex-end;
|
||||
display: inline-flex;
|
||||
flex-grow: 1;
|
||||
justify-content: center;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
#resultsetSpecificity {
|
||||
display: inline-flex;
|
||||
pointer-events: auto;
|
||||
position: relative;
|
||||
}
|
||||
#resultsetSpecificity.hide {
|
||||
#resultsetModifiers.hide > * {
|
||||
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);
|
||||
border: 0;
|
||||
border-left: 1px solid white;
|
||||
display: inline-block;
|
||||
height: 1.2em;
|
||||
width: 1.5em;
|
||||
height: 100%;
|
||||
width: 12.5%;
|
||||
}
|
||||
#resultsetSpecificity[data-specificity="0"] [data-specificity="0"],
|
||||
#resultsetSpecificity[data-specificity="1"] [data-specificity="0"],
|
||||
#resultsetSpecificity[data-specificity="1"] [data-specificity="1"],
|
||||
#resultsetSpecificity[data-specificity="2"] [data-specificity="0"],
|
||||
#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"] {
|
||||
.resultsetModifier span:first-of-type {
|
||||
border-left: 0;
|
||||
}
|
||||
.resultsetModifier span.active {
|
||||
background-color: var(--button-active-surface);
|
||||
}
|
||||
#resultsetSpecificity input {
|
||||
.resultsetModifier input {
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
@ -183,7 +155,6 @@ html#ublock0-epicker,
|
||||
background-color: #aaa;
|
||||
color: white;
|
||||
min-width: 2.2em;
|
||||
padding: 2px 0;
|
||||
text-align: center;
|
||||
}
|
||||
#ublock0-epicker section.invalidFilter #resultsetCount {
|
||||
@ -228,7 +199,7 @@ html#ublock0-epicker,
|
||||
white-space: nowrap;
|
||||
}
|
||||
#ublock0-epicker #candidateFilters .changeFilter li.active {
|
||||
border: 1px dotted gray;
|
||||
border: 1px dotted var(--blue-50);
|
||||
}
|
||||
#ublock0-epicker #candidateFilters .changeFilter li:hover {
|
||||
background-color: white;
|
||||
|
@ -62,6 +62,7 @@ let netFilterCandidates = [];
|
||||
let cosmeticFilterCandidates = [];
|
||||
let computedCandidateSlot = 0;
|
||||
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) {
|
||||
if ( filter === '' || filter === '!' ) { return; }
|
||||
|
||||
@ -131,24 +152,8 @@ const candidateFromFilterChoice = function(filterChoice) {
|
||||
|
||||
$stor(`#cosmeticFilters li:nth-of-type(${slot+1})`)
|
||||
.classList.add('active');
|
||||
|
||||
// Modifier means "target broadly". Hence:
|
||||
// - 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;
|
||||
}
|
||||
renderRange('resultsetDepth', slot, true);
|
||||
renderRange('resultsetSpecificity');
|
||||
|
||||
const specificity = [
|
||||
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
|
||||
0b1110, // remove id, nth-of-type
|
||||
0b1111, // keep all = most specific
|
||||
][
|
||||
parseInt(
|
||||
$id('resultsetSpecificity').getAttribute('data-specificity'),
|
||||
10
|
||||
)
|
||||
];
|
||||
][ parseInt($stor('#resultsetSpecificity input').value, 10) ];
|
||||
|
||||
// Return path: the target element, then all siblings prepended
|
||||
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('')}`;
|
||||
|
||||
return computedCandidate;
|
||||
@ -359,7 +368,7 @@ const onCandidateChanged = function() {
|
||||
$id('resultsetCount').textContent = 'E';
|
||||
$id('create').setAttribute('disabled', '');
|
||||
}
|
||||
$id('resultsetSpecificity').classList.toggle(
|
||||
$id('resultsetModifiers').classList.toggle(
|
||||
'hide',
|
||||
taCandidate.value === '' || taCandidate.value !== computedCandidate
|
||||
);
|
||||
@ -420,16 +429,26 @@ const onQuitClicked = function() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const onSpecificityChanged = function(ev) {
|
||||
const { target } = ev;
|
||||
$id('resultsetSpecificity').setAttribute('data-specificity', target.value);
|
||||
if ( taCandidate.value === computedCandidate ) {
|
||||
const onDepthChanged = function() {
|
||||
const input = $stor('#resultsetDepth input');
|
||||
const max = parseInt(input.max, 10);
|
||||
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({
|
||||
filters: cosmeticFilterCandidates,
|
||||
slot: computedCandidateSlot,
|
||||
});
|
||||
onCandidateChanged();
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
@ -473,8 +492,8 @@ const onStartMoving = (( ) => {
|
||||
|
||||
const move = ( ) => {
|
||||
timer = undefined;
|
||||
let r1 = Math.min(Math.max(r0 - mx1 + mx0, 4), rMax);
|
||||
let b1 = Math.min(Math.max(b0 - my1 + my0, 4), bMax);
|
||||
const r1 = Math.min(Math.max(r0 - mx1 + mx0, 4), rMax);
|
||||
const b1 = Math.min(Math.max(b0 - my1 + my0, 4), bMax);
|
||||
dialog.style.setProperty('right', `${r1}px`, 'important');
|
||||
dialog.style.setProperty('bottom', `${b1}px`, 'important');
|
||||
};
|
||||
@ -612,6 +631,13 @@ const showDialog = function(details) {
|
||||
const { netFilters, cosmeticFilters, filter } = details;
|
||||
|
||||
netFilterCandidates = netFilters;
|
||||
|
||||
needBody =
|
||||
cosmeticFilters.length !== 0 &&
|
||||
cosmeticFilters[cosmeticFilters.length - 1] === '##body';
|
||||
if ( needBody ) {
|
||||
cosmeticFilters.pop();
|
||||
}
|
||||
cosmeticFilterCandidates = cosmeticFilters;
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/738
|
||||
@ -625,6 +651,11 @@ const showDialog = function(details) {
|
||||
populateCandidates(netFilters, '#netFilters');
|
||||
populateCandidates(cosmeticFilters, '#cosmeticFilters');
|
||||
|
||||
const depthInput = $stor('#resultsetDepth input');
|
||||
depthInput.max = cosmeticFilters.length - 1;
|
||||
depthInput.value = depthInput.max;
|
||||
onDepthChanged();
|
||||
|
||||
dialog.querySelector('ul').style.display =
|
||||
netFilters.length || cosmeticFilters.length ? '' : 'none';
|
||||
dialog.querySelector('#create').disabled = true;
|
||||
@ -682,6 +713,8 @@ const startPicker = function() {
|
||||
|
||||
if ( pickerRoot.classList.contains('zap') ) { return; }
|
||||
|
||||
onSpecificityChanged();
|
||||
|
||||
taCandidate.addEventListener('input', onCandidateChanged);
|
||||
$id('preview').addEventListener('click', onPreviewClicked);
|
||||
$id('create').addEventListener('click', onCreateClicked);
|
||||
@ -690,6 +723,7 @@ const startPicker = function() {
|
||||
$id('toolbar').addEventListener('mousedown', onStartMoving);
|
||||
$id('toolbar').addEventListener('touchstart', onStartMoving);
|
||||
$id('candidateFilters').addEventListener('click', onCandidateClicked);
|
||||
$stor('#resultsetDepth input').addEventListener('input', onDepthChanged);
|
||||
$stor('#resultsetSpecificity input').addEventListener('input', onSpecificityChanged);
|
||||
staticFilteringParser = new vAPI.StaticFilteringParser({ interactive: true });
|
||||
};
|
||||
|
@ -529,12 +529,8 @@ const filtersFrom = function(x, y) {
|
||||
// uses `nth-of-type`.
|
||||
let i = cosmeticFilterCandidates.length;
|
||||
if ( i !== 0 ) {
|
||||
const selector = cosmeticFilterCandidates[i-1];
|
||||
if (
|
||||
selector.indexOf(':nth-of-type(') !== -1 &&
|
||||
safeQuerySelectorAll(document.body, selector).length > 1 ||
|
||||
safeQuerySelectorAll(document, cosmeticFilterCandidates.join(' > ')).length > 1
|
||||
) {
|
||||
const selector = cosmeticFilterCandidates[i-1].slice(2);
|
||||
if ( safeQuerySelectorAll(document.body, selector).length > 1 ) {
|
||||
cosmeticFilterCandidates.push('##body');
|
||||
}
|
||||
}
|
||||
|
@ -15,18 +15,31 @@
|
||||
<textarea lang="en" dir="ltr" spellcheck="false"></textarea>
|
||||
<div>
|
||||
<span id="resultsetModifiers">
|
||||
<span id="resultsetSpecificity" data-specificity="6">
|
||||
<span data-specificity="0"></span>
|
||||
<span data-specificity="1"></span>
|
||||
<span data-specificity="2"></span>
|
||||
<span data-specificity="3"></span>
|
||||
<span data-specificity="4"></span>
|
||||
<span data-specificity="5"></span>
|
||||
<span data-specificity="6"></span>
|
||||
<span data-specificity="7"></span>
|
||||
<input type="range" min="0" max="7" value="6"></span>
|
||||
<span id="resultsetDepth" 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="7">
|
||||
</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 id="toolbar">
|
||||
<div>
|
||||
|
Loading…
Reference in New Issue
Block a user