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

Unified Diff: lib/filterClasses.js

Issue 29737558: Issue 6538, 6781 - Implement support for snippet filters (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Patch Set: Rebase Created July 6, 2018, 1:36 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 | « no previous file | lib/filterListener.js » ('j') | 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
@@ -79,20 +79,20 @@
/**
* Cache for known filters, maps string representation to filter objects.
* @type {Map.<string,Filter>}
*/
Filter.knownFilters = new Map();
/**
- * Regular expression that element hiding filters should match
+ * Regular expression that content filters should match
* @type {RegExp}
*/
-Filter.elemhideRegExp = /^([^/*|@"!]*?)#([@?])?#(.+)$/;
+Filter.contentRegExp = /^([^/*|@"!]*?)#([@?$])?#(.+)$/;
/**
* 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}
@@ -112,34 +112,32 @@
* @return {Filter}
*/
Filter.fromText = function(text)
{
let filter = Filter.knownFilters.get(text);
if (filter)
return filter;
- let match = (text.includes("#") ? Filter.elemhideRegExp.exec(text) : null);
+ let match = text.includes("#") ? Filter.contentRegExp.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}`);
}
- filter = ElemHideBase.fromText(
- text, match[1], match[2], match[3]
- );
+ filter = ContentFilter.fromText(text, match[1], match[2], match[3]);
}
else if (text[0] == "!")
filter = new CommentFilter(text);
else
filter = RegExpFilter.fromText(text);
Filter.knownFilters.set(filter.text, filter);
return filter;
@@ -179,22 +177,22 @@
// Remove line breaks, tabs etc
text = text.replace(/[^\S ]+/g, "");
// Don't remove spaces inside comments
if (/^ *!/.test(text))
return text.trim();
- // Special treatment for element hiding filters, right side is allowed to
- // contain spaces
- if (Filter.elemhideRegExp.test(text))
+ // Special treatment for content filters, right side is allowed to contain
+ // spaces
+ if (Filter.contentRegExp.test(text))
{
- let [, domains, separator, selector] = /^(.*?)(#[@?]?#?)(.*)$/.exec(text);
- return domains.replace(/ +/g, "") + separator + selector.trim();
+ let [, domains, separator, script] = /^(.*?)(#[@?$]?#?)(.*)$/.exec(text);
+ return domains.replace(/ +/g, "") + separator + script.trim();
}
// For most regexp filters we strip all spaces, but $csp filter options
// are allowed to contain single (non trailing) spaces.
let strippedText = text.replace(/ +/g, "");
if (!strippedText.includes("$") || !/\bcsp=/i.test(strippedText))
return strippedText;
@@ -990,83 +988,114 @@
}
exports.WhitelistFilter = WhitelistFilter;
WhitelistFilter.prototype = extend(RegExpFilter, {
type: "whitelist"
});
/**
- * Base class for element hiding filters
+ * Base class for content filters
* @param {string} text see {@link Filter Filter()}
* @param {string} [domains] Host names or domains the filter should be
* restricted to
- * @param {string} selector CSS selector for the HTML elements that should be
- * hidden
+ * @param {string} script Script that should be executed
* @constructor
* @augments ActiveFilter
*/
-function ElemHideBase(text, domains, selector)
+function ContentFilter(text, domains, script)
{
ActiveFilter.call(this, text, domains || null);
- // Braces are being escaped to prevent CSS rule injection.
- this.selector = selector.replace("{", "\\7B ").replace("}", "\\7D ");
+ this.script = script;
}
-exports.ElemHideBase = ElemHideBase;
+exports.ContentFilter = ContentFilter;
-ElemHideBase.prototype = extend(ActiveFilter, {
+ContentFilter.prototype = extend(ActiveFilter, {
/**
* @see ActiveFilter.domainSeparator
*/
domainSeparator: ",",
/**
- * CSS selector for the HTML elements that should be hidden
+ * Script that should be executed
* @type {string}
*/
- selector: null
+ script: null
});
/**
- * Creates an element hiding filter from a pre-parsed text representation
+ * Creates a content filter from a pre-parsed text representation
*
* @param {string} text same as in Filter()
* @param {string} [domains]
* domains part of the text representation
* @param {string} [type]
-* rule type, either empty or @ (exception) or ? (emulation rule)
- * @param {string} selector raw CSS selector
+ * rule type, either empty or @ (exception) or ? (emulation rule) or
+ * $ (snippet)
+ * @param {string} script
+ * script part of the text representation, either a CSS selector or a snippet
+ * script
* @return {ElemHideFilter|ElemHideException|
- * ElemHideEmulationFilter|InvalidFilter}
+ * ElemHideEmulationFilter|SnippetFilter|InvalidFilter}
*/
-ElemHideBase.fromText = function(text, domains, type, selector)
+ContentFilter.fromText = function(text, domains, type, script)
{
- // 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.
+ // We don't allow content filters which have any empty domains.
+ // Note: The ContentFilter.prototype.domainSeparator is duplicated here, if
+ // that changes this must be changed too.
if (domains && /(^|,)~?(,|$)/.test(domains))
return new InvalidFilter(text, "filter_invalid_domain");
if (type == "@")
- return new ElemHideException(text, domains, selector);
+ return new ElemHideException(text, domains, script);
+
+ if (type == "$")
+ return new SnippetFilter(text, domains, script);
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("," + domains))
return new InvalidFilter(text, "filter_elemhideemulation_nodomain");
- return new ElemHideEmulationFilter(text, domains, selector);
+ return new ElemHideEmulationFilter(text, domains, script);
}
- return new ElemHideFilter(text, domains, selector);
+ return new ElemHideFilter(text, domains, script);
};
+/*
+ * Base class for element hiding filters
+ * @param {string} text see {@link Filter Filter()}
+ * @param {string} [domains] see {@link ContentFilter ContentFilter()}
+ * @param {string} selector CSS selector for the HTML elements that should be
+ * hidden
+ * @constructor
+ * @augments ContentFilter
+ */
+function ElemHideBase(text, domains, selector)
+{
+ ContentFilter.call(this, text, domains, selector);
+}
+exports.ElemHideBase = ElemHideBase;
+
+ElemHideBase.prototype = extend(ContentFilter, {
+ /**
+ * CSS selector for the HTML elements that should be hidden
+ * @type {string}
+ */
+ get selector()
+ {
+ // Braces are being escaped to prevent CSS rule injection.
+ return this.script.replace("{", "\\7B ").replace("}", "\\7D ");
+ }
+});
+
/**
* Class for element hiding filters
* @param {string} text see {@link Filter Filter()}
* @param {string} [domains] see {@link ElemHideBase ElemHideBase()}
* @param {string} selector see {@link ElemHideBase ElemHideBase()}
* @constructor
* @augments ElemHideBase
*/
@@ -1110,8 +1139,26 @@
{
ElemHideBase.call(this, text, domains, selector);
}
exports.ElemHideEmulationFilter = ElemHideEmulationFilter;
ElemHideEmulationFilter.prototype = extend(ElemHideBase, {
type: "elemhideemulation"
});
+
+/**
+ * Class for snippet filters
+ * @param {string} text see Filter()
+ * @param {string} [domains] see ContentFilter()
+ * @param {string} script Script that should be executed
+ * @constructor
+ * @augments ContentFilter
+ */
+function SnippetFilter(text, domains, script)
+{
+ ContentFilter.call(this, text, domains, script);
+}
+exports.SnippetFilter = SnippetFilter;
+
+SnippetFilter.prototype = extend(ContentFilter, {
+ type: "snippet"
+});
« no previous file with comments | « no previous file | lib/filterListener.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld