1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-09-15 07:22:28 +02:00

fix #781: support for explicit style properties

This commit is contained in:
gorhill 2016-06-29 17:07:33 -04:00
parent 09d35b65e0
commit 3752ac4880
2 changed files with 96 additions and 52 deletions

View File

@ -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 ) {

View File

@ -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) ) {