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