Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: lib/elemHide.js

Issue 29784555: Issue 6665 - Abstract element hiding container logic into its own module Base URL: https://hg.adblockplus.org/adblockpluscore/
Patch Set: Created May 17, 2018, 5:15 a.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | lib/elemHideEmulation.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/elemHide.js
===================================================================
--- a/lib/elemHide.js
+++ b/lib/elemHide.js
@@ -20,177 +20,195 @@
/**
* @fileOverview Element hiding implementation.
*/
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>}
+ * Template for element hiding and element hiding emulation filter containers
+ * @class
*/
-let knownFilters = new Set();
-
-/**
- * Adds a filter to the lookup table of filters by domain.
- * @param {Filter} filter
- */
-function addToFiltersByDomain(filter)
+function ElemHideTemplate()
{
- 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;
+ this._filtersByDomain = new Map();
+ this._filterBySelector = new Map();
+ this._unconditionalSelectors = null;
+ this._knownFilters = new Set();
- let filters = filtersByDomain.get(domain);
- if (!filters)
- filtersByDomain.set(domain, filters = new Map());
- filters.set(filter, isIncluded);
- }
+ ElemHideExceptions.on("added", this._onExceptionAdded.bind(this));
}
-/**
- * Returns a list of selectors that apply on each website unconditionally.
- * @returns {string[]}
- */
-function getUnconditionalSelectors()
-{
- if (!unconditionalSelectors)
- unconditionalSelectors = [...filterBySelector.keys()];
+ElemHideTemplate.prototype = {
+ /**
+ * 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>>}
+ */
+ _filtersByDomain: null,
+
+ /**
+ * Lookup table, filter by selector. (Only used for selectors that are
+ * unconditionally matched for all domains.)
+ * @type {Map.<string,Filter>}
+ */
+ _filterBySelector: null,
- return unconditionalSelectors;
-}
+ /**
+ * 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[]}
+ */
+ _unconditionalSelectors: null,
-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)
+ /**
+ * Set containing known element hiding filters
+ * @type {Set.<ElemHideFilter>}
+ */
+ _knownFilters: null,
+
+ /**
+ * Adds a filter to the lookup table of filters by domain.
+ * @param {Filter} filter
+ */
+ _addToFiltersByDomain(filter)
{
- addToFiltersByDomain(unconditionalFilterForSelector);
- filterBySelector.delete(selector);
- unconditionalSelectors = null;
- }
+ 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;
- FilterNotifier.emit("elemhideupdate");
-});
+ let filters = this._filtersByDomain.get(domain);
+ if (!filters)
+ this._filtersByDomain.set(domain, filters = new Map());
+ filters.set(filter, isIncluded);
+ }
+ },
+
+ /**
+ * Returns a list of selectors that apply on each website unconditionally.
+ * @returns {string[]}
+ */
+ _getUnconditionalSelectors()
+ {
+ if (!this._unconditionalSelectors)
+ this._unconditionalSelectors = [...this._filterBySelector.keys()];
-ElemHideExceptions.on("removed", () =>
-{
- FilterNotifier.emit("elemhideupdate");
-});
+ return this._unconditionalSelectors;
+ },
+
+ /**
+ * Handles the event when a new element hiding exception has been added
+ * @param {ElemHideException} exception
+ */
+ _onExceptionAdded(exception)
+ {
+ let {selector} = exception;
-/**
- * Container for element hiding filters
- * @class
- */
-exports.ElemHide = {
+ // 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 = this._filterBySelector.get(selector);
+ if (unconditionalFilterForSelector)
+ {
+ this._addToFiltersByDomain(unconditionalFilterForSelector);
+ this._filterBySelector.delete(selector);
+ this._unconditionalSelectors = null;
+ }
+ },
+
/**
* Removes all known filters
*/
clear()
{
- for (let collection of [filtersByDomain, filterBySelector,
- knownFilters])
+ for (let collection of [this._filtersByDomain, this._filterBySelector,
+ this._knownFilters])
{
collection.clear();
}
- unconditionalSelectors = null;
+ this._unconditionalSelectors = null;
FilterNotifier.emit("elemhideupdate");
},
/**
* Add a new element hiding filter
* @param {ElemHideFilter} filter
*/
add(filter)
{
- if (knownFilters.has(filter))
+ if (this._knownFilters.has(filter))
return;
if (!(filter.domains || ElemHideExceptions.hasExceptions(filter.selector)))
{
// The new filter's selector is unconditionally applied to all domains
- filterBySelector.set(filter.selector, filter);
- unconditionalSelectors = null;
+ this._filterBySelector.set(filter.selector, filter);
+ this._unconditionalSelectors = null;
}
else
{
// The new filter's selector only applies to some domains
- addToFiltersByDomain(filter);
+ this._addToFiltersByDomain(filter);
}
- knownFilters.add(filter);
+ this._knownFilters.add(filter);
FilterNotifier.emit("elemhideupdate");
},
/**
* Removes an element hiding filter
* @param {ElemHideFilter} filter
*/
remove(filter)
{
- if (!knownFilters.has(filter))
+ if (!this._knownFilters.has(filter))
return;
// Unconditially applied element hiding filters
- if (filterBySelector.get(filter.selector) == filter)
+ if (this._filterBySelector.get(filter.selector) == filter)
{
- filterBySelector.delete(filter.selector);
- unconditionalSelectors = null;
+ this._filterBySelector.delete(filter.selector);
+ this._unconditionalSelectors = null;
}
// Conditionally applied element hiding filters
else
{
let domains = filter.domains || defaultDomains;
for (let domain of domains.keys())
{
- let filters = filtersByDomain.get(domain);
+ let filters = this._filtersByDomain.get(domain);
if (filters)
filters.delete(filter);
}
}
- knownFilters.delete(filter);
+ this._knownFilters.delete(filter);
FilterNotifier.emit("elemhideupdate");
- },
+ }
+};
+
+exports.ElemHideTemplate = ElemHideTemplate;
+/**
+ * Container for element hiding filters
+ * @class
+ */
+exports.ElemHide = Object.assign(new ElemHideTemplate(), {
/**
* 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.
*/
getSelectorsForDomain(domain, specificOnly = false)
@@ -202,17 +220,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);
}
@@ -227,13 +245,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;
}
-};
+});
« no previous file with comments | « no previous file | lib/elemHideEmulation.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld