| 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; |