 Issue 5730585574113280:
  Issue 2390 - Created filter class for CSS property filters  (Closed)
    
  
    Issue 5730585574113280:
  Issue 2390 - Created filter class for CSS property filters  (Closed) 
  | Index: lib/filterClasses.js | 
| =================================================================== | 
| --- a/lib/filterClasses.js | 
| +++ b/lib/filterClasses.js | 
| @@ -20,6 +20,7 @@ | 
| */ | 
| let {FilterNotifier} = require("filterNotifier"); | 
| +let {Utils} = require("utils"); | 
| /** | 
| * Abstract base class for filters | 
| @@ -85,6 +86,11 @@ | 
| * @type RegExp | 
| */ | 
| Filter.optionsRegExp = /\$(~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)$/; | 
| +/** | 
| + * Regular expression that CSS property filters should match | 
| + * @type RegExp | 
| + */ | 
| +Filter.csspropertyRegExp = /\[\-abp\-properties=(["'])([^"']+)\1\]/; | 
| 
Sebastian Noack
2015/05/05 15:47:02
So we don't allow quotes in the value here. Should
 
Thomas Greiner
2015/05/06 12:08:32
Done, I added a comment as suggested. We could cha
 
Thomas Greiner
2015/05/06 15:33:07
Yes, there's currently no negative lookbehind in J
 
Sebastian Noack
2015/05/06 15:42:29
Yeah, let's stick to not allowing any quotes for n
 | 
| /** | 
| * Creates a filter of correct type from its text representation - does the basic parsing and | 
| @@ -160,6 +166,27 @@ | 
| }; | 
| /** | 
| + * Converts filter text into regular expression string | 
| + * @param {String} text as in Filter() | 
| + * @return {String} regular expression representation of filter text | 
| + */ | 
| +Filter.toRegExp = function(text) | 
| +{ | 
| + return text | 
| + .replace(/\*+/g, "*") // remove multiple wildcards | 
| + .replace(/\^\|$/, "^") // remove anchors following separator placeholder | 
| + .replace(/\W/g, "\\$&") // escape special symbols | 
| + .replace(/\\\*/g, ".*") // replace wildcards by .* | 
| + // process separator placeholders (all ANSI characters but alphanumeric characters and _%.-) | 
| + .replace(/\\\^/g, "(?:[\\x00-\\x24\\x26-\\x2C\\x2F\\x3A-\\x40\\x5B-\\x5E\\x60\\x7B-\\x7F]|$)") | 
| + .replace(/^\\\|\\\|/, "^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?") // process extended anchor at expression start | 
| + .replace(/^\\\|/, "^") // process anchor at expression start | 
| + .replace(/\\\|$/, "$") // process anchor at expression end | 
| + .replace(/^(\.\*)/, "") // remove leading wildcards | 
| + .replace(/(\.\*)$/, ""); // remove trailing wildcards | 
| +} | 
| + | 
| +/** | 
| * Class for invalid filters | 
| * @param {String} text see Filter() | 
| * @param {String} reason Reason why this filter is invalid | 
| @@ -543,20 +570,7 @@ | 
| if (prop) | 
| return prop.value; | 
| - // Remove multiple wildcards | 
| - let source = this.regexpSource | 
| - .replace(/\*+/g, "*") // remove multiple wildcards | 
| - .replace(/\^\|$/, "^") // remove anchors following separator placeholder | 
| - .replace(/\W/g, "\\$&") // escape special symbols | 
| - .replace(/\\\*/g, ".*") // replace wildcards by .* | 
| - // process separator placeholders (all ANSI characters but alphanumeric characters and _%.-) | 
| - .replace(/\\\^/g, "(?:[\\x00-\\x24\\x26-\\x2C\\x2F\\x3A-\\x40\\x5B-\\x5E\\x60\\x7B-\\x7F]|$)") | 
| - .replace(/^\\\|\\\|/, "^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?") // process extended anchor at expression start | 
| - .replace(/^\\\|/, "^") // process anchor at expression start | 
| - .replace(/\\\|$/, "$") // process anchor at expression end | 
| - .replace(/^(\.\*)/, "") // remove leading wildcards | 
| - .replace(/(\.\*)$/, ""); // remove trailing wildcards | 
| - | 
| + let source = Filter.toRegExp(this.regexpSource); | 
| let regexp = new RegExp(source, this.matchCase ? "" : "i"); | 
| Object.defineProperty(this, "regexp", {value: regexp}); | 
| return regexp; | 
| @@ -861,7 +875,7 @@ | 
| * @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) | 
| - * @return {ElemHideFilter|ElemHideException|InvalidFilter} | 
| + * @return {ElemHideFilter|ElemHideException|CSSPropertyFilter|InvalidFilter} | 
| */ | 
| ElemHideBase.fromText = function(text, domain, isException, tagName, attrRules, selector) | 
| { | 
| @@ -883,10 +897,7 @@ | 
| } | 
| else { | 
| if (id) | 
| - { | 
| - let {Utils} = require("utils"); | 
| return new InvalidFilter(text, Utils.getString("filter_elemhide_duplicate_id")); | 
| - } | 
| else | 
| 
Sebastian Noack
2015/05/05 15:47:02
Nit: Redundant else statement.
 
Thomas Greiner
2015/05/06 12:08:32
Done.
 | 
| id = rule; | 
| } | 
| @@ -898,15 +909,24 @@ | 
| else if (tagName || additional) | 
| selector = tagName + additional; | 
| else | 
| - { | 
| - let {Utils} = require("utils"); | 
| return new InvalidFilter(text, Utils.getString("filter_elemhide_nocriteria")); | 
| - } | 
| } | 
| if (isException) | 
| return new ElemHideException(text, domain, selector); | 
| else | 
| 
Sebastian Noack
2015/05/05 15:47:02
Nit: Redundant else statement.
 
Thomas Greiner
2015/05/06 12:08:32
Done.
 | 
| - return new ElemHideFilter(text, domain, selector); | 
| + { | 
| + if (Filter.csspropertyRegExp.test(selector)) | 
| + { | 
| + // CSS property filters are inefficient so we need to make sure that | 
| + // they're only applied if they specify active domains | 
| + if (/,[^~]/.test("," + domain)) | 
| 
Sebastian Noack
2015/05/05 15:47:02
I wonder whether we should also look for at least
 
Thomas Greiner
2015/05/06 12:08:32
Good point but note that this still doesn't cover
 
Sebastian Noack
2015/05/06 13:07:48
Hmm, if we want to do it properly, I suppose we ha
 | 
| + return new CSSPropertyFilter(text, domain, selector); | 
| + else | 
| 
Sebastian Noack
2015/05/05 15:47:02
Nit: Redundant else statement.
 | 
| + return new InvalidFilter(text, Utils.getString("filter_cssproperty_nodomain")); | 
| + } | 
| + else | 
| 
Sebastian Noack
2015/05/05 15:47:02
Nit: Redundant else statement.
 
Thomas Greiner
2015/05/06 12:08:32
Done.
 | 
| + return new ElemHideFilter(text, domain, selector); | 
| + } | 
| }; | 
| /** | 
| @@ -946,3 +966,64 @@ | 
| { | 
| __proto__: ElemHideBase.prototype | 
| }; | 
| + | 
| +/** | 
| + * Class for CSS property filters | 
| + * @param {String} text see Filter() | 
| + * @param {String} domains see ElemHideBase() | 
| + * @param {String} selector see ElemHideBase() | 
| + * @constructor | 
| + * @augments ElemHideBase | 
| + */ | 
| +function CSSPropertyFilter(text, domains, selector) | 
| +{ | 
| + ElemHideBase.call(this, text, domains, selector); | 
| + | 
| + let properties; | 
| + [properties, , this.regexpSource] = selector.match(Filter.csspropertyRegExp); | 
| + [this.selectorPrefix, this.selectorSuffix] = selector.split(properties); | 
| +} | 
| +exports.CSSPropertyFilter = CSSPropertyFilter; | 
| + | 
| +CSSPropertyFilter.prototype = | 
| +{ | 
| + __proto__: ElemHideBase.prototype, | 
| + | 
| + /** | 
| + * Expression from which a regular expression should be generated for matching | 
| + * CSS properties - for delayed creation of the regexp property | 
| + * @type String | 
| + */ | 
| + regexpSource: null, | 
| + /** | 
| + * Substring of CSS selector before properties for the HTML elements that | 
| + * should be hidden | 
| + * @type String | 
| + */ | 
| + selectorPrefix: null, | 
| + /** | 
| + * Substring of CSS selector after properties for the HTML elements that | 
| + * should be hidden | 
| + * @type String | 
| + */ | 
| + selectorSuffix: null, | 
| + | 
| + /** | 
| + * Regular expression to be used when testing CSS properties against | 
| + * this filter | 
| + * @type RegExp | 
| + */ | 
| + get regexp() | 
| 
Sebastian Noack
2015/05/05 15:47:02
Hmm, this is almost the same code we already have
 
Thomas Greiner
2015/05/06 12:08:32
You're right, the issue description doesn't explic
 
Sebastian Noack
2015/05/06 13:07:48
Well, objects get serialized when passed to conten
 | 
| + { | 
| + // Despite this property being cached, the getter is called | 
| + // several times on Safari, due to WebKit bug 132872 | 
| + let prop = Object.getOwnPropertyDescriptor(this, "regexp"); | 
| + if (prop) | 
| + return prop.value; | 
| + | 
| + let source = Filter.toRegExp(this.regexpSource); | 
| + let regexp = new RegExp(source, ""); | 
| + Object.defineProperty(this, "regexp", {value: regexp}); | 
| + return regexp; | 
| + } | 
| +}; |