Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: lib/filterClasses.js

Issue 5730585574113280: Issue 2390 - Created filter class for CSS property filters (Closed)
Patch Set: Modified constructor signature Created June 8, 2015, 2:25 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/locale/en-US/global.properties ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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,12 @@
* @type RegExp
*/
Filter.optionsRegExp = /\$(~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)$/;
+/**
+ * Regular expression that CSS property filters should match
+ * Properties must not contain " or '
+ * @type RegExp
+ */
+Filter.csspropertyRegExp = /\[\-abp\-properties=(["'])([^"']+)\1\]/;
/**
* Creates a filter of correct type from its text representation - does the basic parsing and
@@ -160,6 +167,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 +571,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;
@@ -852,7 +867,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)
{
@@ -863,23 +878,24 @@
let id = null;
let additional = "";
- if (attrRules) {
+ if (attrRules)
+ {
attrRules = attrRules.match(/\([\w\-]+(?:[$^*]?=[^\(\)"]*)?\)/g);
- for (let rule of attrRules) {
+ for (let rule of attrRules)
+ {
rule = rule.substr(1, rule.length - 2);
let separatorPos = rule.indexOf("=");
- if (separatorPos > 0) {
+ if (separatorPos > 0)
+ {
rule = rule.replace(/=/, '="') + '"';
additional += "[" + rule + "]";
}
- else {
+ else
+ {
if (id)
- {
- let {Utils} = require("utils");
return new InvalidFilter(text, Utils.getString("filter_elemhide_duplicate_id"));
- }
- else
- id = rule;
+
+ id = rule;
}
}
}
@@ -889,15 +905,26 @@
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
- return new ElemHideFilter(text, domain, selector);
+
+ let match = Filter.csspropertyRegExp.exec(selector);
+ if (match)
+ {
+ // CSS property 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, Utils.getString("filter_cssproperty_nodomain"));
+
+ return new CSSPropertyFilter(text, domain, selector, match[2],
+ selector.substr(0, match.index),
+ selector.substr(match.index + match[0].length));
+ }
+
+ return new ElemHideFilter(text, domain, selector);
};
/**
@@ -937,3 +964,67 @@
{
__proto__: ElemHideBase.prototype
};
+
+/**
+ * Class for CSS property filters
+ * @param {String} text see Filter()
+ * @param {String} domains see ElemHideBase()
+ * @param {String} selector see ElemHideBase()
+ * @param {String} regexpSource see CSSPropertyFilter.regexpSource
+ * @param {String} selectorPrefix see CSSPropertyFilter.selectorPrefix
+ * @param {String} selectorSuffix see CSSPropertyFilter.selectorSuffix
+ * @constructor
+ * @augments ElemHideBase
+ */
+function CSSPropertyFilter(text, domains, selector, regexpSource,
+ selectorPrefix, selectorSuffix)
+{
+ ElemHideBase.call(this, text, domains, selector);
+
+ this.regexpSource = regexpSource;
+ this.selectorPrefix = selectorPrefix;
+ this.selectorSuffix = selectorSuffix;
+}
+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 regexpString 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,
+
+ /**
+ * Raw regular expression string to be used when testing CSS properties
+ * against this filter
+ * @type String
+ */
+ get regexpString()
+ {
+ // Despite this property being cached, the getter is called
+ // several times on Safari, due to WebKit bug 132872
+ let prop = Object.getOwnPropertyDescriptor(this, "regexpString");
+ if (prop)
+ return prop.value;
+
+ let regexp = Filter.toRegExp(this.regexpSource);
+ Object.defineProperty(this, "regexpString", {value: regexp});
+ return regexp;
+ }
+};
« no previous file with comments | « chrome/locale/en-US/global.properties ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld