Index: lib/elemHide.js |
=================================================================== |
--- a/lib/elemHide.js |
+++ b/lib/elemHide.js |
@@ -16,174 +16,50 @@ |
*/ |
"use strict"; |
/** |
* @fileOverview Element hiding implementation. |
*/ |
+const {ContentFilterModule} = require("./contentFilterModule"); |
const {ElemHideExceptions} = require("./elemHideExceptions"); |
const {FilterNotifier} = require("./filterNotifier"); |
/** |
- * Lookup table, active flag, by filter by domain. |
- * (Only contains filters that aren't unconditionally matched for all domains.) |
- * @type {Map.<string,Map.<Filter,boolean>>} |
- */ |
-let filtersByDomain = new Map(); |
- |
-/** |
- * Lookup table, filter by selector. (Only used for selectors that are |
- * unconditionally matched for all domains.) |
- * @type {Map.<string,Filter>} |
- */ |
-let filterBySelector = new Map(); |
- |
-/** |
- * This array caches the keys of filterBySelector table (selectors |
- * which unconditionally apply on all domains). It will be null if the |
- * cache needs to be rebuilt. |
- * @type {?string[]} |
- */ |
-let unconditionalSelectors = null; |
- |
-/** |
- * Map to be used instead when a filter has a blank domains property. |
- * @type {Map.<string,boolean>} |
- * @const |
- */ |
-let defaultDomains = new Map([["", true]]); |
- |
-/** |
- * Set containing known element hiding filters |
- * @type {Set.<ElemHideFilter>} |
- */ |
-let knownFilters = new Set(); |
- |
-/** |
- * Adds a filter to the lookup table of filters by domain. |
- * @param {Filter} filter |
- */ |
-function addToFiltersByDomain(filter) |
-{ |
- let domains = filter.domains || defaultDomains; |
- for (let [domain, isIncluded] of domains) |
- { |
- // There's no need to note that a filter is generically disabled. |
- if (!isIncluded && domain == "") |
- continue; |
- |
- let filters = filtersByDomain.get(domain); |
- if (!filters) |
- filtersByDomain.set(domain, filters = new Map()); |
- filters.set(filter, isIncluded); |
- } |
-} |
- |
-/** |
- * Returns a list of selectors that apply on each website unconditionally. |
- * @returns {string[]} |
- */ |
-function getUnconditionalSelectors() |
-{ |
- if (!unconditionalSelectors) |
- unconditionalSelectors = [...filterBySelector.keys()]; |
- |
- return unconditionalSelectors; |
-} |
- |
-ElemHideExceptions.on("added", ({selector}) => |
-{ |
- // If this is the first exception for a previously unconditionally applied |
- // element hiding selector we need to take care to update the lookups. |
- let unconditionalFilterForSelector = filterBySelector.get(selector); |
- if (unconditionalFilterForSelector) |
- { |
- addToFiltersByDomain(unconditionalFilterForSelector); |
- filterBySelector.delete(selector); |
- unconditionalSelectors = null; |
- } |
-}); |
- |
-/** |
* Container for element hiding filters |
* @class |
*/ |
-exports.ElemHide = { |
- /** |
- * Removes all known filters |
- */ |
+exports.ElemHide = Object.assign(new ContentFilterModule(), { |
clear() |
{ |
- for (let collection of [filtersByDomain, filterBySelector, knownFilters]) |
- collection.clear(); |
+ ContentFilterModule.prototype.clear.call(this); |
- unconditionalSelectors = null; |
FilterNotifier.emit("elemhideupdate"); |
}, |
- /** |
- * Add a new element hiding filter |
- * @param {ElemHideFilter} filter |
- */ |
add(filter) |
{ |
- if (knownFilters.has(filter)) |
- return; |
- |
- let {selector} = filter; |
+ let {size} = this._knownFilters; |
- if (!(filter.domains || ElemHideExceptions.hasExceptions(selector))) |
- { |
- // The new filter's selector is unconditionally applied to all domains |
- filterBySelector.set(selector, filter); |
- unconditionalSelectors = null; |
- } |
- else |
- { |
- // The new filter's selector only applies to some domains |
- addToFiltersByDomain(filter); |
- } |
+ ContentFilterModule.prototype.add.call(this, filter); |
- knownFilters.add(filter); |
- FilterNotifier.emit("elemhideupdate"); |
+ if (size != this._knownFilters.size) |
+ FilterNotifier.emit("elemhideupdate"); |
}, |
- /** |
- * Removes an element hiding filter |
- * @param {ElemHideFilter} filter |
- */ |
remove(filter) |
{ |
- if (!knownFilters.has(filter)) |
- return; |
- |
- let {selector} = filter; |
+ let {size} = this._knownFilters; |
- // Unconditially applied element hiding filters |
- if (filterBySelector.get(selector) == filter) |
- { |
- filterBySelector.delete(selector); |
- unconditionalSelectors = null; |
- } |
- // Conditionally applied element hiding filters |
- else |
- { |
- let domains = filter.domains || defaultDomains; |
- for (let domain of domains.keys()) |
- { |
- let filters = filtersByDomain.get(domain); |
- if (filters) |
- filters.delete(filter); |
- } |
- } |
+ ContentFilterModule.prototype.remove.call(this, filter); |
- knownFilters.delete(filter); |
- FilterNotifier.emit("elemhideupdate"); |
+ if (size != this._knownFilters.size) |
+ FilterNotifier.emit("elemhideupdate"); |
}, |
/** |
* Determines from the current filter list which selectors should be applied |
* on a particular host name. |
* @param {string} domain |
* @param {boolean} [specificOnly] true if generic filters should not apply. |
* @returns {string[]} List of selectors. |
@@ -197,17 +73,17 @@ |
// This code is a performance hot-spot, which is why we've made certain |
// micro-optimisations. Please be careful before making changes. |
while (true) |
{ |
if (specificOnly && currentDomain == "") |
break; |
- let filters = filtersByDomain.get(currentDomain); |
+ let filters = this._filtersByDomain.get(currentDomain); |
if (filters) |
{ |
for (let [filter, isIncluded] of filters) |
{ |
if (!isIncluded) |
{ |
excluded.add(filter); |
} |
@@ -226,13 +102,13 @@ |
if (currentDomain == "") |
break; |
let nextDot = currentDomain.indexOf("."); |
currentDomain = nextDot == -1 ? "" : currentDomain.substr(nextDot + 1); |
} |
if (!specificOnly) |
- selectors = getUnconditionalSelectors().concat(selectors); |
+ selectors = this._getUnconditionalSelectors().concat(selectors); |
return selectors; |
} |
-}; |
+}); |