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

Unified Diff: lib/elemHide.js

Issue 29349187: Issue 4167 - getSelectorsForDomain criteria + keys (Closed)
Patch Set: Addressed further feedback Created Sept. 27, 2016, 12:10 p.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 | test/elemHide.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/elemHide.js
diff --git a/lib/elemHide.js b/lib/elemHide.js
index 2c81a2324f579247d53eca5eeb6ac459210a937a..a3155163cfbbe6895d2fa4867a8d2dd02264ab95 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,27 @@ var usingGetSelectorsForDomain = !("nsIStyleSheetService" in Ci);
var filtersByDomain = Object.create(null);
/**
- * Lookup table, filters by selector. (Only contains filters that have a
+ * Lookup table, filter keys by selector. (Only contains filters that have a
* selector that is unconditionally matched for all domains.)
*/
-var filtersBySelector = Object.create(null);
+var filterKeysBySelector = Object.create(null);
/**
- * This array caches the keys of filtersBySelector table (selectors which
+ * This array caches the keys of filterKeysBySelector 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 filterKeysBySelector table (filterIds for
+ * selectors which unconditionally apply on all domains). It will be null if the
+ * cache needs to be rebuilt. Note: Only the first filter key for each selector
+ * is cached.
+ */
+var unconditionalFilterKeys = null;
+
+/**
* Object to be used instead when a filter has a blank domains property.
*/
var defaultDomains = Object.create(null);
@@ -95,16 +95,15 @@ var ElemHide = exports.ElemHide =
filterByKey = [];
keyByFilter = Object.create(null);
filtersByDomain = Object.create(null);
- filtersBySelector = Object.create(null);
- unconditionalSelectors = null;
+ filterKeysBySelector = 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 +134,16 @@ 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 filterKeys = filterKeysBySelector[selector];
+ if (filterKeys)
{
- // 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;
- }
+ for (let filterKey of filterKeys)
+ this._addToFiltersByDomain(filterKey, filterByKey[filterKey]);
+ delete filterKeysBySelector[selector];
+ unconditionalSelectors = unconditionalFilterKeys = null;
}
knownExceptions[filter.text] = true;
@@ -160,33 +156,64 @@ 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 filterKeys = filterKeysBySelector[filter.selector];
+ if (filterKeys)
{
- // 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;
- }
+ filterKeys.push(key);
}
else
{
- // The new filter's selector only applies to some domains
- this._addToFiltersByDomain(filter);
+ filterKeysBySelector[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: function(key, filter)
+ {
+ let filterKeys = filterKeysBySelector[filter.selector];
+ if (filterKeys)
+ {
+ let index = filterKeys.indexOf(key);
+ if (index >= 0)
+ {
+ if (filterKeys.length > 1)
+ {
+ filterKeys.splice(index, 1);
+ if (index == 0)
+ unconditionalFilterKeys = null;
+ }
+ else
+ {
+ delete filterKeysBySelector[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 in domains)
+ {
+ let filters = filtersByDomain[domain];
+ if (filters)
+ delete filters[key];
+ }
+ },
+
/**
* Removes an element hiding filter
* @param {ElemHideFilter} filter
@@ -212,34 +239,7 @@ var ElemHide = exports.ElemHide =
let key = keyByFilter[filter.text];
delete filterByKey[key];
delete keyByFilter[filter.text];
-
- if (usingGetSelectorsForDomain)
- {
- 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
- {
- let domains = filter.domains || defaultDomains;
- for (let domain in domains)
- {
- let filters = filtersByDomain[domain];
- if (filters)
- delete filters[key];
- }
- }
- }
+ this._removeFilterKey(key, filter);
}
FilterNotifier.emit("elemhideupdate");
@@ -265,7 +265,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,18 +298,86 @@ 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(filterKeysBySelector);
+ 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(filterKeysBySelector[selector][0]);
+ }
+ return unconditionalFilterKeys.slice();
+ },
+
+ /**
+ * Constant used by getSelectorsForDomain's when matching all selectors.
Wladimir Palant 2016/09/27 13:08:38 Nit: why "'s"? How about: Constant used by getSel
kzar 2016/09/27 13:53:06 No idea, I guess it's a typo that I missed and the
+ */
+ ALL_MATCHING: 0,
+
+ /**
+ * Constant used by getSelectorsForDomain's when not matching unconditional
+ * selectors.
Wladimir Palant 2016/09/27 13:08:38 How about: Constant used by getSelectorsForDomain
kzar 2016/09/27 13:53:06 Done.
+ */
+ NO_UNCONDITIONAL: 1,
+
+ /**
+ * Constant used by getSelectorsForDomain's when only matching specific
+ * selectors.
Wladimir Palant 2016/09/27 13:08:38 Nit: Just realized, "specific selectors" makes no
kzar 2016/09/27 13:53:06 Done.
+ */
+ SPECIFIC_ONLY: 2,
+
+ /**
+ * Determines from the current filter list which selectors should be applied
+ * on a particular host name. Optionally returns the corresponding filter
+ * keys.
+ * @param {String} domain
+ * @param {Number} [criteria]
+ * One of the following:
Wladimir Palant 2016/09/27 13:08:38 Nit: Please indent parameter and return value desc
kzar 2016/09/27 13:53:06 Done.
+ * ElemHide.ALL_MATCHING - Returns all matching selectors for the host name.
+ * ElemHide.NO_UNCONDITIONAL - Returns all matching selectors except those
+ * which match all host names unconditionally.
+ * ElemHide.SPECIFIC_ONLY - Returns only selectors for filters which
+ * specifically match the given host name.
Wladimir Palant 2016/09/27 13:08:38 Please don't document these constants twice, just
kzar 2016/09/27 13:53:06 Done.
+ * @param {Boolean} [provideFilterKeys]
+ * If true, the function will return a list of corresponding filter keys in
+ * addition to selectors.
+ * @returns {string[]|Array.<string[]>}
+ * List of selectors or an array with two elements (list of selectors and list
+ * of corresponding keys) if provideFilterKeys is true.
+ */
+ getSelectorsForDomain: function(domain, criteria, provideFilterKeys)
+ {
+ let filterKeys = [];
+ let selectors = [];
+
+ if (typeof criteria == "undefined")
+ criteria = ElemHide.ALL_MATCHING;
+ 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 currentDomain = domain ? domain.toUpperCase() : "";
while (true)
@@ -328,7 +396,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 +411,9 @@ var ElemHide = exports.ElemHide =
currentDomain = nextDot == -1 ? "" : currentDomain.substr(nextDot + 1);
}
- return selectors;
+ if (provideFilterKeys)
+ return [selectors, filterKeys];
+ else
+ return selectors;
}
};
« no previous file with comments | « no previous file | test/elemHide.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld