Index: lib/elemHideEmulation.js |
=================================================================== |
--- a/lib/elemHideEmulation.js |
+++ b/lib/elemHideEmulation.js |
@@ -17,64 +17,144 @@ |
"use strict"; |
/** |
* @fileOverview Element hiding emulation implementation. |
*/ |
const {ElemHide} = require("./elemHide"); |
-const {Filter} = require("./filterClasses"); |
+const {filterIt, mapIt, flattenIt, regExpIt} = require("./coreUtils"); |
+ |
+/** |
+ * Map of element hiding emulation filters by domain |
+ * @type {Map.<string,Map.<ElemHideEmulationFilter,boolean>>} |
+ */ |
+let filtersByDomain = new Map(); |
+ |
+/** |
+ * Set containing known element hiding emulation filters |
+ * @type {Set.<ElemHideEmulation>} |
+ */ |
+let knownFilters = new Set(); |
-let filters = new Set(); |
+/** |
+ * Yields the domains associated with a filter, along with whether the filter |
+ * should be included on the domain and the set of filters associated with the |
+ * domain |
+ * @param {ElemHideEmulationFilter} filter |
+ * @yields {Array.<string,boolean,?Set.<ElemHideEmulationFilter>>} |
+ */ |
+function* filterDomains(filter) |
+{ |
+ yield* mapIt(filterIt(filter.domains || [], ([domain]) => domain != ""), |
+ ([domain, include]) => [domain, include, |
+ filtersByDomain.get(domain)]); |
+} |
+ |
+/** |
+ * Yields subdomains of a domain |
+ * @param {string} domain |
+ * @yields {string} |
+ */ |
+function* subdomains(domain) |
+{ |
+ yield* mapIt(regExpIt(/([^|]*)\|/g, domain.replace(/([^.]+\.)/g, "$'|")), |
+ ([, subdomain]) => subdomain); |
+} |
+ |
+/** |
+ * Yields the filters for a domain and its subdomains, along with whether the |
+ * filter should be included on its corresponding domain |
+ * @param {string} domain |
+ * @yields {Array.<ElemHideEmulationFilter,boolean>} |
+ */ |
+function* filtersForDomain(domain) |
+{ |
+ yield* filtersByDomain.get(domain) || []; |
+ |
+ yield* flattenIt(mapIt(subdomains(domain), |
+ subdomain => filtersByDomain.get(subdomain) || [])); |
+} |
/** |
* Container for element hiding emulation filters |
* @class |
*/ |
let ElemHideEmulation = { |
/** |
* Removes all known filters |
*/ |
clear() |
{ |
- filters.clear(); |
+ filtersByDomain.clear(); |
}, |
/** |
* Add a new element hiding emulation filter |
* @param {ElemHideEmulationFilter} filter |
*/ |
add(filter) |
{ |
- filters.add(filter.text); |
+ if (knownFilters.has(filter)) |
+ return; |
+ |
+ for (let [domain, include, filters] of filterDomains(filter)) |
+ { |
+ if (filters) |
+ filters.set(filter, include); |
+ else |
+ filtersByDomain.set(domain, new Map([[filter, include]])); |
+ } |
+ |
+ knownFilters.add(filter); |
}, |
/** |
* Removes an element hiding emulation filter |
* @param {ElemHideEmulationFilter} filter |
*/ |
remove(filter) |
{ |
- filters.delete(filter.text); |
+ if (!knownFilters.has(filter)) |
+ return; |
+ |
+ for (let [domain, , filters] of filterDomains(filter)) |
+ { |
+ if (filters) |
+ { |
+ filters.delete(filter); |
+ |
+ if (filters.size == 0) |
+ filtersByDomain.delete(domain); |
+ } |
+ } |
+ |
+ knownFilters.delete(filter); |
}, |
/** |
* Returns a list of all rules active on a particular domain |
* @param {string} domain |
* @return {ElemHideEmulationFilter[]} |
*/ |
getRulesForDomain(domain) |
{ |
let result = []; |
- for (let text of filters.values()) |
+ |
+ let excludeSet = new Set(); |
+ for (let [filter, include] of filtersForDomain(domain.toUpperCase())) |
{ |
- let filter = Filter.fromText(text); |
- if (filter.isActiveOnDomain(domain) && |
- !ElemHide.getException(filter, domain)) |
+ if (!include) |
+ { |
+ excludeSet.add(filter); |
+ } |
+ else if ((excludeSet.size == 0 || !excludeSet.has(filter)) && |
+ !ElemHide.getException(filter, domain)) |
{ |
result.push(filter); |
} |
} |
+ |
return result; |
} |
}; |
exports.ElemHideEmulation = ElemHideEmulation; |