Index: lib/elemHide.js |
diff --git a/lib/elemHide.js b/lib/elemHide.js |
index 2c81a2324f579247d53eca5eeb6ac459210a937a..1ca6f7910a2d3cd8953a05c4bebb0e0af001c5ef 100644 |
--- a/lib/elemHide.js |
+++ b/lib/elemHide.js |
@@ -36,14 +36,6 @@ var filterByKey = []; |
var keyByFilter = Object.create(null); |
/** |
- * Indicates whether we are using the getSelectorsForDomain function and |
- * therefore mainting the required filtersByDomain, filtersBySelector and |
- * unconditionalSelectors lookups. (Will be false for Firefox) |
- * @type Boolean |
- */ |
-var usingGetSelectorsForDomain = !("nsIStyleSheetService" in Ci); |
- |
-/** |
* Nested lookup table, filter (or false if inactive) by filter key by domain. |
* (Only contains filters that aren't unconditionally matched for all domains.) |
* @type Object |
@@ -51,19 +43,27 @@ var usingGetSelectorsForDomain = !("nsIStyleSheetService" in Ci); |
var filtersByDomain = Object.create(null); |
/** |
- * Lookup table, filters by selector. (Only contains filters that have a |
+ * Lookup table, filter keys by selector. (Only contains filters that have a |
* selector that is unconditionally matched for all domains.) |
*/ |
-var filtersBySelector = Object.create(null); |
+var filterKeysBySelector = Object.create(null); |
/** |
- * This array caches the keys of filtersBySelector table (selectors which |
+ * This array caches the keys of filterKeysBySelector table (selectors which |
* unconditionally apply on all domains). It will be null if the cache needs to |
* be rebuilt. |
*/ |
var unconditionalSelectors = null; |
/** |
+ * This array caches the values of filterKeysBySelector table (filterIds for |
+ * selectors which unconditionally apply on all domains). It will be null if the |
+ * cache needs to be rebuilt. Note: Only the first filter key for each selector |
+ * is cached. |
+ */ |
+var unconditionalFilterKeys = null; |
+ |
+/** |
* Object to be used instead when a filter has a blank domains property. |
*/ |
var defaultDomains = Object.create(null); |
@@ -95,16 +95,15 @@ var ElemHide = exports.ElemHide = |
filterByKey = []; |
keyByFilter = Object.create(null); |
filtersByDomain = Object.create(null); |
- filtersBySelector = Object.create(null); |
- unconditionalSelectors = null; |
+ filterKeysBySelector = Object.create(null); |
+ unconditionalSelectors = unconditionalFilterKeys = null; |
knownExceptions = Object.create(null); |
exceptions = Object.create(null); |
FilterNotifier.emit("elemhideupdate"); |
}, |
- _addToFiltersByDomain: function(filter) |
+ _addToFiltersByDomain: function(key, filter) |
{ |
- let key = keyByFilter[filter.text]; |
let domains = filter.domains || defaultDomains; |
for (let domain in domains) |
{ |
@@ -135,19 +134,16 @@ var ElemHide = exports.ElemHide = |
exceptions[selector] = []; |
exceptions[selector].push(filter); |
- if (usingGetSelectorsForDomain) |
+ // If this is the first exception for a previously unconditionally |
+ // applied element hiding selector we need to take care to update the |
+ // lookups. |
+ let filterKeys = filterKeysBySelector[selector]; |
+ if (filterKeys) |
{ |
- // If this is the first exception for a previously unconditionally |
- // applied element hiding selector we need to take care to update the |
- // lookups. |
- let unconditionalFilters = filtersBySelector[selector]; |
- if (unconditionalFilters) |
- { |
- for (let f of unconditionalFilters) |
- this._addToFiltersByDomain(f); |
- delete filtersBySelector[selector]; |
- unconditionalSelectors = null; |
- } |
+ for (let filterKey of filterKeys) |
+ this._addToFiltersByDomain(filterKey, filterByKey[filterKey]); |
+ delete filterKeysBySelector[selector]; |
+ unconditionalSelectors = unconditionalFilterKeys = null; |
} |
knownExceptions[filter.text] = true; |
@@ -160,28 +156,25 @@ var ElemHide = exports.ElemHide = |
let key = filterByKey.push(filter) - 1; |
keyByFilter[filter.text] = key; |
- if (usingGetSelectorsForDomain) |
+ if (!(filter.domains || filter.selector in exceptions)) |
{ |
- if (!(filter.domains || filter.selector in exceptions)) |
+ // The new filter's selector is unconditionally applied to all domains |
+ let filterKeys = filterKeysBySelector[filter.selector]; |
+ if (filterKeys) |
{ |
- // The new filter's selector is unconditionally applied to all domains |
- let filters = filtersBySelector[filter.selector]; |
- if (filters) |
- { |
- filters.push(filter); |
- } |
- else |
- { |
- filtersBySelector[filter.selector] = [filter]; |
- unconditionalSelectors = null; |
- } |
+ filterKeys.push(key); |
} |
else |
{ |
- // The new filter's selector only applies to some domains |
- this._addToFiltersByDomain(filter); |
+ filterKeysBySelector[filter.selector] = [key]; |
+ unconditionalSelectors = unconditionalFilterKeys = null; |
} |
} |
+ else |
+ { |
+ // The new filter's selector only applies to some domains |
+ this._addToFiltersByDomain(key, filter); |
+ } |
} |
FilterNotifier.emit("elemhideupdate"); |
@@ -213,31 +206,42 @@ var ElemHide = exports.ElemHide = |
delete filterByKey[key]; |
delete keyByFilter[filter.text]; |
- if (usingGetSelectorsForDomain) |
+ let unconditional = !(filter.domains || filter.selector in exceptions); |
+ if (unconditional) |
{ |
- let filters = filtersBySelector[filter.selector]; |
- if (filters) |
+ let filterKeys = filterKeysBySelector[filter.selector]; |
+ if (filterKeys) |
{ |
- if (filters.length > 1) |
+ if (filterKeys.length > 1) |
{ |
- let index = filters.indexOf(filter); |
- filters.splice(index, 1); |
+ let index = filterKeys.indexOf(key); |
+ filterKeys.splice(index, 1); |
Wladimir Palant
2016/09/20 16:31:14
index should be positive but if we ever have a bug
kzar
2016/09/20 18:37:35
Done.
|
+ if (index == 0) |
+ unconditionalFilterKeys = null; |
} |
else |
{ |
- delete filtersBySelector[filter.selector]; |
- unconditionalSelectors = null; |
+ delete filterKeysBySelector[filter.selector]; |
+ unconditionalSelectors = unconditionalFilterKeys = null; |
} |
} |
else |
{ |
- let domains = filter.domains || defaultDomains; |
- for (let domain in domains) |
- { |
- let filters = filtersByDomain[domain]; |
- if (filters) |
- delete filters[key]; |
- } |
+ // Even if this filter appears unconditional its selector might not |
+ // be. In that case we need to take care to remove it from |
+ // filtersByDomain instead. |
Wladimir Palant
2016/09/20 16:31:14
This comment makes little sense, should really be
kzar
2016/09/20 18:37:35
Done.
|
+ unconditional = false; |
+ } |
+ } |
+ |
+ if (!unconditional) |
+ { |
+ let domains = filter.domains || defaultDomains; |
+ for (let domain in domains) |
+ { |
+ let filters = filtersByDomain[domain]; |
+ if (filters) |
+ delete filters[key]; |
} |
} |
} |
@@ -265,7 +269,7 @@ var ElemHide = exports.ElemHide = |
/** |
* Retrieves an element hiding filter by the corresponding protocol key |
*/ |
- getFilterByKey: function(/**String*/ key) /**Filter*/ |
+ getFilterByKey: function(/**Number*/ key) /**Filter*/ |
{ |
return (key in filterByKey ? filterByKey[key] : null); |
}, |
@@ -298,18 +302,56 @@ var ElemHide = exports.ElemHide = |
}, |
/** |
- * Returns a list of all selectors active on a particular domain, must not be |
- * used in Firefox (when usingGetSelectorsForDomain is false). |
+ * Returns a list of selectors that apply on each website unconditionally. |
+ * @returns {String[]} |
*/ |
- getSelectorsForDomain: function(/**String*/ domain, /**Boolean*/ specificOnly) |
+ getUnconditionalSelectors: function() |
{ |
- if (!usingGetSelectorsForDomain) |
- throw new Error("getSelectorsForDomain can not be used in Firefox!"); |
- |
if (!unconditionalSelectors) |
- unconditionalSelectors = Object.keys(filtersBySelector); |
- let selectors = specificOnly ? [] : unconditionalSelectors.slice(); |
+ unconditionalSelectors = Object.keys(filterKeysBySelector); |
+ return unconditionalSelectors.slice(); |
+ }, |
+ /** |
+ * Returns a list of all selectors active on a particular domain. |
+ * Returns a list of filterKeys for selectors that apply on each website |
+ * unconditionally. |
+ * @returns {Number[]} |
+ */ |
+ getUnconditionalFilterKeys: function() |
+ { |
+ if (!unconditionalFilterKeys) |
+ { |
+ let selectors = this.getUnconditionalSelectors(); |
+ unconditionalFilterKeys = []; |
+ for (let selector of selectors) |
+ unconditionalFilterKeys.push(filterKeysBySelector[selector][0]); |
+ } |
+ return unconditionalFilterKeys.slice(); |
+ }, |
+ |
+ /** |
+ * Returns a list of all selectors active on a particular domain. Optionally |
+ * a list of corresponding filter keys for the selectors can be returned too. |
+ * The optional criteria parameter restricts the results as follows: |
+ * 0 - All selectors allowed (default) |
+ * 1 - No unconditionally matching selectors allowed |
+ * 2 - Only specifically matching selectors allowed |
Wladimir Palant
2016/09/20 16:31:14
No magic numbers please, these should be exposed a
kzar
2016/09/20 18:37:35
Done.
|
+ */ |
+ getSelectorsForDomain: function(/**String*/ domain, |
+ /**Number*/ criteria, |
+ /**Boolean*/ provideFilterKeys) |
+ { |
+ let filterKeys = []; |
+ let selectors = []; |
+ if (!criteria) |
Wladimir Palant
2016/09/20 16:31:14
Should be something like:
if (typeof criteria =
kzar
2016/09/20 18:37:35
Done.
|
+ { |
+ selectors = this.getUnconditionalSelectors(); |
+ if (provideFilterKeys) |
+ filterKeys = this.getUnconditionalFilterKeys(); |
+ } |
+ |
+ let specificOnly = criteria == 2; |
Wladimir Palant
2016/09/20 16:31:14
Should be something like:
let specificOnly = (c
kzar
2016/09/20 18:37:35
Done.
|
let seenFilters = Object.create(null); |
let currentDomain = domain ? domain.toUpperCase() : ""; |
while (true) |
@@ -328,7 +370,11 @@ var ElemHide = exports.ElemHide = |
let filter = filters[filterKey]; |
if (filter && !this.getException(filter, domain)) |
+ { |
selectors.push(filter.selector); |
+ // It is faster to always push the key, even if not required. |
+ filterKeys.push(filterKey); |
+ } |
} |
} |
@@ -339,6 +385,9 @@ var ElemHide = exports.ElemHide = |
currentDomain = nextDot == -1 ? "" : currentDomain.substr(nextDot + 1); |
} |
- return selectors; |
+ if (provideFilterKeys) |
+ return [selectors, filterKeys.map(key => parseInt(key, 10))]; |
Wladimir Palant
2016/09/20 16:31:14
Keys are opaque to the caller, we used to have str
kzar
2016/09/20 18:37:35
Done.
|
+ else |
+ return selectors; |
} |
}; |