| Index: lib/matcher.js |
| =================================================================== |
| --- a/lib/matcher.js |
| +++ b/lib/matcher.js |
| @@ -25,25 +25,33 @@ |
| // Make sure that filters don't apply to extension pages. We shouldn't allow |
| // users to break our options page unintentionally, recovering is very hard |
| // if they do. |
| opera.extension.urlfilter.allow.add("widget://*"); |
| var WhitelistFilter = null; |
| var RegExpFilter = null; |
| var resourceTypes = [ |
| - "DOCUMENT", "FONT", "IMAGE", "MEDIA", "OBJECT", "OBJECT_SUBREQUEST", |
| + "FONT", "IMAGE", "MEDIA", "OBJECT", "OBJECT_SUBREQUEST", |
| "OTHER", "SCRIPT", "STYLESHEET", "SUBDOCUMENT", "XMLHTTPREQUEST" |
| ]; |
| require.scopes.matcher = |
| { |
| + init: function() |
| + { |
| + WhitelistFilter = require("filterClasses").WhitelistFilter; |
| + RegExpFilter = require("filterClasses").RegExpFilter; |
| + }, |
| + |
| defaultMatcher: |
| { |
| _rules: {}, |
| + _domainExceptions: {}, |
| + _domainExceptionsTimeout: null, |
| /** |
| * 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*/ |
| { |
| @@ -134,61 +142,116 @@ |
| * 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; |
| }, |
| + /** |
| + * Checks whether the filter is a domain exception and adds/removes it |
| + * according to the add parameter. Returns true if a domain exception |
| + * has been processed, false otherwise. |
| + */ |
| + _processDomainException: function(/**Filter*/ filter, /**Boolean*/ add) /**Boolean*/ |
| + { |
| + if (!(filter instanceof WhitelistFilter) || |
| + filter.contentType != RegExpFilter.typeMap.DOCUMENT || |
| + filter.domainSource) |
| + { |
| + return false; |
| + } |
| + |
| + var match = /^\|\|([^\/]+)\^$/.exec(filter.regexpSource); |
| + if (!match) |
| + return false; |
| + |
| + var domain = match[1]; |
| + if (add) |
| + this._domainExceptions[domain] = true; |
| + else |
| + delete this._domainExceptions[domain]; |
| + |
| + this._updateDomainExceptions(); |
| + return true; |
| + }, |
| + |
| + /** |
| + * Updates domain exceptions rule, execution happens delayed to prevent |
| + * multiple subsequent updates. |
| + */ |
| + _updateDomainExceptions: function() |
| + { |
| + if (this._domainExceptionsTimeout) |
| + window.clearTimeout(this._domainExceptionsTimeout); |
| + |
| + this._domainExceptionsTimeout = window.setTimeout(function() |
| + { |
| + this._domainExceptionsTimeout = null; |
| + opera.extension.urlfilter.allow.remove("*:*"); |
| + |
| + var domains = Object.keys(this._domainExceptions); |
| + if (domains.length) |
| + { |
| + opera.extension.urlfilter.allow.add("*:*", { |
| + includeDomains: domains |
| + }); |
| + } |
| + }.bind(this), 0); |
| + }, |
| + |
| add: function(filter) |
| { |
| + if (this._processDomainException(filter, true)) |
| + return; |
| + |
| if (filter.text in this._rules) |
| return; |
| if (!filter.regexpSource) // Regular expressions aren't supported |
| 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 (this._processDomainException(filter, false)) |
| + return; |
| + |
| 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 = {}; |
| + |
| + this._domainExceptions = {}; |
| + this._updateDomainExceptions(); |
| } |
| } |
| }; |
| })(); |