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; |
+ } |
+}; |