| Index: lib/elemHideEmulation.js | 
| =================================================================== | 
| --- a/lib/elemHideEmulation.js | 
| +++ b/lib/elemHideEmulation.js | 
| @@ -17,64 +17,149 @@ | 
| "use strict"; | 
| /** | 
| * @fileOverview Element hiding emulation implementation. | 
| */ | 
| const {ElemHide} = require("./elemHide"); | 
| -const {Filter} = require("./filterClasses"); | 
| +const {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) | 
| +{ | 
| + for (let [domain, include] of filter.domains || []) | 
| + { | 
| + if (domain != "") | 
| + yield [domain, include, filtersByDomain.get(domain)]; | 
| + } | 
| +} | 
| + | 
| +/** | 
| + * Yields subdomains of a domain | 
| + * @param {string} domain | 
| + * @yields {string} | 
| + */ | 
| +function* subdomains(domain) | 
| +{ | 
| + for (let [, subdomain] of | 
| + regExpIt(/([^|]*)\|/g, domain.replace(/([^.]+\.)/g, "$'|"))) | 
| + { | 
| + yield 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) || []; | 
| + | 
| + for (let subdomain of subdomains(domain)) | 
| + yield* 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; |