mirror of
https://github.com/gorhill/uBlock.git
synced 2024-09-18 17:02:27 +02:00
fix #781: support for explicit style properties
This commit is contained in:
parent
09d35b65e0
commit
3752ac4880
@ -66,6 +66,7 @@ vAPI.domFilterer = {
|
|||||||
hiddenId: String.fromCharCode(Date.now() % 26 + 97) + Math.floor(Math.random() * 982451653 + 982451653).toString(36),
|
hiddenId: String.fromCharCode(Date.now() % 26 + 97) + Math.floor(Math.random() * 982451653 + 982451653).toString(36),
|
||||||
hiddenNodeCount: 0,
|
hiddenNodeCount: 0,
|
||||||
matchesProp: vAPI.matchesProp,
|
matchesProp: vAPI.matchesProp,
|
||||||
|
newCSSRules: [],
|
||||||
newDeclarativeSelectors: [],
|
newDeclarativeSelectors: [],
|
||||||
shadowId: String.fromCharCode(Date.now() % 26 + 97) + Math.floor(Math.random() * 982451653 + 982451653).toString(36),
|
shadowId: String.fromCharCode(Date.now() % 26 + 97) + Math.floor(Math.random() * 982451653 + 982451653).toString(36),
|
||||||
styleTags: [],
|
styleTags: [],
|
||||||
@ -94,32 +95,13 @@ vAPI.domFilterer = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
addHasSelector: function(s1, s2) {
|
|
||||||
var entry = { a: s1, b: s2.slice(5, -1) };
|
|
||||||
if ( s1.indexOf(' ') === -1 ) {
|
|
||||||
this.simpleHasSelectors.push(entry);
|
|
||||||
} else {
|
|
||||||
this.complexHasSelectors.push(entry);
|
|
||||||
this.complexHasSelectorsCost = 0;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
addSelector: function(s) {
|
addSelector: function(s) {
|
||||||
if ( this.allSelectors[s] || this.allExceptions[s] ) {
|
if ( this.allSelectors[s] || this.allExceptions[s] ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.allSelectors[s] = true;
|
this.allSelectors[s] = true;
|
||||||
var pos = s.indexOf(':');
|
if ( s.indexOf(':') !== -1 && this.addSelectorEx(s) ) {
|
||||||
if ( pos !== -1 ) {
|
return;
|
||||||
pos = s.indexOf(':has(');
|
|
||||||
if ( pos !== -1 ) {
|
|
||||||
this.addHasSelector(s.slice(0, pos), s.slice(pos));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ( s.lastIndexOf(':xpath(', 0) === 0 ) {
|
|
||||||
this.addXpathSelector('', s);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if ( s.indexOf(' ') === -1 ) {
|
if ( s.indexOf(' ') === -1 ) {
|
||||||
this.simpleSelectors.push(s);
|
this.simpleSelectors.push(s);
|
||||||
@ -132,18 +114,41 @@ vAPI.domFilterer = {
|
|||||||
this.newDeclarativeSelectors.push(s);
|
this.newDeclarativeSelectors.push(s);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
addSelectorEx: function(s) {
|
||||||
|
var pos = s.indexOf(':has(');
|
||||||
|
if ( pos !== -1 ) {
|
||||||
|
var entry = {
|
||||||
|
a: s.slice(0, pos),
|
||||||
|
b: s.slice(pos + 5, -1)
|
||||||
|
};
|
||||||
|
if ( entry.a.indexOf(' ') === -1 ) {
|
||||||
|
this.simpleHasSelectors.push(entry);
|
||||||
|
} else {
|
||||||
|
this.complexHasSelectors.push(entry);
|
||||||
|
this.complexHasSelectorsCost = 0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
pos = s.indexOf(':style(');
|
||||||
|
if ( pos !== -1 ) {
|
||||||
|
this.newCSSRules.push(s.slice(0, pos) + ' {' + s.slice(pos + 7, -1) + '}');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ( s.lastIndexOf(':xpath(', 0) === 0 ) {
|
||||||
|
this.xpathExpression = null;
|
||||||
|
this.xpathSelectorsCost = 0;
|
||||||
|
this.addXpathSelector('', s.slice(7, -1));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
addSelectors: function(aa) {
|
addSelectors: function(aa) {
|
||||||
for ( var i = 0, n = aa.length; i < n; i++ ) {
|
for ( var i = 0, n = aa.length; i < n; i++ ) {
|
||||||
this.addSelector(aa[i]);
|
this.addSelector(aa[i]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
addXpathSelector: function(s1, s2) {
|
|
||||||
this.xpathSelectors.push(s2.slice(7, -1));
|
|
||||||
this.xpathExpression = null;
|
|
||||||
this.xpathSelectorsCost = 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
checkStyleTags: function(commitIfNeeded) {
|
checkStyleTags: function(commitIfNeeded) {
|
||||||
var doc = document,
|
var doc = document,
|
||||||
html = doc.documentElement,
|
html = doc.documentElement,
|
||||||
@ -188,8 +193,9 @@ vAPI.domFilterer = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Inject new declarative selectors.
|
// Inject new declarative selectors.
|
||||||
|
var styleTag;
|
||||||
if ( this.newDeclarativeSelectors.length ) {
|
if ( this.newDeclarativeSelectors.length ) {
|
||||||
var styleTag = document.createElement('style');
|
styleTag = document.createElement('style');
|
||||||
styleTag.setAttribute('type', 'text/css');
|
styleTag.setAttribute('type', 'text/css');
|
||||||
styleTag.textContent =
|
styleTag.textContent =
|
||||||
':root ' +
|
':root ' +
|
||||||
@ -199,6 +205,15 @@ vAPI.domFilterer = {
|
|||||||
this.styleTags.push(styleTag);
|
this.styleTags.push(styleTag);
|
||||||
this.newDeclarativeSelectors.length = 0;
|
this.newDeclarativeSelectors.length = 0;
|
||||||
}
|
}
|
||||||
|
// Inject new CSS rules.
|
||||||
|
if ( this.newCSSRules.length ) {
|
||||||
|
styleTag = document.createElement('style');
|
||||||
|
styleTag.setAttribute('type', 'text/css');
|
||||||
|
styleTag.textContent = ':root ' + this.newCSSRules.join(',\n:root ');
|
||||||
|
document.head.appendChild(styleTag);
|
||||||
|
this.styleTags.push(styleTag);
|
||||||
|
this.newCSSRules.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Simple `:has()` selectors.
|
// Simple `:has()` selectors.
|
||||||
if ( this.simpleHasSelectors.length ) {
|
if ( this.simpleHasSelectors.length ) {
|
||||||
|
@ -297,17 +297,29 @@ FilterParser.prototype.parse = function(raw) {
|
|||||||
|
|
||||||
// https://github.com/gorhill/uBlock/issues/952
|
// https://github.com/gorhill/uBlock/issues/952
|
||||||
// Find out whether we are dealing with an Adguard-specific cosmetic
|
// Find out whether we are dealing with an Adguard-specific cosmetic
|
||||||
// filter, and if so, discard the filter.
|
// filter, and if so, translate it if supported, or discard it if not
|
||||||
|
// supported.
|
||||||
var cCode = raw.charCodeAt(rpos - 1);
|
var cCode = raw.charCodeAt(rpos - 1);
|
||||||
if ( cCode !== 0x23 /* '#' */ && cCode !== 0x40 /* '@' */ ) {
|
if ( cCode !== 0x23 /* '#' */ && cCode !== 0x40 /* '@' */ ) {
|
||||||
// We have an Adguard cosmetic filter if and only if the character is
|
// We have an Adguard cosmetic filter if and only if the character is
|
||||||
// `$` or `%`, otherwise it's not a cosmetic filter.
|
// `$` or `%`, otherwise it's not a cosmetic filter.
|
||||||
if ( cCode === 0x24 /* '$' */ || cCode === 0x25 /* '%' */ ) {
|
// Not a cosmetic filter.
|
||||||
this.invalid = true;
|
if ( cCode !== 0x24 /* '$' */ && cCode !== 0x25 /* '%' */ ) {
|
||||||
} else {
|
|
||||||
this.cosmetic = false;
|
this.cosmetic = false;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
return this;
|
// Not supported.
|
||||||
|
if ( cCode !== 0x24 /* '$' */ ) {
|
||||||
|
this.invalid = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
// CSS injection rule: supported, but translate into uBO's own format.
|
||||||
|
raw = this.translateAdguardCSSInjectionFilter(raw);
|
||||||
|
if ( raw === '' ) {
|
||||||
|
this.invalid = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
rpos = raw.indexOf('#', lpos + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the hostname(s).
|
// Extract the hostname(s).
|
||||||
@ -322,17 +334,6 @@ FilterParser.prototype.parse = function(raw) {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cosmetic filters with explicit style properties can apply only:
|
|
||||||
// - to specific cosmetic filters (those which apply to a specific site)
|
|
||||||
// - to block cosmetic filters (not exception cosmetic filters)
|
|
||||||
if ( this.suffix.endsWith('}') ) {
|
|
||||||
// Not supported for now: this code will ensure some backward
|
|
||||||
// compatibility for when cosmetic filters with explicit style
|
|
||||||
// properties start to be in use.
|
|
||||||
this.invalid = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2014-05-23:
|
// 2014-05-23:
|
||||||
// https://github.com/gorhill/httpswitchboard/issues/260
|
// https://github.com/gorhill/httpswitchboard/issues/260
|
||||||
// Any sequence of `#` longer than one means the line is not a valid
|
// Any sequence of `#` longer than one means the line is not a valid
|
||||||
@ -380,6 +381,21 @@ FilterParser.prototype.parse = function(raw) {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// Reference: https://adguard.com/en/filterrules.html#cssInjection
|
||||||
|
|
||||||
|
FilterParser.prototype.translateAdguardCSSInjectionFilter = function(raw) {
|
||||||
|
var matches = /^([^#]*)#(@?)\$#([^{]+)\{([^}]+)\}$/.exec(raw);
|
||||||
|
if ( matches === null ) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return matches[1] +
|
||||||
|
'#' + matches[2] + '#' +
|
||||||
|
matches[3].trim() +
|
||||||
|
':style(' + matches[4].trim() + ')';
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
FilterParser.prototype.parseScriptTagFilter = function(matches) {
|
FilterParser.prototype.parseScriptTagFilter = function(matches) {
|
||||||
// Currently supported only as non-generic selector. Also, exception
|
// Currently supported only as non-generic selector. Also, exception
|
||||||
// script tag filter makes no sense, ignore.
|
// script tag filter makes no sense, ignore.
|
||||||
@ -699,6 +715,10 @@ FilterContainer.prototype.reset = function() {
|
|||||||
// https://github.com/chrisaljoudi/uBlock/issues/1004
|
// https://github.com/chrisaljoudi/uBlock/issues/1004
|
||||||
// Detect and report invalid CSS selectors.
|
// Detect and report invalid CSS selectors.
|
||||||
|
|
||||||
|
// Discard new ABP's `-abp-properties` directive until it is
|
||||||
|
// implemented (if ever). Unlikely, see:
|
||||||
|
// https://github.com/gorhill/uBlock/issues/1752
|
||||||
|
|
||||||
FilterContainer.prototype.isValidSelector = (function() {
|
FilterContainer.prototype.isValidSelector = (function() {
|
||||||
var div = document.createElement('div');
|
var div = document.createElement('div');
|
||||||
var matchesProp = (function() {
|
var matchesProp = (function() {
|
||||||
@ -722,18 +742,22 @@ FilterContainer.prototype.isValidSelector = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var reHasSelector = /^(.+?):has\((.+?)\)$/;
|
var reHasSelector = /^(.+?):has\((.+?)\)$/;
|
||||||
|
var reStyleSelector = /^(.+?):style\((.+?)\)$/;
|
||||||
var reXpathSelector = /^:xpath\((.+?)\)$/;
|
var reXpathSelector = /^:xpath\((.+?)\)$/;
|
||||||
|
|
||||||
return function(s) {
|
// Keep in mind: https://github.com/gorhill/uBlock/issues/693
|
||||||
|
var isValidCSSSelector = function(s) {
|
||||||
try {
|
try {
|
||||||
// https://github.com/gorhill/uBlock/issues/693
|
|
||||||
div[matchesProp](s + ',\n#foo');
|
div[matchesProp](s + ',\n#foo');
|
||||||
// Discard new ABP's `-abp-properties` directive until it is
|
} catch (ex) {
|
||||||
// implemented (if ever).
|
return false;
|
||||||
if ( s.indexOf('[-abp-properties=') === -1 ) {
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
};
|
||||||
} catch (e) {
|
|
||||||
|
return function(s) {
|
||||||
|
if ( isValidCSSSelector(s) && s.indexOf('[-abp-properties=') === -1 ) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
// We reach this point very rarely.
|
// We reach this point very rarely.
|
||||||
var matches;
|
var matches;
|
||||||
@ -753,6 +777,11 @@ FilterContainer.prototype.isValidSelector = (function() {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// `:style` selector?
|
||||||
|
matches = reStyleSelector.exec(s);
|
||||||
|
if ( matches !== null ) {
|
||||||
|
return isValidCSSSelector(matches[1]);
|
||||||
|
}
|
||||||
// Special `script:` filter?
|
// Special `script:` filter?
|
||||||
if ( s.startsWith('script') ) {
|
if ( s.startsWith('script') ) {
|
||||||
if ( s.startsWith('?', 6) || s.startsWith('+', 6) ) {
|
if ( s.startsWith('?', 6) || s.startsWith('+', 6) ) {
|
||||||
|
Loading…
Reference in New Issue
Block a user