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(); |
} |
} |
}; |
})(); |