| 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 |