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

Unified Diff: lib/filterClasses.js

Issue 29335650: Issue 2595 - Use the core code from adblockpluscore (Closed)
Patch Set: Created Feb. 4, 2016, 6:35 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 | « lib/elemHide.js ('k') | lib/filterListener.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/filterClasses.js
===================================================================
deleted file mode 100644
--- a/lib/filterClasses.js
+++ /dev/null
@@ -1,1070 +0,0 @@
-/*
- * This file is part of Adblock Plus <https://adblockplus.org/>,
- * Copyright (C) 2006-2016 Eyeo GmbH
- *
- * Adblock Plus is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * Adblock Plus is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @fileOverview Definition of Filter class and its subclasses.
- */
-
-let {FilterNotifier} = require("filterNotifier");
-let {Utils} = require("utils");
-
-/**
- * Abstract base class for filters
- *
- * @param {String} text string representation of the filter
- * @constructor
- */
-function Filter(text)
-{
- this.text = text;
- this.subscriptions = [];
-}
-exports.Filter = Filter;
-
-Filter.prototype =
-{
- /**
- * String representation of the filter
- * @type String
- */
- text: null,
-
- /**
- * Filter subscriptions the filter belongs to
- * @type Subscription[]
- */
- subscriptions: null,
-
- /**
- * Filter type as a string, e.g. "blocking".
- * @type String
- */
- get type()
- {
- throw new Error("Please define filter type in the subclass");
- },
-
- /**
- * Serializes the filter to an array of strings for writing out on the disk.
- * @param {string[]} buffer buffer to push the serialization results into
- */
- serialize: function(buffer)
- {
- buffer.push("[Filter]");
- buffer.push("text=" + this.text);
- },
-
- toString: function()
- {
- return this.text;
- }
-};
-
-/**
- * Cache for known filters, maps string representation to filter objects.
- * @type Object
- */
-Filter.knownFilters = Object.create(null);
-
-/**
- * Regular expression that element hiding filters should match
- * @type RegExp
- */
-Filter.elemhideRegExp = /^([^\/\*\|\@"!]*?)#(\@)?(?:([\w\-]+|\*)((?:\([\w\-]+(?:[$^*]?=[^\(\)"]*)?\))*)|#([^{}]+))$/;
-/**
- * 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
- */
-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
- * calls the right constructor then.
- *
- * @param {String} text as in Filter()
- * @return {Filter}
- */
-Filter.fromText = function(text)
-{
- if (text in Filter.knownFilters)
- return Filter.knownFilters[text];
-
- let ret;
- let match = (text.indexOf("#") >= 0 ? Filter.elemhideRegExp.exec(text) : null);
- if (match)
- ret = ElemHideBase.fromText(text, match[1], !!match[2], match[3], match[4], match[5]);
- else if (text[0] == "!")
- ret = new CommentFilter(text);
- else
- ret = RegExpFilter.fromText(text);
-
- Filter.knownFilters[ret.text] = ret;
- return ret;
-};
-
-/**
- * Deserializes a filter
- *
- * @param {Object} obj map of serialized properties and their values
- * @return {Filter} filter or null if the filter couldn't be created
- */
-Filter.fromObject = function(obj)
-{
- let ret = Filter.fromText(obj.text);
- if (ret instanceof ActiveFilter)
- {
- if ("disabled" in obj)
- ret._disabled = (obj.disabled == "true");
- if ("hitCount" in obj)
- ret._hitCount = parseInt(obj.hitCount) || 0;
- if ("lastHit" in obj)
- ret._lastHit = parseInt(obj.lastHit) || 0;
- }
- return ret;
-};
-
-/**
- * Removes unnecessary whitespaces from filter text, will only return null if
- * the input parameter is null.
- */
-Filter.normalize = function(/**String*/ text) /**String*/
-{
- if (!text)
- return text;
-
- // Remove line breaks and such
- text = text.replace(/[^\S ]/g, "");
-
- if (/^\s*!/.test(text))
- {
- // Don't remove spaces inside comments
- return text.trim();
- }
- else if (Filter.elemhideRegExp.test(text))
- {
- // Special treatment for element hiding filters, right side is allowed to contain spaces
- let [, domain, separator, selector] = /^(.*?)(#\@?#?)(.*)$/.exec(text);
- return domain.replace(/\s/g, "") + separator + selector.trim();
- }
- else
- return text.replace(/\s/g, "");
-};
-
-/**
- * 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
- * @constructor
- * @augments Filter
- */
-function InvalidFilter(text, reason)
-{
- Filter.call(this, text);
-
- this.reason = reason;
-}
-exports.InvalidFilter = InvalidFilter;
-
-InvalidFilter.prototype =
-{
- __proto__: Filter.prototype,
-
- type: "invalid",
-
- /**
- * Reason why this filter is invalid
- * @type String
- */
- reason: null,
-
- /**
- * See Filter.serialize()
- */
- serialize: function(buffer) {}
-};
-
-/**
- * Class for comments
- * @param {String} text see Filter()
- * @constructor
- * @augments Filter
- */
-function CommentFilter(text)
-{
- Filter.call(this, text);
-}
-exports.CommentFilter = CommentFilter;
-
-CommentFilter.prototype =
-{
- __proto__: Filter.prototype,
-
- type: "comment",
-
- /**
- * See Filter.serialize()
- */
- serialize: function(buffer) {}
-};
-
-/**
- * Abstract base class for filters that can get hits
- * @param {String} text see Filter()
- * @param {String} [domains] Domains that the filter is restricted to separated by domainSeparator e.g. "foo.com|bar.com|~baz.com"
- * @constructor
- * @augments Filter
- */
-function ActiveFilter(text, domains)
-{
- Filter.call(this, text);
-
- this.domainSource = domains;
-}
-exports.ActiveFilter = ActiveFilter;
-
-ActiveFilter.prototype =
-{
- __proto__: Filter.prototype,
-
- _disabled: false,
- _hitCount: 0,
- _lastHit: 0,
-
- /**
- * Defines whether the filter is disabled
- * @type Boolean
- */
- get disabled()
- {
- return this._disabled;
- },
- set disabled(value)
- {
- if (value != this._disabled)
- {
- let oldValue = this._disabled;
- this._disabled = value;
- FilterNotifier.triggerListeners("filter.disabled", this, value, oldValue);
- }
- return this._disabled;
- },
-
- /**
- * Number of hits on the filter since the last reset
- * @type Number
- */
- get hitCount()
- {
- return this._hitCount;
- },
- set hitCount(value)
- {
- if (value != this._hitCount)
- {
- let oldValue = this._hitCount;
- this._hitCount = value;
- FilterNotifier.triggerListeners("filter.hitCount", this, value, oldValue);
- }
- return this._hitCount;
- },
-
- /**
- * Last time the filter had a hit (in milliseconds since the beginning of the epoch)
- * @type Number
- */
- get lastHit()
- {
- return this._lastHit;
- },
- set lastHit(value)
- {
- if (value != this._lastHit)
- {
- let oldValue = this._lastHit;
- this._lastHit = value;
- FilterNotifier.triggerListeners("filter.lastHit", this, value, oldValue);
- }
- return this._lastHit;
- },
-
- /**
- * String that the domains property should be generated from
- * @type String
- */
- domainSource: null,
-
- /**
- * Separator character used in domainSource property, must be overridden by subclasses
- * @type String
- */
- domainSeparator: null,
-
- /**
- * Determines whether the trailing dot in domain names isn't important and
- * should be ignored, must be overridden by subclasses.
- * @type Boolean
- */
- ignoreTrailingDot: true,
-
- /**
- * Determines whether domainSource is already upper-case,
- * can be overridden by subclasses.
- * @type Boolean
- */
- domainSourceIsUpperCase: false,
-
- /**
- * Map containing domains that this filter should match on/not match on or null if the filter should match on all domains
- * @type Object
- */
- get domains()
- {
- // Despite this property being cached, the getter is called
- // several times on Safari, due to WebKit bug 132872
- let prop = Object.getOwnPropertyDescriptor(this, "domains");
- if (prop)
- return prop.value;
-
- let domains = null;
-
- if (this.domainSource)
- {
- let source = this.domainSource;
- if (!this.domainSourceIsUpperCase) {
- // RegExpFilter already have uppercase domains
- source = source.toUpperCase();
- }
- let list = source.split(this.domainSeparator);
- if (list.length == 1 && list[0][0] != "~")
- {
- // Fast track for the common one-domain scenario
- domains = {__proto__: null, "": false};
- if (this.ignoreTrailingDot)
- list[0] = list[0].replace(/\.+$/, "");
- domains[list[0]] = true;
- }
- else
- {
- let hasIncludes = false;
- for (let i = 0; i < list.length; i++)
- {
- let domain = list[i];
- if (this.ignoreTrailingDot)
- domain = domain.replace(/\.+$/, "");
- if (domain == "")
- continue;
-
- let include;
- if (domain[0] == "~")
- {
- include = false;
- domain = domain.substr(1);
- }
- else
- {
- include = true;
- hasIncludes = true;
- }
-
- if (!domains)
- domains = Object.create(null);
-
- domains[domain] = include;
- }
- domains[""] = !hasIncludes;
- }
-
- this.domainSource = null;
- }
-
- Object.defineProperty(this, "domains", {value: domains, enumerable: true});
- return this.domains;
- },
-
- /**
- * Array containing public keys of websites that this filter should apply to
- * @type string[]
- */
- sitekeys: null,
-
- /**
- * Checks whether this filter is active on a domain.
- * @param {String} docDomain domain name of the document that loads the URL
- * @param {String} [sitekey] public key provided by the document
- * @return {Boolean} true in case of the filter being active
- */
- isActiveOnDomain: function(docDomain, sitekey)
- {
- // Sitekeys are case-sensitive so we shouldn't convert them to upper-case to avoid false
- // positives here. Instead we need to change the way filter options are parsed.
- if (this.sitekeys && (!sitekey || this.sitekeys.indexOf(sitekey.toUpperCase()) < 0))
- return false;
-
- // If no domains are set the rule matches everywhere
- if (!this.domains)
- return true;
-
- // If the document has no host name, match only if the filter isn't restricted to specific domains
- if (!docDomain)
- return this.domains[""];
-
- if (this.ignoreTrailingDot)
- docDomain = docDomain.replace(/\.+$/, "");
- docDomain = docDomain.toUpperCase();
-
- while (true)
- {
- if (docDomain in this.domains)
- return this.domains[docDomain];
-
- let nextDot = docDomain.indexOf(".");
- if (nextDot < 0)
- break;
- docDomain = docDomain.substr(nextDot + 1);
- }
- return this.domains[""];
- },
-
- /**
- * Checks whether this filter is active only on a domain and its subdomains.
- */
- isActiveOnlyOnDomain: function(/**String*/ docDomain) /**Boolean*/
- {
- if (!docDomain || !this.domains || this.domains[""])
- return false;
-
- if (this.ignoreTrailingDot)
- docDomain = docDomain.replace(/\.+$/, "");
- docDomain = docDomain.toUpperCase();
-
- for (let domain in this.domains)
- if (this.domains[domain] && domain != docDomain && (domain.length <= docDomain.length || domain.indexOf("." + docDomain) != domain.length - docDomain.length - 1))
- return false;
-
- return true;
- },
-
- /**
- * Checks whether this filter is generic or specific
- */
- isGeneric: function() /**Boolean*/
- {
- return !(this.sitekeys && this.sitekeys.length) &&
- (!this.domains || this.domains[""]);
- },
-
- /**
- * See Filter.serialize()
- */
- serialize: function(buffer)
- {
- if (this._disabled || this._hitCount || this._lastHit)
- {
- Filter.prototype.serialize.call(this, buffer);
- if (this._disabled)
- buffer.push("disabled=true");
- if (this._hitCount)
- buffer.push("hitCount=" + this._hitCount);
- if (this._lastHit)
- buffer.push("lastHit=" + this._lastHit);
- }
- }
-};
-
-/**
- * Abstract base class for RegExp-based filters
- * @param {String} text see Filter()
- * @param {String} regexpSource filter part that the regular expression should be build from
- * @param {Number} [contentType] Content types the filter applies to, combination of values from RegExpFilter.typeMap
- * @param {Boolean} [matchCase] Defines whether the filter should distinguish between lower and upper case letters
- * @param {String} [domains] Domains that the filter is restricted to, e.g. "foo.com|bar.com|~baz.com"
- * @param {Boolean} [thirdParty] Defines whether the filter should apply to third-party or first-party content only
- * @param {String} [sitekeys] Public keys of websites that this filter should apply to
- * @constructor
- * @augments ActiveFilter
- */
-function RegExpFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys)
-{
- ActiveFilter.call(this, text, domains, sitekeys);
-
- if (contentType != null)
- this.contentType = contentType;
- if (matchCase)
- this.matchCase = matchCase;
- if (thirdParty != null)
- this.thirdParty = thirdParty;
- if (sitekeys != null)
- this.sitekeySource = sitekeys;
-
- if (regexpSource.length >= 2 && regexpSource[0] == "/" && regexpSource[regexpSource.length - 1] == "/")
- {
- // The filter is a regular expression - convert it immediately to catch syntax errors
- let regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2), this.matchCase ? "" : "i");
- Object.defineProperty(this, "regexp", {value: regexp});
- }
- else
- {
- // No need to convert this filter to regular expression yet, do it on demand
- this.regexpSource = regexpSource;
- }
-}
-exports.RegExpFilter = RegExpFilter;
-
-RegExpFilter.prototype =
-{
- __proto__: ActiveFilter.prototype,
-
- /**
- * @see ActiveFilter.domainSourceIsUpperCase
- */
- domainSourceIsUpperCase: true,
-
- /**
- * Number of filters contained, will always be 1 (required to optimize Matcher).
- * @type Integer
- */
- length: 1,
-
- /**
- * @see ActiveFilter.domainSeparator
- */
- domainSeparator: "|",
-
- /**
- * Expression from which a regular expression should be generated - for delayed creation of the regexp property
- * @type String
- */
- regexpSource: null,
- /**
- * Regular expression to be used when testing against this filter
- * @type RegExp
- */
- get regexp()
- {
- // 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, this.matchCase ? "" : "i");
- Object.defineProperty(this, "regexp", {value: regexp});
- return regexp;
- },
- /**
- * Content types the filter applies to, combination of values from RegExpFilter.typeMap
- * @type Number
- */
- contentType: 0x7FFFFFFF,
- /**
- * Defines whether the filter should distinguish between lower and upper case letters
- * @type Boolean
- */
- matchCase: false,
- /**
- * Defines whether the filter should apply to third-party or first-party content only. Can be null (apply to all content).
- * @type Boolean
- */
- thirdParty: null,
-
- /**
- * String that the sitekey property should be generated from
- * @type String
- */
- sitekeySource: null,
-
- /**
- * Array containing public keys of websites that this filter should apply to
- * @type string[]
- */
- get sitekeys()
- {
- // Despite this property being cached, the getter is called
- // several times on Safari, due to WebKit bug 132872
- let prop = Object.getOwnPropertyDescriptor(this, "sitekeys");
- if (prop)
- return prop.value;
-
- let sitekeys = null;
-
- if (this.sitekeySource)
- {
- sitekeys = this.sitekeySource.split("|");
- this.sitekeySource = null;
- }
-
- Object.defineProperty(this, "sitekeys", {value: sitekeys, enumerable: true});
- return this.sitekeys;
- },
-
- /**
- * Tests whether the URL matches this filter
- * @param {String} location URL to be tested
- * @param {String} typeMask bitmask of content / request types to match
- * @param {String} docDomain domain name of the document that loads the URL
- * @param {Boolean} thirdParty should be true if the URL is a third-party request
- * @param {String} sitekey public key provided by the document
- * @return {Boolean} true in case of a match
- */
- matches: function(location, typeMask, docDomain, thirdParty, sitekey)
- {
- if (this.contentType & typeMask &&
- (this.thirdParty == null || this.thirdParty == thirdParty) &&
- this.isActiveOnDomain(docDomain, sitekey) && this.regexp.test(location))
- {
- return true;
- }
-
- return false;
- }
-};
-
-// Required to optimize Matcher, see also RegExpFilter.prototype.length
-Object.defineProperty(RegExpFilter.prototype, "0",
-{
- get: function() { return this; }
-});
-
-/**
- * Creates a RegExp filter from its text representation
- * @param {String} text same as in Filter()
- */
-RegExpFilter.fromText = function(text)
-{
- let blocking = true;
- let origText = text;
- if (text.indexOf("@@") == 0)
- {
- blocking = false;
- text = text.substr(2);
- }
-
- let contentType = null;
- let matchCase = null;
- let domains = null;
- let sitekeys = null;
- let thirdParty = null;
- let collapse = null;
- let options;
- let match = (text.indexOf("$") >= 0 ? Filter.optionsRegExp.exec(text) : null);
- if (match)
- {
- options = match[1].toUpperCase().split(",");
- text = match.input.substr(0, match.index);
- for (let option of options)
- {
- let value = null;
- let separatorIndex = option.indexOf("=");
- if (separatorIndex >= 0)
- {
- value = option.substr(separatorIndex + 1);
- option = option.substr(0, separatorIndex);
- }
- option = option.replace(/-/, "_");
- if (option in RegExpFilter.typeMap)
- {
- if (contentType == null)
- contentType = 0;
- contentType |= RegExpFilter.typeMap[option];
- }
- else if (option[0] == "~" && option.substr(1) in RegExpFilter.typeMap)
- {
- if (contentType == null)
- contentType = RegExpFilter.prototype.contentType;
- contentType &= ~RegExpFilter.typeMap[option.substr(1)];
- }
- else if (option == "MATCH_CASE")
- matchCase = true;
- else if (option == "~MATCH_CASE")
- matchCase = false;
- else if (option == "DOMAIN" && typeof value != "undefined")
- domains = value;
- else if (option == "THIRD_PARTY")
- thirdParty = true;
- else if (option == "~THIRD_PARTY")
- thirdParty = false;
- else if (option == "COLLAPSE")
- collapse = true;
- else if (option == "~COLLAPSE")
- collapse = false;
- else if (option == "SITEKEY" && typeof value != "undefined")
- sitekeys = value;
- else
- return new InvalidFilter(origText, "Unknown option " + option.toLowerCase());
- }
- }
-
- try
- {
- if (blocking)
- return new BlockingFilter(origText, text, contentType, matchCase, domains, thirdParty, sitekeys, collapse);
- else
- return new WhitelistFilter(origText, text, contentType, matchCase, domains, thirdParty, sitekeys);
- }
- catch (e)
- {
- return new InvalidFilter(origText, e);
- }
-};
-
-/**
- * Maps type strings like "SCRIPT" or "OBJECT" to bit masks
- */
-RegExpFilter.typeMap = {
- OTHER: 1,
- SCRIPT: 2,
- IMAGE: 4,
- STYLESHEET: 8,
- OBJECT: 16,
- SUBDOCUMENT: 32,
- DOCUMENT: 64,
- XBL: 1,
- PING: 1024,
- XMLHTTPREQUEST: 2048,
- OBJECT_SUBREQUEST: 4096,
- DTD: 1,
- MEDIA: 16384,
- FONT: 32768,
-
- BACKGROUND: 4, // Backwards compat, same as IMAGE
-
- POPUP: 0x10000000,
- GENERICBLOCK: 0x20000000,
- ELEMHIDE: 0x40000000,
- GENERICHIDE: 0x80000000
-};
-
-// DOCUMENT, ELEMHIDE, POPUP, GENERICHIDE and GENERICBLOCK options shouldn't
-// be there by default
-RegExpFilter.prototype.contentType &= ~(RegExpFilter.typeMap.DOCUMENT |
- RegExpFilter.typeMap.ELEMHIDE |
- RegExpFilter.typeMap.POPUP |
- RegExpFilter.typeMap.GENERICHIDE |
- RegExpFilter.typeMap.GENERICBLOCK);
-
-/**
- * Class for blocking filters
- * @param {String} text see Filter()
- * @param {String} regexpSource see RegExpFilter()
- * @param {Number} contentType see RegExpFilter()
- * @param {Boolean} matchCase see RegExpFilter()
- * @param {String} domains see RegExpFilter()
- * @param {Boolean} thirdParty see RegExpFilter()
- * @param {String} sitekeys see RegExpFilter()
- * @param {Boolean} collapse defines whether the filter should collapse blocked content, can be null
- * @constructor
- * @augments RegExpFilter
- */
-function BlockingFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys, collapse)
-{
- RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys);
-
- this.collapse = collapse;
-}
-exports.BlockingFilter = BlockingFilter;
-
-BlockingFilter.prototype =
-{
- __proto__: RegExpFilter.prototype,
-
- type: "blocking",
-
- /**
- * Defines whether the filter should collapse blocked content. Can be null (use the global preference).
- * @type Boolean
- */
- collapse: null
-};
-
-/**
- * Class for whitelist filters
- * @param {String} text see Filter()
- * @param {String} regexpSource see RegExpFilter()
- * @param {Number} contentType see RegExpFilter()
- * @param {Boolean} matchCase see RegExpFilter()
- * @param {String} domains see RegExpFilter()
- * @param {Boolean} thirdParty see RegExpFilter()
- * @param {String} sitekeys see RegExpFilter()
- * @constructor
- * @augments RegExpFilter
- */
-function WhitelistFilter(text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys)
-{
- RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, thirdParty, sitekeys);
-}
-exports.WhitelistFilter = WhitelistFilter;
-
-WhitelistFilter.prototype =
-{
- __proto__: RegExpFilter.prototype,
-
- type: "whitelist"
-};
-
-/**
- * Base class for element hiding filters
- * @param {String} text see 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
- * @constructor
- * @augments ActiveFilter
- */
-function ElemHideBase(text, domains, selector)
-{
- ActiveFilter.call(this, text, domains || null);
-
- if (domains)
- this.selectorDomain = domains.replace(/,~[^,]+/g, "").replace(/^~[^,]+,?/, "").toLowerCase();
- this.selector = selector;
-}
-exports.ElemHideBase = ElemHideBase;
-
-ElemHideBase.prototype =
-{
- __proto__: ActiveFilter.prototype,
-
- /**
- * @see ActiveFilter.domainSeparator
- */
- domainSeparator: ",",
-
- /**
- * @see ActiveFilter.ignoreTrailingDot
- */
- ignoreTrailingDot: false,
-
- /**
- * Host name or domain the filter should be restricted to (can be null for no restriction)
- * @type String
- */
- selectorDomain: null,
- /**
- * CSS selector for the HTML elements that should be hidden
- * @type String
- */
- selector: null
-};
-
-/**
- * Creates an element hiding filter from a pre-parsed text representation
- *
- * @param {String} text same as in Filter()
- * @param {String} domain domain part of the text representation (can be empty)
- * @param {Boolean} isException exception rule indicator
- * @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|CSSPropertyFilter|InvalidFilter}
- */
-ElemHideBase.fromText = function(text, domain, isException, tagName, attrRules, selector)
-{
- if (!selector)
- {
- if (tagName == "*")
- tagName = "";
-
- let id = null;
- let additional = "";
- if (attrRules)
- {
- attrRules = attrRules.match(/\([\w\-]+(?:[$^*]?=[^\(\)"]*)?\)/g);
- for (let rule of attrRules)
- {
- rule = rule.substr(1, rule.length - 2);
- let separatorPos = rule.indexOf("=");
- if (separatorPos > 0)
- {
- rule = rule.replace(/=/, '="') + '"';
- additional += "[" + rule + "]";
- }
- else
- {
- if (id)
- return new InvalidFilter(text, Utils.getString("filter_elemhide_duplicate_id"));
-
- id = rule;
- }
- }
- }
-
- if (id)
- selector = tagName + "." + id + additional + "," + tagName + "#" + id + additional;
- else if (tagName || additional)
- selector = tagName + additional;
- else
- return new InvalidFilter(text, Utils.getString("filter_elemhide_nocriteria"));
- }
-
- if (isException)
- return new ElemHideException(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);
-};
-
-/**
- * Class for element hiding filters
- * @param {String} text see Filter()
- * @param {String} domains see ElemHideBase()
- * @param {String} selector see ElemHideBase()
- * @constructor
- * @augments ElemHideBase
- */
-function ElemHideFilter(text, domains, selector)
-{
- ElemHideBase.call(this, text, domains, selector);
-}
-exports.ElemHideFilter = ElemHideFilter;
-
-ElemHideFilter.prototype =
-{
- __proto__: ElemHideBase.prototype,
-
- type: "elemhide"
-};
-
-/**
- * Class for element hiding exceptions
- * @param {String} text see Filter()
- * @param {String} domains see ElemHideBase()
- * @param {String} selector see ElemHideBase()
- * @constructor
- * @augments ElemHideBase
- */
-function ElemHideException(text, domains, selector)
-{
- ElemHideBase.call(this, text, domains, selector);
-}
-exports.ElemHideException = ElemHideException;
-
-ElemHideException.prototype =
-{
- __proto__: ElemHideBase.prototype,
-
- type: "elemhideexception"
-};
-
-/**
- * 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,
-
- type: "cssproperty",
-
- /**
- * 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 | « lib/elemHide.js ('k') | lib/filterListener.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld