| Index: lib/elemHide.js |
| diff --git a/lib/elemHide.js b/lib/elemHide.js |
| index 700db132d52c5ee81e90e3f122f6ac701a1d074c..0ed899e99c3f9052c587761f725f751b692a7f8a 100644 |
| --- a/lib/elemHide.js |
| +++ b/lib/elemHide.js |
| @@ -40,17 +40,31 @@ var filterByKey = Object.create(null); |
| var keyByFilter = Object.create(null); |
| /** |
| - * Nested lookup table, filter (or false if inactive) by filter text by domain |
| - * @type Object |
| + * Indicates whether we are using getSelectorsByDomain and maintaining the |
| + * required lookup tables. (Will be false for Firefox) |
| + * @type Boolean |
| */ |
| -var filtersByDomain = Object.create(null); |
| +var usingGetSelectorsByDomain = !("nsIStyleSheetService" in Ci); |
| /** |
| - * Indicates whether we are using (and maintaining) the filtersByDomain lookup. |
| - * (Will be false for Firefox) |
| - * @type Boolean |
| + * Lookup table, filter selector by filter ID. |
| + */ |
| +var selectorByFilterId = []; |
| + |
| +/** |
| + * Lookup table, active filter IDs by domain. |
| + */ |
| +var activeFilterIdsByDomain = Object.create(null); |
| + |
| +/** |
| + * Lookup table, inactive filter IDs by domain. |
| + */ |
| +var inactiveFilterIdsByDomain = Object.create(null); |
| + |
| +/** |
| + * Lookup table, filter ID by filter text. |
| */ |
| -var usingFiltersByDomain = !("nsIStyleSheetService" in Ci); |
| +var filterIdByFilterText = Object.create(null); |
| /** |
| * Object to be used instead when a filter has a blank domains property. |
| @@ -118,7 +132,10 @@ var ElemHide = exports.ElemHide = |
| { |
| filterByKey = Object.create(null); |
| keyByFilter = Object.create(null); |
| - filtersByDomain = Object.create(null); |
| + selectorByFilterId = []; |
| + activeFilterIdsByDomain = Object.create(null); |
| + inactiveFilterIdsByDomain = Object.create(null); |
| + filterIdByFilterText = Object.create(null); |
| knownExceptions = Object.create(null); |
| exceptions = Object.create(null); |
| ElemHide.isDirty = false; |
| @@ -155,19 +172,25 @@ var ElemHide = exports.ElemHide = |
| filterByKey[key] = filter; |
| keyByFilter[filter.text] = key; |
| - if (usingFiltersByDomain) |
| + if (usingGetSelectorsByDomain && !(filter.text in filterIdByFilterText)) |
| { |
| + let filterId = selectorByFilterId.push(filter.selector) - 1; |
| + filterIdByFilterText[filter.text] = filterId; |
| + |
| let domains = filter.domains || defaultDomains; |
| for (let domain in domains) |
| { |
| - let filters = filtersByDomain[domain]; |
| - if (!filters) |
| - filters = filtersByDomain[domain] = Object.create(null); |
| - |
| + let lookup; |
| if (domains[domain]) |
| - filters[filter.text] = filter; |
| + lookup = activeFilterIdsByDomain; |
| else |
| - filters[filter.text] = false; |
| + lookup = inactiveFilterIdsByDomain; |
| + |
| + let filterIds = lookup[domain]; |
| + if (filterIds == undefined) |
| + filterIds = lookup[domain] = []; |
| + |
| + filterIds.push(filterId); |
| } |
| } |
| @@ -202,14 +225,30 @@ var ElemHide = exports.ElemHide = |
| delete keyByFilter[filter.text]; |
| ElemHide.isDirty = true; |
| - if (usingFiltersByDomain) |
| + if (usingGetSelectorsByDomain) |
| { |
| - let domains = filter.domains || defaultDomains; |
| - for (let domain in domains) |
| + let filterId = filterIdByFilterText[filter.text]; |
| + if (filterId) |
| { |
| - let filters = filtersByDomain[domain]; |
| - if (filters) |
| - delete filters[filter.text]; |
| + delete filterIdByFilterText[filter.text]; |
| + delete selectorByFilterId[filterId]; |
| + |
| + let domains = filter.domains || defaultDomains; |
| + let filterIdsByDomainLookups = [activeFilterIdsByDomain, |
| + inactiveFilterIdsByDomain]; |
| + for (let domain in domains) |
| + { |
| + for (let filterIdsByDomain of filterIdsByDomainLookups) |
| + { |
| + let lookup = filterIdsByDomain[domain]; |
| + if (lookup) |
| + { |
| + let index = lookup.indexOf(filterId); |
| + if (index != -1) |
| + lookup.splice(index, 1); |
| + } |
| + } |
| + } |
| } |
| } |
| } |
| @@ -219,12 +258,12 @@ var ElemHide = exports.ElemHide = |
| * Checks whether an exception rule is registered for a filter on a particular |
| * domain. |
| */ |
| - getException: function(/**Filter*/ filter, /**String*/ docDomain) /**ElemHideException*/ |
| + getException: function(/**String*/ selector, /**String*/ docDomain) /**ElemHideException*/ |
| { |
| - if (!(filter.selector in exceptions)) |
| + if (!(selector in exceptions)) |
| return null; |
| - let list = exceptions[filter.selector]; |
| + let list = exceptions[selector]; |
| for (let i = list.length - 1; i >= 0; i--) |
| if (list[i].isActiveOnDomain(docDomain)) |
| return list[i]; |
| @@ -421,30 +460,35 @@ var ElemHide = exports.ElemHide = |
| */ |
| getSelectorsForDomain: function(/**String*/ domain, /**Boolean*/ specificOnly) |
| { |
| - if (!usingFiltersByDomain) |
| + if (!usingGetSelectorsByDomain) |
| throw new Error("getSelectorsForDomain can not be used in Firefox!"); |
| let selectors = []; |
| - let seenFilters = Object.create(null); |
| + let seenFilterIds = Object.create(null); |
| let currentDomain = domain ? domain.toUpperCase() : ""; |
| while (true) |
| { |
| if (specificOnly && currentDomain == "") |
| break; |
| - let filters = filtersByDomain[currentDomain]; |
| - if (filters) |
| + let inactiveFilterIds = inactiveFilterIdsByDomain[currentDomain]; |
| + if (inactiveFilterIds) |
| + for (let filterId of inactiveFilterIds) |
| + seenFilterIds[filterId] = true; |
| + |
| + let activeFilterIds = activeFilterIdsByDomain[currentDomain]; |
| + if (activeFilterIds) |
| { |
| - for (let filterText in filters) |
| + for (let filterId of activeFilterIds) |
| { |
| - if (filterText in seenFilters) |
| + if (filterId in seenFilterIds) |
| continue; |
| - seenFilters[filterText] = true; |
| + seenFilterIds[filterId] = true; |
| - let filter = filters[filterText]; |
| - if (filter && !this.getException(filter, domain)) |
| - selectors.push(filter.selector); |
| + let selector = selectorByFilterId[filterId]; |
| + if (!this.getException(selector, domain)) |
| + selectors.push(selector); |
| } |
| } |