| 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, body] = /^(.*?)(#[@?$]?#?)(.*)$/.exec(text); |
| + return domains.replace(/ +/g, "") + separator + body.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,84 +988,118 @@ |
| } |
| 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} body The body of the filter |
| * @constructor |
| * @augments ActiveFilter |
| */ |
| -function ElemHideBase(text, domains, selector) |
| +function ContentFilter(text, domains, body) |
| { |
| ActiveFilter.call(this, text, domains || null); |
| - // Braces are being escaped to prevent CSS rule injection. |
| - this.selector = selector.replace("{", "\\7B ").replace("}", "\\7D "); |
| + this.body = body; |
| } |
| -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 |
| + * The body of the filter |
| * @type {string} |
| */ |
| - selector: null |
| + body: 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: |
| + * <li>"" for an element hiding filter</li> |
|
Manish Jethani
2018/07/11 13:04:26
Using just "-" doesn't work in the HTML version, b
kzar
2018/07/11 17:17:52
Acknowledged.
|
| + * <li>"@" for an element hiding exception filter</li> |
| + * <li>"?" for an element hiding emulation filter</li> |
| + * <li>"$" for a snippet filter</li> |
| + * @param {string} body |
| + * body 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, body) |
| { |
| - // 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, body); |
| + |
| + if (type == "$") |
| + return new SnippetFilter(text, domains, body); |
| 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, body); |
| } |
| - return new ElemHideFilter(text, domains, selector); |
| + return new ElemHideFilter(text, domains, body); |
| }; |
| /** |
| + * 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.body.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 |
| */ |
| function ElemHideFilter(text, domains, selector) |
| @@ -1110,8 +1142,35 @@ |
| { |
| 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", |
| + |
| + /** |
| + * Script that should be executed |
| + * @type {string} |
| + */ |
| + get script() |
| + { |
| + return this.body; |
| + } |
| +}); |