 Issue 29886555:
  Issue 6957 - Add generateStyleSheetForDomain function to ElemHide module  (Closed) 
  Base URL: https://hg.adblockplus.org/adblockpluscore/
    
  
    Issue 29886555:
  Issue 6957 - Add generateStyleSheetForDomain function to ElemHide module  (Closed) 
  Base URL: https://hg.adblockplus.org/adblockpluscore/| Index: lib/elemHide.js | 
| =================================================================== | 
| --- a/lib/elemHide.js | 
| +++ b/lib/elemHide.js | 
| @@ -51,16 +51,23 @@ | 
| * 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; | 
| /** | 
| + * The default style sheet that applies on all domains. This is based on the | 
| + * value of <code>{@link unconditionalSelectors}</code>. | 
| + * @type {?string} | 
| + */ | 
| +let defaultStyleSheet = 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 | 
| @@ -95,26 +102,94 @@ | 
| function getUnconditionalSelectors() | 
| { | 
| if (!unconditionalSelectors) | 
| unconditionalSelectors = [...filterBySelector.keys()]; | 
| return unconditionalSelectors; | 
| } | 
| +/** | 
| + * Returns the list of selectors that apply on a given domain from the subset | 
| + * of filters that do not apply unconditionally on all domains. | 
| + * | 
| + * @param {string} domain The domain. | 
| + * @param {boolean} [specificOnly=false] Whether selectors from generic filters | 
| + * should be included. | 
| + * | 
| + * @returns {Array.<string>} The list of selectors. | 
| + */ | 
| +function getConditionalSelectorsForDomain(domain, specificOnly = false) | 
| +{ | 
| + let selectors = []; | 
| + | 
| + let excluded = new Set(); | 
| + let currentDomain = domain ? domain.replace(/\.+$/, "").toLowerCase() : ""; | 
| + | 
| + // 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); | 
| + if (filters) | 
| + { | 
| + for (let [filter, isIncluded] of filters) | 
| + { | 
| + if (!isIncluded) | 
| + { | 
| + excluded.add(filter); | 
| + } | 
| + else | 
| + { | 
| + let {selector} = filter; | 
| + if ((excluded.size == 0 || !excluded.has(filter)) && | 
| + !ElemHideExceptions.getException(selector, domain)) | 
| + { | 
| + selectors.push(selector); | 
| + } | 
| + } | 
| + } | 
| + } | 
| + | 
| + if (currentDomain == "") | 
| + break; | 
| + | 
| + let nextDot = currentDomain.indexOf("."); | 
| + currentDomain = nextDot == -1 ? "" : currentDomain.substr(nextDot + 1); | 
| + } | 
| + | 
| + return selectors; | 
| +} | 
| + | 
| +/** | 
| + * Returns the default style sheet that applies on all domains. | 
| + * @returns {string} | 
| + */ | 
| +function getDefaultStyleSheet() | 
| +{ | 
| + if (!defaultStyleSheet) | 
| + defaultStyleSheet = createStyleSheet(getUnconditionalSelectors()); | 
| + | 
| + return defaultStyleSheet; | 
| +} | 
| + | 
| 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; | 
| + defaultStyleSheet = null; | 
| } | 
| }); | 
| /** | 
| * Container for element hiding filters | 
| * @class | 
| */ | 
| exports.ElemHide = { | 
| @@ -122,16 +197,18 @@ | 
| * Removes all known filters | 
| */ | 
| clear() | 
| { | 
| for (let collection of [filtersByDomain, filterBySelector, knownFilters]) | 
| collection.clear(); | 
| unconditionalSelectors = null; | 
| + defaultStyleSheet = null; | 
| + | 
| filterNotifier.emit("elemhideupdate"); | 
| }, | 
| /** | 
| * Add a new element hiding filter | 
| * @param {ElemHideFilter} filter | 
| */ | 
| add(filter) | 
| @@ -141,16 +218,17 @@ | 
| let {selector} = filter; | 
| if (!(filter.domains || ElemHideExceptions.hasExceptions(selector))) | 
| { | 
| // The new filter's selector is unconditionally applied to all domains | 
| filterBySelector.set(selector, filter); | 
| unconditionalSelectors = null; | 
| + defaultStyleSheet = null; | 
| } | 
| else | 
| { | 
| // The new filter's selector only applies to some domains | 
| addToFiltersByDomain(filter); | 
| } | 
| knownFilters.add(filter); | 
| @@ -168,16 +246,17 @@ | 
| let {selector} = filter; | 
| // Unconditially applied element hiding filters | 
| if (filterBySelector.get(selector) == filter) | 
| { | 
| filterBySelector.delete(selector); | 
| unconditionalSelectors = null; | 
| + defaultStyleSheet = null; | 
| } | 
| // Conditionally applied element hiding filters | 
| else | 
| { | 
| let domains = filter.domains || defaultDomains; | 
| for (let domain of domains.keys()) | 
| { | 
| let filters = filtersByDomain.get(domain); | 
| @@ -199,60 +278,51 @@ | 
| * 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) | 
| { | 
| - let selectors = []; | 
| 
Manish Jethani
2018/09/20 12:27:24
This entire block of code is moved into getConditi
 | 
| - | 
| - let excluded = new Set(); | 
| - let currentDomain = domain ? domain.replace(/\.+$/, "").toLowerCase() : ""; | 
| - | 
| - // 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); | 
| - if (filters) | 
| - { | 
| - for (let [filter, isIncluded] of filters) | 
| - { | 
| - if (!isIncluded) | 
| - { | 
| - excluded.add(filter); | 
| - } | 
| - else | 
| - { | 
| - let {selector} = filter; | 
| - if ((excluded.size == 0 || !excluded.has(filter)) && | 
| - !ElemHideExceptions.getException(selector, domain)) | 
| - { | 
| - selectors.push(selector); | 
| - } | 
| - } | 
| - } | 
| - } | 
| - | 
| - if (currentDomain == "") | 
| - break; | 
| - | 
| - let nextDot = currentDomain.indexOf("."); | 
| - currentDomain = nextDot == -1 ? "" : currentDomain.substr(nextDot + 1); | 
| - } | 
| + let selectors = getConditionalSelectorsForDomain(domain, specificOnly); | 
| if (!specificOnly) | 
| selectors = getUnconditionalSelectors().concat(selectors); | 
| return selectors; | 
| + }, | 
| + | 
| + /** | 
| + * @typedef {object} ElemHideStyleSheet | 
| + * @property {string} code CSS code. | 
| + * @property {Array.<string>} selectors List of selectors. | 
| + */ | 
| + | 
| + /** | 
| + * Generates a style sheet for a given domain based on the current set of | 
| + * filters. | 
| + * | 
| + * @param {string} domain The domain. | 
| + * @param {boolean} [specificOnly=false] Whether selectors from generic | 
| + * filters should be included. | 
| + * | 
| + * @returns {ElemHideStyleSheet} An object containing the CSS code and the | 
| + * list of selectors. | 
| + */ | 
| + generateStyleSheetForDomain(domain, specificOnly = false) | 
| 
Manish Jethani
2018/09/20 12:27:24
The idea is that calling this function will be fas
 
Jon Sonesen
2018/09/23 18:01:59
Acknowledged.
 | 
| + { | 
| + let selectors = getConditionalSelectorsForDomain(domain, specificOnly); | 
| + let code = (specificOnly ? "" : getDefaultStyleSheet()) + | 
| + createStyleSheet(selectors); | 
| 
Jon Sonesen
2018/09/23 18:01:59
Regarding the use of this ternary operation, I won
 
Manish Jethani
2018/09/24 11:51:14
This function is supposed to be very performance c
 
Jon Sonesen
2018/09/24 15:09:44
Ah yeah, that's a good point here. My bad, haha I
 
Manish Jethani
2018/09/27 15:58:29
So I tested this by the way, it seems the Patch Se
 
Manish Jethani
2018/09/27 15:58:29
Acknowledged.
 | 
| + | 
| + if (!specificOnly) | 
| + selectors = getUnconditionalSelectors().concat(selectors); | 
| + | 
| + return {code, selectors}; | 
| } | 
| }; | 
| /** | 
| * Splits a list of selectors into groups determined by the value of | 
| * <code>{@link selectorGroupSize}</code>. | 
| * | 
| * @param {Array.<string>} selectors |