| Index: lib/elemHide.js |
| diff --git a/lib/elemHide.js b/lib/elemHide.js |
| index 2c81a2324f579247d53eca5eeb6ac459210a937a..c3df791db5e5b8420560e90b796bdfd37c254f5b 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,26 @@ var usingGetSelectorsForDomain = !("nsIStyleSheetService" in Ci); |
| var filtersByDomain = Object.create(null); |
| /** |
| - * Lookup table, filters by selector. (Only contains filters that have a |
| + * Lookup table, filters key by selector. (Only contains filters that have a |
| * selector that is unconditionally matched for all domains.) |
| */ |
| -var filtersBySelector = Object.create(null); |
| +var filterKeyBySelector = Object.create(null); |
| /** |
| - * This array caches the keys of filtersBySelector table (selectors which |
| + * This array caches the keys of filterKeyBySelector 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 filterKeyBySelector table (filterIds for |
| + * selectors which unconditionally apply on all domains). It will be null if the |
| + * cache needs to be rebuilt. |
| + */ |
| +var unconditionalFilterKeys = null; |
| + |
| +/** |
| * Object to be used instead when a filter has a blank domains property. |
| */ |
| var defaultDomains = Object.create(null); |
| @@ -95,16 +94,15 @@ var ElemHide = exports.ElemHide = |
| filterByKey = []; |
| keyByFilter = Object.create(null); |
| filtersByDomain = Object.create(null); |
| - filtersBySelector = Object.create(null); |
| - unconditionalSelectors = null; |
| + filterKeyBySelector = 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 +133,15 @@ 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 filterKey = filterKeyBySelector[selector]; |
| + if (filterKey) |
| { |
| - // 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; |
| - } |
| + this._addToFiltersByDomain(filterKey, filterByKey[filterKey]); |
| + delete filterKeyBySelector[selector]; |
| + unconditionalSelectors = unconditionalFilterKeys = null; |
| } |
| knownExceptions[filter.text] = true; |
| @@ -160,27 +154,16 @@ 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 filters = filtersBySelector[filter.selector]; |
| - if (filters) |
| - { |
| - filters.push(filter); |
| - } |
| - else |
| - { |
| - filtersBySelector[filter.selector] = [filter]; |
| - unconditionalSelectors = null; |
| - } |
| - } |
| - else |
| - { |
| - // The new filter's selector only applies to some domains |
| - this._addToFiltersByDomain(filter); |
| - } |
| + // The new filter's selector is unconditionally applied to all domains |
| + filterKeyBySelector[filter.selector] = key; |
| + unconditionalSelectors = unconditionalFilterKeys = null; |
| + } |
| + else |
| + { |
| + // The new filter's selector only applies to some domains |
| + this._addToFiltersByDomain(key, filter); |
| } |
| } |
| @@ -213,31 +196,19 @@ var ElemHide = exports.ElemHide = |
| delete filterByKey[key]; |
| delete keyByFilter[filter.text]; |
| - if (usingGetSelectorsForDomain) |
| + if (filter.selector in filterKeyBySelector) |
| { |
| - let filters = filtersBySelector[filter.selector]; |
| - if (filters) |
| - { |
| - if (filters.length > 1) |
| - { |
| - let index = filters.indexOf(filter); |
| - filters.splice(index, 1); |
| - } |
| - else |
| - { |
| - delete filtersBySelector[filter.selector]; |
| - unconditionalSelectors = null; |
| - } |
| - } |
| - else |
| + delete filterKeyBySelector[filter.selector]; |
| + unconditionalSelectors = unconditionalFilterKeys = null; |
| + } |
| + else |
| + { |
| + let domains = filter.domains || defaultDomains; |
| + for (let domain in domains) |
| { |
| - let domains = filter.domains || defaultDomains; |
| - for (let domain in domains) |
| - { |
| - let filters = filtersByDomain[domain]; |
| - if (filters) |
| - delete filters[key]; |
| - } |
| + let filters = filtersByDomain[domain]; |
| + if (filters) |
| + delete filters[key]; |
| } |
| } |
| } |
| @@ -265,7 +236,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,17 +269,50 @@ 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(filterKeyBySelector); |
| + 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(filterKeyBySelector[selector]); |
| + } |
| + 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. |
| + */ |
| + getSelectorsForDomain: function(/**String*/ domain, /**Boolean*/ specificOnly, |
| + /**Boolean*/ noUnconditional, |
| + /**Boolean*/ provideFilterKeys) |
| + { |
| + let filterKeys = []; |
| + let selectors = []; |
| + if (!specificOnly && !noUnconditional) |
| + { |
| + selectors = this.getUnconditionalSelectors(); |
| + if (provideFilterKeys) |
| + filterKeys = this.getUnconditionalFilterKeys(); |
| + } |
| let seenFilters = Object.create(null); |
| let currentDomain = domain ? domain.toUpperCase() : ""; |
| @@ -328,7 +332,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 +347,9 @@ var ElemHide = exports.ElemHide = |
| currentDomain = nextDot == -1 ? "" : currentDomain.substr(nextDot + 1); |
| } |
| - return selectors; |
| + if (provideFilterKeys) |
| + return [selectors, filterKeys]; |
| + else |
| + return selectors; |
| } |
| }; |