| Index: lib/matcher.js |
| =================================================================== |
| --- a/lib/matcher.js |
| +++ b/lib/matcher.js |
| @@ -25,25 +25,27 @@ |
| // 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 = |
| { |
| 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 +136,139 @@ |
| * 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; |
| }, |
| + /** |
| + * Extracts the domain to which the exception applies if any. |
| + */ |
| + _getDomainFromException: function(/**Filter*/ filter) /**String*/ |
| + { |
| + if (filter.domainSource) |
| + return null; |
| + |
| + var match = /^\|\|([^\/]+)\^$/.exec(filter.regexpSource); |
| + if (!match) |
| + return null; |
| + |
| + return match[1]; |
| + }, |
| + |
| + /** |
| + * Adds a global exception for a particular document domain. |
| + */ |
| + _addDomainException: function(/**String*/ domain) |
| + { |
| + this._domainExceptions[domain] = true; |
| + |
| + // Update domain exceptions rule delayed to prevent multiple subsequent |
| + // updates. |
| + if (this._domainExceptionsTimeout) |
| + window.clearTimeout(this._domainExceptionsTimeout); |
| + this._domainExceptionsTimeout = window.setTimeout(this._updateDomainExceptions.bind(this), 0); |
| + }, |
| + |
| + /** |
| + * Removes a global exception for a particular document domain. |
| + */ |
| + _removeDomainException: function(/**String*/ domain) |
| + { |
| + delete this._domainExceptions[domain]; |
| + |
| + // Update domain exceptions rule delayed to prevent multiple subsequent |
| + // updates. |
| + if (this._domainExceptionsTimeout) |
| + window.clearTimeout(this._domainExceptionsTimeout); |
| + this._domainExceptionsTimeout = window.setTimeout(this._updateDomainExceptions.bind(this), 0); |
| + }, |
| + |
| + /** |
| + * Updates domain exceptions rule (should be called delayed). |
| + */ |
| + _updateDomainExceptions: 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 |
| + }); |
| + } |
| + }, |
| + |
| add: function(filter) |
| { |
| + if (!WhitelistFilter) |
|
Felix Dahlke
2012/11/14 13:03:51
Not a new problem, but can't we do this earlier? B
Wladimir Palant
2012/11/14 13:46:53
Yes, it's ugly. Problem is that matcher.js needs t
|
| + { |
| + WhitelistFilter = require("filterClasses").WhitelistFilter; |
| + RegExpFilter = require("filterClasses").RegExpFilter; |
| + } |
| + |
| + if (filter instanceof WhitelistFilter && filter.contentType == RegExpFilter.typeMap.DOCUMENT) |
|
Felix Dahlke
2012/11/14 13:03:51
I'd like a function for both this check and the _g
Wladimir Palant
2012/11/14 13:46:53
Ok, I changed the solution to have maximal code re
|
| + { |
| + var domain = this._getDomainFromException(filter); |
| + if (domain) |
| + this._addDomainException(domain); |
| + } |
| + |
| 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 (filter instanceof WhitelistFilter && filter.contentType == RegExpFilter.typeMap.DOCUMENT) |
| + { |
| + var domain = this._getDomainFromException(filter); |
| + if (domain) |
| + this._removeDomainException(domain); |
| + } |
| + |
| 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 = {}; |
| + |
| + for (var domain in this._domainExceptions) |
| + this._removeDomainException(domain); |
| + this._domainExceptions = {}; |
| } |
| } |
| }; |
| })(); |