Index: lib/elemHide.js |
=================================================================== |
--- a/lib/elemHide.js |
+++ b/lib/elemHide.js |
@@ -21,38 +21,39 @@ |
* @fileOverview Element hiding implementation. |
*/ |
const {ElemHideException} = require("./filterClasses"); |
const {FilterNotifier} = require("./filterNotifier"); |
/** |
* Lookup table, filters by their associated key |
- * @type {Object} |
+ * @type {Filter[]} |
*/ |
let filterByKey = []; |
/** |
* Lookup table, keys of the filters by filter |
- * @type {Map.<Filter,string>} |
+ * @type {Map.<Filter,number>} |
*/ |
let keyByFilter = new Map(); |
/** |
* 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 {Map.<string,Map.<string,(Filter|boolean)>>} |
+ * @type {Map.<string,Map.<number,(Filter|boolean)>>} |
*/ |
let filtersByDomain = new Map(); |
/** |
* Lookup table, filter key by selector. (Only used for selectors that are |
* unconditionally matched for all domains.) |
+ * @type {Map.<string,number>} |
*/ |
-let filterKeyBySelector = Object.create(null); |
+let filterKeyBySelector = new Map(); |
/** |
* 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. |
*/ |
let unconditionalSelectors = null; |
@@ -64,44 +65,44 @@ |
let unconditionalFilterKeys = null; |
/** |
* Object to be used instead when a filter has a blank domains property. |
*/ |
let defaultDomains = new Map([["", true]]); |
/** |
- * Lookup table, keys are known element hiding exceptions |
- * @type {Object} |
+ * Set containing known element hiding exceptions |
+ * @type {Set.<string>} |
*/ |
-let knownExceptions = Object.create(null); |
+let knownExceptions = new Set(); |
/** |
* Lookup table, lists of element hiding exceptions by selector |
- * @type {Object} |
+ * @type {Map.<string,Filter>} |
*/ |
-let exceptions = Object.create(null); |
+let exceptions = new Map(); |
/** |
* Container for element hiding filters |
* @class |
*/ |
let ElemHide = exports.ElemHide = { |
/** |
* Removes all known filters |
*/ |
clear() |
{ |
+ for (let collection of [keyByFilter, filtersByDomain, filterKeyBySelector, |
+ knownExceptions, exceptions]) |
+ { |
+ collection.clear(); |
+ } |
filterByKey = []; |
- keyByFilter = new Map(); |
- filtersByDomain = new Map(); |
- filterKeyBySelector = Object.create(null); |
unconditionalSelectors = unconditionalFilterKeys = null; |
- knownExceptions = Object.create(null); |
- exceptions = Object.create(null); |
FilterNotifier.emit("elemhideupdate"); |
}, |
_addToFiltersByDomain(key, filter) |
{ |
let domains = filter.domains || defaultDomains; |
for (let [domain, isIncluded] of domains) |
{ |
@@ -115,66 +116,68 @@ |
/** |
* Add a new element hiding filter |
* @param {ElemHideFilter} filter |
*/ |
add(filter) |
{ |
if (filter instanceof ElemHideException) |
{ |
- if (filter.text in knownExceptions) |
+ if (knownExceptions.has(filter.text)) |
return; |
let {selector} = filter; |
- if (!(selector in exceptions)) |
- exceptions[selector] = []; |
- exceptions[selector].push(filter); |
+ let list = exceptions.get(selector); |
+ if (list) |
+ list.push(filter); |
+ else |
+ exceptions.set(selector, [filter]); |
// 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]; |
+ let filterKey = filterKeyBySelector.get(selector); |
if (typeof filterKey != "undefined") |
{ |
this._addToFiltersByDomain(filterKey, filterByKey[filterKey]); |
- delete filterKeyBySelector[selector]; |
+ filterKeyBySelector.delete(selector); |
unconditionalSelectors = unconditionalFilterKeys = null; |
} |
- knownExceptions[filter.text] = true; |
+ knownExceptions.add(filter.text); |
} |
else |
{ |
if (keyByFilter.has(filter)) |
return; |
let key = filterByKey.push(filter) - 1; |
keyByFilter.set(filter, key); |
- if (!(filter.domains || filter.selector in exceptions)) |
+ if (!(filter.domains || exceptions.has(filter.selector))) |
{ |
// The new filter's selector is unconditionally applied to all domains |
- filterKeyBySelector[filter.selector] = key; |
+ filterKeyBySelector.set(filter.selector, key); |
unconditionalSelectors = unconditionalFilterKeys = null; |
} |
else |
{ |
// The new filter's selector only applies to some domains |
this._addToFiltersByDomain(key, filter); |
} |
} |
FilterNotifier.emit("elemhideupdate"); |
}, |
_removeFilterKey(key, filter) |
{ |
- if (filterKeyBySelector[filter.selector] == key) |
+ if (filterKeyBySelector.get(filter.selector) == key) |
{ |
- delete filterKeyBySelector[filter.selector]; |
+ filterKeyBySelector.delete(filter.selector); |
unconditionalSelectors = unconditionalFilterKeys = null; |
return; |
} |
// We haven't found this filter in unconditional filters, look in |
// filtersByDomain. |
let domains = filter.domains || defaultDomains; |
for (let domain of domains.keys()) |
@@ -188,24 +191,24 @@ |
/** |
* Removes an element hiding filter |
* @param {ElemHideFilter} filter |
*/ |
remove(filter) |
{ |
if (filter instanceof ElemHideException) |
{ |
- if (!(filter.text in knownExceptions)) |
+ if (!knownExceptions.has(filter.text)) |
return; |
- let list = exceptions[filter.selector]; |
+ let list = exceptions.get(filter.selector); |
let index = list.indexOf(filter); |
if (index >= 0) |
list.splice(index, 1); |
- delete knownExceptions[filter.text]; |
+ knownExceptions.delete(filter.text); |
} |
else |
{ |
let key = keyByFilter.get(filter); |
if (typeof key == "undefined") |
return; |
delete filterByKey[key]; |
@@ -220,20 +223,20 @@ |
* Checks whether an exception rule is registered for a filter on a particular |
* domain. |
* @param {Filter} filter |
* @param {string} docDomain |
* @return {ElemHideException} |
*/ |
getException(filter, docDomain) |
{ |
- if (!(filter.selector in exceptions)) |
+ let list = exceptions.get(filter.selector); |
+ if (!list) |
return null; |
- let list = exceptions[filter.selector]; |
for (let i = list.length - 1; i >= 0; i--) |
{ |
if (list[i].isActiveOnDomain(docDomain)) |
return list[i]; |
} |
return null; |
}, |
@@ -276,33 +279,33 @@ |
/** |
* Returns a list of selectors that apply on each website unconditionally. |
* @returns {string[]} |
*/ |
getUnconditionalSelectors() |
{ |
if (!unconditionalSelectors) |
- unconditionalSelectors = Object.keys(filterKeyBySelector); |
+ unconditionalSelectors = [...filterKeyBySelector.keys()]; |
return unconditionalSelectors.slice(); |
}, |
/** |
* Returns a list of filter keys for selectors which apply to all websites |
* without exception. |
* @returns {number[]} |
*/ |
getUnconditionalFilterKeys() |
{ |
if (!unconditionalFilterKeys) |
{ |
let selectors = this.getUnconditionalSelectors(); |
unconditionalFilterKeys = []; |
for (let selector of selectors) |
- unconditionalFilterKeys.push(filterKeyBySelector[selector]); |
+ unconditionalFilterKeys.push(filterKeyBySelector.get(selector)); |
} |
return unconditionalFilterKeys.slice(); |
}, |
/** |
* Constant used by getSelectorsForDomain to return all selectors applying to |
* a particular hostname. |
@@ -346,31 +349,31 @@ |
if (criteria < ElemHide.NO_UNCONDITIONAL) |
{ |
selectors = this.getUnconditionalSelectors(); |
if (provideFilterKeys) |
filterKeys = this.getUnconditionalFilterKeys(); |
} |
let specificOnly = (criteria >= ElemHide.SPECIFIC_ONLY); |
- let seenFilters = Object.create(null); |
+ let seenFilters = new Set(); |
let currentDomain = domain ? domain.toUpperCase() : ""; |
while (true) |
{ |
if (specificOnly && currentDomain == "") |
break; |
let filters = filtersByDomain.get(currentDomain); |
if (filters) |
{ |
for (let [filterKey, filter] of filters) |
{ |
- if (filterKey in seenFilters) |
+ if (seenFilters.has(filterKey)) |
continue; |
- seenFilters[filterKey] = true; |
+ seenFilters.add(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); |
} |
} |