mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-07 03:12:33 +01:00
This commit is contained in:
parent
f79c6ced20
commit
674c3c6079
@ -462,27 +462,21 @@ var filterTypes = {
|
|||||||
// Extract the best possible cosmetic filter, i.e. as specific as possible.
|
// Extract the best possible cosmetic filter, i.e. as specific as possible.
|
||||||
|
|
||||||
// https://github.com/gorhill/uBlock/issues/1725
|
// https://github.com/gorhill/uBlock/issues/1725
|
||||||
// Also take into account the `src` attribute for `img` elements -- and limit
|
// Also take into account the `src` attribute for `img` elements -- and limit
|
||||||
// the value to the 1024 first characters.
|
// the value to the 1024 first characters.
|
||||||
|
|
||||||
var cosmeticFilterFromElement = function(elem) {
|
var cosmeticFilterFromElement = function(elem) {
|
||||||
if ( elem === null ) {
|
if ( elem === null ) { return 0; }
|
||||||
return 0;
|
if ( elem.nodeType !== 1 ) { return 0; }
|
||||||
}
|
|
||||||
if ( elem.nodeType !== 1 ) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( candidateElements.indexOf(elem) === -1 ) {
|
if ( candidateElements.indexOf(elem) === -1 ) {
|
||||||
candidateElements.push(elem);
|
candidateElements.push(elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
var tagName = elem.localName;
|
let selector = '';
|
||||||
var selector = '';
|
|
||||||
var v, i;
|
|
||||||
|
|
||||||
// Id
|
// Id
|
||||||
v = typeof elem.id === 'string' && CSS.escape(elem.id);
|
let v = typeof elem.id === 'string' && CSS.escape(elem.id);
|
||||||
if ( v ) {
|
if ( v ) {
|
||||||
selector = '#' + v;
|
selector = '#' + v;
|
||||||
}
|
}
|
||||||
@ -490,18 +484,20 @@ var cosmeticFilterFromElement = function(elem) {
|
|||||||
// Class(es)
|
// Class(es)
|
||||||
v = elem.classList;
|
v = elem.classList;
|
||||||
if ( v ) {
|
if ( v ) {
|
||||||
i = v.length || 0;
|
let i = v.length || 0;
|
||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
selector += '.' + CSS.escape(v.item(i));
|
selector += '.' + CSS.escape(v.item(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tag name
|
// Tag name
|
||||||
|
let tagName = elem.localName;
|
||||||
|
|
||||||
|
// Use attributes if still no selector found.
|
||||||
// https://github.com/gorhill/uBlock/issues/1901
|
// https://github.com/gorhill/uBlock/issues/1901
|
||||||
// Trim attribute value, this may help in case of malformed HTML.
|
// Trim attribute value, this may help in case of malformed HTML.
|
||||||
if ( selector === '' ) {
|
if ( selector === '' ) {
|
||||||
selector = tagName;
|
let attributes = [], attr;
|
||||||
var attributes = [], attr;
|
|
||||||
switch ( tagName ) {
|
switch ( tagName ) {
|
||||||
case 'a':
|
case 'a':
|
||||||
v = elem.getAttribute('href');
|
v = elem.getAttribute('href');
|
||||||
@ -529,13 +525,11 @@ var cosmeticFilterFromElement = function(elem) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
while ( (attr = attributes.pop()) ) {
|
while ( (attr = attributes.pop()) ) {
|
||||||
if ( attr.v.length === 0 ) {
|
if ( attr.v.length === 0 ) { continue; }
|
||||||
continue;
|
|
||||||
}
|
|
||||||
v = elem.getAttribute(attr.k);
|
v = elem.getAttribute(attr.k);
|
||||||
if ( attr.v === v ) {
|
if ( attr.v === v ) {
|
||||||
selector += '[' + attr.k + '="' + attr.v + '"]';
|
selector += '[' + attr.k + '="' + attr.v + '"]';
|
||||||
} else if ( v.lastIndexOf(attr.v, 0) === 0 ) {
|
} else if ( v.startsWith(attr.v) ) {
|
||||||
selector += '[' + attr.k + '^="' + attr.v + '"]';
|
selector += '[' + attr.k + '^="' + attr.v + '"]';
|
||||||
} else {
|
} else {
|
||||||
selector += '[' + attr.k + '*="' + attr.v + '"]';
|
selector += '[' + attr.k + '*="' + attr.v + '"]';
|
||||||
@ -543,19 +537,31 @@ var cosmeticFilterFromElement = function(elem) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/17
|
||||||
|
// If selector is ambiguous at this point, add the element name to
|
||||||
|
// further narrow it down.
|
||||||
|
let parentNode = elem.parentNode;
|
||||||
|
if (
|
||||||
|
selector === '' ||
|
||||||
|
safeQuerySelectorAll(parentNode, cssScope + selector).length > 1
|
||||||
|
) {
|
||||||
|
selector = tagName + selector;
|
||||||
|
}
|
||||||
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/637
|
// https://github.com/chrisaljoudi/uBlock/issues/637
|
||||||
// If the selector is still ambiguous at this point, further narrow using
|
// If the selector is still ambiguous at this point, further narrow using
|
||||||
// `nth-of-type`. It is preferable to use `nth-of-type` as opposed to
|
// `nth-of-type`. It is preferable to use `nth-of-type` as opposed to
|
||||||
// `nth-child`, as `nth-of-type` is less volatile.
|
// `nth-child`, as `nth-of-type` is less volatile.
|
||||||
var parentNode = elem.parentNode;
|
|
||||||
if ( safeQuerySelectorAll(parentNode, cssScope + selector).length > 1 ) {
|
if ( safeQuerySelectorAll(parentNode, cssScope + selector).length > 1 ) {
|
||||||
i = 1;
|
let i = 1;
|
||||||
while ( elem.previousSibling !== null ) {
|
while ( elem.previousSibling !== null ) {
|
||||||
elem = elem.previousSibling;
|
elem = elem.previousSibling;
|
||||||
if ( typeof elem.localName !== 'string' || elem.localName !== tagName ) {
|
if (
|
||||||
continue;
|
typeof elem.localName === 'string' &&
|
||||||
|
elem.localName === tagName
|
||||||
|
) {
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
selector += ':nth-of-type(' + i + ')';
|
selector += ':nth-of-type(' + i + ')';
|
||||||
}
|
}
|
||||||
@ -582,7 +588,7 @@ var filtersFrom = function(x, y) {
|
|||||||
candidateElements.length = 0;
|
candidateElements.length = 0;
|
||||||
|
|
||||||
// We need at least one element.
|
// We need at least one element.
|
||||||
var first = null;
|
let first = null;
|
||||||
if ( typeof x === 'number' ) {
|
if ( typeof x === 'number' ) {
|
||||||
first = elementFromPoint(x, y);
|
first = elementFromPoint(x, y);
|
||||||
} else if ( x instanceof HTMLElement ) {
|
} else if ( x instanceof HTMLElement ) {
|
||||||
@ -596,23 +602,29 @@ var filtersFrom = function(x, y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cosmetic filter candidates from ancestors.
|
// Cosmetic filter candidates from ancestors.
|
||||||
var elem = first;
|
let elem = first;
|
||||||
while ( elem && elem !== document.body ) {
|
while ( elem && elem !== document.body ) {
|
||||||
cosmeticFilterFromElement(elem);
|
cosmeticFilterFromElement(elem);
|
||||||
elem = elem.parentNode;
|
elem = elem.parentNode;
|
||||||
}
|
}
|
||||||
// The body tag is needed as anchor only when the immediate child
|
// The body tag is needed as anchor only when the immediate child
|
||||||
// uses`nth-of-type`.
|
// uses `nth-of-type`.
|
||||||
var i = cosmeticFilterCandidates.length;
|
let i = cosmeticFilterCandidates.length;
|
||||||
if ( i !== 0 && cosmeticFilterCandidates[i-1].indexOf(':nth-of-type(') !== -1 ) {
|
if ( i !== 0 ) {
|
||||||
cosmeticFilterCandidates.push('##body');
|
let selector = cosmeticFilterCandidates[i-1];
|
||||||
|
if (
|
||||||
|
selector.indexOf(':nth-of-type(') !== -1 &&
|
||||||
|
safeQuerySelectorAll(document.body, selector).length > 1
|
||||||
|
) {
|
||||||
|
cosmeticFilterCandidates.push('##body');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/gorhill/uBlock/issues/1545
|
// https://github.com/gorhill/uBlock/issues/1545
|
||||||
// Network filter candidates from all other elements found at point (x, y).
|
// Network filter candidates from all other elements found at point (x, y).
|
||||||
if ( typeof x === 'number' ) {
|
if ( typeof x === 'number' ) {
|
||||||
var attrName = pickerRoot.id + '-clickblind';
|
let attrName = pickerRoot.id + '-clickblind';
|
||||||
var previous;
|
let previous;
|
||||||
elem = first;
|
elem = first;
|
||||||
while ( elem !== null ) {
|
while ( elem !== null ) {
|
||||||
previous = elem;
|
previous = elem;
|
||||||
@ -623,7 +635,7 @@ var filtersFrom = function(x, y) {
|
|||||||
}
|
}
|
||||||
netFilterFromElement(elem);
|
netFilterFromElement(elem);
|
||||||
}
|
}
|
||||||
var elems = document.querySelectorAll('[' + attrName + ']');
|
let elems = document.querySelectorAll('[' + attrName + ']');
|
||||||
i = elems.length;
|
i = elems.length;
|
||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
elems[i].removeAttribute(attrName);
|
elems[i].removeAttribute(attrName);
|
||||||
@ -1014,35 +1026,34 @@ var onCandidateChanged = (function() {
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var candidateFromFilterChoice = function(filterChoice) {
|
var candidateFromFilterChoice = function(filterChoice) {
|
||||||
var slot = filterChoice.slot;
|
let slot = filterChoice.slot;
|
||||||
var filters = filterChoice.filters;
|
let filters = filterChoice.filters;
|
||||||
var filter = filters[slot];
|
let filter = filters[slot];
|
||||||
|
|
||||||
if ( filter === undefined ) {
|
if ( filter === undefined ) { return ''; }
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// For net filters there no such thing as a path
|
// For net filters there no such thing as a path
|
||||||
if ( filter.lastIndexOf('##', 0) !== 0 ) {
|
if ( filter.startsWith('##') === false ) { return filter; }
|
||||||
return filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point, we have a cosmetic filter
|
// At this point, we have a cosmetic filter
|
||||||
|
|
||||||
// Modifier means "target broadly". Hence:
|
// Modifier means "target broadly". Hence:
|
||||||
// - Do not compute exact path.
|
// - Do not compute exact path.
|
||||||
// - Discard narrowing directives.
|
// - Discard narrowing directives.
|
||||||
|
// - Remove the id if one or more classes exist
|
||||||
|
// TODO: should remove tag name too? ¯\_(ツ)_/¯
|
||||||
if ( filterChoice.modifier ) {
|
if ( filterChoice.modifier ) {
|
||||||
filter = filter.replace(/:nth-of-type\(\d+\)/, '');
|
filter = filter.replace(/:nth-of-type\(\d+\)/, '');
|
||||||
// Remove the id if one or more classes exist.
|
if ( filter.indexOf('.') !== -1 ) {
|
||||||
if ( filter.charAt(2) === '#' && filter.indexOf('.') !== -1 ) {
|
if ( filter.charAt(2) === '#' ) {
|
||||||
filter = filter.replace(/#[^#.]+/, '');
|
filter = filter.replace(/#[^#.]+/, '');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return path: the target element, then all siblings prepended
|
// Return path: the target element, then all siblings prepended
|
||||||
var selector = '', joiner = '';
|
let selector = '', joiner = '';
|
||||||
for ( ; slot < filters.length; slot++ ) {
|
for ( ; slot < filters.length; slot++ ) {
|
||||||
filter = filters[slot];
|
filter = filters[slot];
|
||||||
// Remove all classes when an id exists.
|
// Remove all classes when an id exists.
|
||||||
@ -1051,19 +1062,17 @@ var candidateFromFilterChoice = function(filterChoice) {
|
|||||||
}
|
}
|
||||||
selector = filter.slice(2) + joiner + selector;
|
selector = filter.slice(2) + joiner + selector;
|
||||||
// Stop at any element with an id: these are unique in a web page
|
// Stop at any element with an id: these are unique in a web page
|
||||||
if ( filter.lastIndexOf('###', 0) === 0 ) {
|
if ( filter.startsWith('###') ) { break; }
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Stop if current selector matches only one element on the page
|
// Stop if current selector matches only one element on the page
|
||||||
if ( document.querySelectorAll(selector).length === 1 ) {
|
if ( document.querySelectorAll(selector).length === 1 ) { break; }
|
||||||
break;
|
|
||||||
}
|
|
||||||
joiner = ' > ';
|
joiner = ' > ';
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/gorhill/uBlock/issues/2519
|
// https://github.com/gorhill/uBlock/issues/2519
|
||||||
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/17
|
||||||
if (
|
if (
|
||||||
slot === filters.length &&
|
slot === filters.length &&
|
||||||
|
selector.startsWith('body > ') === false &&
|
||||||
document.querySelectorAll(selector).length > 1
|
document.querySelectorAll(selector).length > 1
|
||||||
) {
|
) {
|
||||||
selector = 'body > ' + selector;
|
selector = 'body > ' + selector;
|
||||||
|
Loading…
Reference in New Issue
Block a user