Index: lib/filterClasses.js |
=================================================================== |
--- a/lib/filterClasses.js |
+++ b/lib/filterClasses.js |
@@ -82,17 +82,17 @@ Filter.prototype = |
* @type {Object} |
*/ |
Filter.knownFilters = Object.create(null); |
/** |
* Regular expression that element hiding filters should match |
* @type {RegExp} |
*/ |
-Filter.elemhideRegExp = /^([^/*|@"!]*?)#(@)?(?:([\w-]+|\*)((?:\([\w-]+(?:[$^*]?=[^()"]*)?\))*)|#(.+))$/; |
+Filter.elemhideRegExp = /^([^/*|@"!]*?)#([@?])?#(.+)$/; |
/** |
* Regular expression that RegExp filters specified as RegExps should match |
* @type {RegExp} |
*/ |
Filter.regexpRegExp = /^(@@)?\/.*\/(?:\$~?[\w-]+(?:=[^,\s]+)?(?:,~?[\w-]+(?:=[^,\s]+)?)*)?$/; |
/** |
* Regular expression that options on a RegExp filter should match |
* @type {RegExp} |
@@ -110,18 +110,30 @@ Filter.fromText = function(text) |
{ |
if (text in Filter.knownFilters) |
return Filter.knownFilters[text]; |
let ret; |
let match = (text.includes("#") ? Filter.elemhideRegExp.exec(text) : null); |
if (match) |
{ |
+ let propsMatch; |
+ if (!match[2] && |
+ (propsMatch = /\[-abp-properties=(["'])([^"']+)\1\]/.exec(match[3]))) |
+ { |
+ // This is legacy CSS properties syntax, convert to current syntax |
+ let prefix = match[3].substr(0, propsMatch.index); |
+ let expression = propsMatch[2]; |
+ let suffix = match[3].substr(propsMatch.index + propsMatch[0].length); |
+ return Filter.fromText(`${match[1]}#?#` + |
+ `${prefix}:-abp-properties(${expression})${suffix}`); |
+ } |
+ |
ret = ElemHideBase.fromText( |
- text, match[1], !!match[2], match[3], match[4], match[5] |
+ text, match[1], match[2], match[3] |
); |
} |
else if (text[0] == "!") |
ret = new CommentFilter(text); |
else |
ret = RegExpFilter.fromText(text); |
Filter.knownFilters[ret.text] = ret; |
@@ -925,81 +937,46 @@ ElemHideBase.prototype = extend(ActiveFi |
*/ |
selector: null |
}); |
/** |
* Creates an element hiding filter from a pre-parsed text representation |
* |
* @param {string} text same as in Filter() |
- * @param {string} domain |
- * domain part of the text representation (can be empty) |
- * @param {boolean} isException exception rule indicator |
- * @param {string} tagName tag name part (can be empty) |
- * @param {string} attrRules attribute matching rules (can be empty) |
- * @param {string} selector raw CSS selector (can be empty) |
+ * @param {string?} domain |
+ * domain part of the text representation |
+ * @param {string?} type |
+* rule type, either empty or @ (exception) or ? (emulation rule) |
+ * @param {string} selector raw CSS selector |
* @return {ElemHideFilter|ElemHideException| |
* ElemHideEmulationFilter|InvalidFilter} |
*/ |
-ElemHideBase.fromText = function(text, domain, isException, tagName, attrRules, |
- selector) |
+ElemHideBase.fromText = function(text, domain, type, selector) |
{ |
- if (!selector) |
- { |
- if (tagName == "*") |
- tagName = ""; |
- |
- let id = null; |
- let additional = ""; |
- if (attrRules) |
- { |
- attrRules = attrRules.match(/\([\w-]+(?:[$^*]?=[^()"]*)?\)/g); |
- for (let rule of attrRules) |
- { |
- rule = rule.substr(1, rule.length - 2); |
- let separatorPos = rule.indexOf("="); |
- if (separatorPos > 0) |
- { |
- rule = rule.replace(/=/, '="') + '"'; |
- additional += "[" + rule + "]"; |
- } |
- else |
- { |
- if (id) |
- return new InvalidFilter(text, "filter_elemhide_duplicate_id"); |
- |
- id = rule; |
- } |
- } |
- } |
- |
- if (id) |
- selector = `${tagName}.${id}${additional},${tagName}#${id}${additional}`; |
- else if (tagName || additional) |
- selector = tagName + additional; |
- else |
- return new InvalidFilter(text, "filter_elemhide_nocriteria"); |
- } |
- |
// We don't allow ElemHide filters which have any empty domains. |
// Note: The ElemHide.prototype.domainSeparator is duplicated here, if that |
// changes this must be changed too. |
if (domain && /(^|,)~?(,|$)/.test(domain)) |
return new InvalidFilter(text, "filter_invalid_domain"); |
- if (isException) |
+ if (type == "@") |
return new ElemHideException(text, domain, selector); |
- if (selector.indexOf("[-abp-properties=") != -1) |
+ if (type == "?") |
{ |
// Element hiding emulation filters are inefficient so we need to make sure |
// that they're only applied if they specify active domains |
if (!/,[^~][^,.]*\.[^,]/.test("," + domain)) |
return new InvalidFilter(text, "filter_elemhideemulation_nodomain"); |
+ // The selector should contain at least one :-abp-foo() pseudo-class |
+ if (!/:-abp-[\w-]+\(/.test(selector)) |
+ return new InvalidFilter(text, "filter_elemhideemulation_plainselector"); |
+ |
return new ElemHideEmulationFilter(text, domain, selector); |
} |
return new ElemHideFilter(text, domain, selector); |
}; |
/** |
* Class for element hiding filters |