| Index: lib/matcher.js |
| =================================================================== |
| new file mode 100644 |
| --- /dev/null |
| +++ b/lib/matcher.js |
| @@ -0,0 +1,175 @@ |
| +/* |
| + * This Source Code is subject to the terms of the Mozilla Public License |
| + * version 2.0 (the "License"). You can obtain a copy of the License at |
| + * http://mozilla.org/MPL/2.0/. |
| + */ |
| + |
| +// |
| +// This mimicks the API of the Matcher module in ABP/Firefox but users Opera's |
| +// URLFilter API. |
| +// |
| + |
| +(function() |
| +{ |
| + var WhitelistFilter = null; |
| + var RegExpFilter = null; |
| + var resourceTypes = [ |
| + "DOCUMENT", "FONT", "IMAGE", "MEDIA", "OBJECT", "OBJECT_SUBREQUEST", |
| + "OTHER", "SCRIPT", "STYLESHEET", "SUBDOCUMENT", "XMLHTTPREQUEST" |
| + ]; |
| + |
| + require.scopes.matcher = |
| + { |
| + defaultMatcher: |
| + { |
| + _rules: {}, |
| + |
| + /** |
| + * Converts rule text from Adblock Plus format (implicit * at beginning |
| + * and end of the rule unless there is an anchor) to Opera format (* has |
| + * to be specified explicitly). |
| + */ |
| + _getRuleText: function(/**Filter*/ filter) /**String*/ |
| + { |
| + var text = filter.regexpSource; |
| + |
| + // |foo => foo |
| + // foo => *foo |
| + // *foo and ||foo stay unchanged |
| + if (text.substr(0, 2) != "||") |
| + { |
| + var start = text.substr(0, 1); |
| + if (start == "|") |
| + text = text.slice(1); |
| + else if (start != "*") |
| + text = "*" + text; |
| + } |
| + |
| + // foo| => foo |
| + // foo => foo* |
| + // foo* stays unchanged |
| + var end = text.substr(-1); |
| + if (end == "|") |
| + text = text.slice(0, -1); |
| + else if (end != "*") |
| + text = text + "*"; |
| + |
| + return text; |
| + }, |
| + |
| + /** |
| + * Converts type options of a filter into a bit mask as expected by Opera. |
| + */ |
| + _getRuleTypes: function(/**Filter*/ filter) /**Integer*/ |
| + { |
| + var types = 0; |
| + var urlfilter = opera.extension.urlfilter; |
| + for (var i = 0; i < resourceTypes.length; i++) |
| + { |
| + var type = resourceTypes[i]; |
| + if (filter.contentType & RegExpFilter.typeMap[type]) |
| + types |= urlfilter["RESOURCE_" + type]; |
| + } |
| + return types; |
| + }, |
| + |
| + /** |
| + * Converts domain options of a filter into includeDomains/excludeDomains |
| + * options as expected by Opera. The options object has to be passed in, |
| + * properties will be added to it if necessary. |
| + */ |
| + _getRuleDomains: function(/**Filter*/ filter, /**Object*/ options) |
| + { |
| + if (filter.domainSource) |
| + { |
| + var domains = filter.domainSource.split(filter.domainSeparator); |
| + for (var i = 0; i < domains.length; i++) |
| + { |
| + var domain = domains[i]; |
| + if (domain == "") |
| + continue; |
| + |
| + var type = "includeDomains"; |
| + if (domain[0] == "~") |
| + { |
| + type = "excludeDomains"; |
| + domain = domain.substr(1); |
| + } |
| + if (!(type in options)) |
| + options[type] = []; |
| + options[type].push(domain); |
| + } |
| + } |
| + }, |
| + |
| + /** |
| + * Converts third-party filter option to the format expected by Opera. |
| + * The options object has to be passed in, a property will be added to it |
| + * if necessary. |
| + */ |
| + _getRuleThirdParty: function(/**Filter*/ filter, /**Object*/ options) |
| + { |
| + if (filter.thirdParty !== null) |
| + options.thirdParty = filter.thirdParty; |
| + }, |
| + |
| + /** |
| + * Converts an Adblock Plus filter to a rule that can be processed by |
| + * Opera. The following options will be set: |
| + * |
| + * type: urlfilter to be used, either "allow" or "block" |
| + * text: rule text |
| + * options: rule options |
| + */ |
| + _generateRule: function(/**Filter*/ filter) /**Object*/ |
| + { |
| + if (!WhitelistFilter) |
| + { |
| + WhitelistFilter = require("filterClasses").WhitelistFilter; |
| + RegExpFilter = require("filterClasses").RegExpFilter; |
| + } |
| + |
| + var rule = { |
| + type: filter instanceof WhitelistFilter ? "allow" : "block", |
| + text: this._getRuleText(filter), |
| + options: { |
| + resources: this._getRuleTypes(filter) |
| + } |
| + }; |
| + this._getRuleDomains(filter, rule.options); |
| + this._getRuleThirdParty(filter, rule.options); |
| + return rule; |
| + }, |
| + |
| + add: function(filter) |
| + { |
| + if (filter.text in this._rules) |
| + return; |
| + |
| + var rule = this._generateRule(filter); |
| + opera.extension.urlfilter[rule.type].add(rule.text, rule.options); |
| + this._rules[filter.text] = rule; |
| + }, |
| + |
| + remove: function(filter) |
| + { |
| + if (!(filter.text in this._rules)) |
| + return; |
| + |
| + var rule = this._rules[filter.text]; |
| + opera.extension.urlfilter[rule.type].remove(rule.text); |
| + delete this._rules[filter.text]; |
| + }, |
| + |
| + clear: function() |
| + { |
| + for (var text in this._rules) |
| + { |
| + var rule = this._rules[text]; |
| + opera.extension.urlfilter[rule.type].remove(rule.text); |
| + } |
| + this._rules = {}; |
| + } |
| + } |
| + }; |
| +})(); |