OLD | NEW |
1 /* | 1 /* |
2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
3 * Copyright (C) 2006-present eyeo GmbH | 3 * Copyright (C) 2006-present eyeo GmbH |
4 * | 4 * |
5 * Adblock Plus is free software: you can redistribute it and/or modify | 5 * Adblock Plus is free software: you can redistribute it and/or modify |
6 * it under the terms of the GNU General Public License version 3 as | 6 * it under the terms of the GNU General Public License version 3 as |
7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
8 * | 8 * |
9 * Adblock Plus is distributed in the hope that it will be useful, | 9 * Adblock Plus is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
51 let filterKeyBySelector = new Map(); | 51 let filterKeyBySelector = new Map(); |
52 | 52 |
53 /** | 53 /** |
54 * This array caches the keys of filterKeyBySelector table (selectors which | 54 * This array caches the keys of filterKeyBySelector table (selectors which |
55 * unconditionally apply on all domains). It will be null if the cache needs to | 55 * unconditionally apply on all domains). It will be null if the cache needs to |
56 * be rebuilt. | 56 * be rebuilt. |
57 */ | 57 */ |
58 let unconditionalSelectors = null; | 58 let unconditionalSelectors = null; |
59 | 59 |
60 /** | 60 /** |
61 * This array caches the values of filterKeyBySelector table (filterIds for | |
62 * selectors which unconditionally apply on all domains). It will be null if the | |
63 * cache needs to be rebuilt. | |
64 */ | |
65 let unconditionalFilterKeys = null; | |
66 | |
67 /** | |
68 * Object to be used instead when a filter has a blank domains property. | 61 * Object to be used instead when a filter has a blank domains property. |
69 */ | 62 */ |
70 let defaultDomains = new Map([["", true]]); | 63 let defaultDomains = new Map([["", true]]); |
71 | 64 |
72 /** | 65 /** |
73 * Set containing known element hiding exceptions | 66 * Set containing known element hiding exceptions |
74 * @type {Set.<string>} | 67 * @type {Set.<string>} |
75 */ | 68 */ |
76 let knownExceptions = new Set(); | 69 let knownExceptions = new Set(); |
77 | 70 |
(...skipping 12 matching lines...) Expand all Loading... |
90 * Removes all known filters | 83 * Removes all known filters |
91 */ | 84 */ |
92 clear() | 85 clear() |
93 { | 86 { |
94 for (let collection of [keyByFilter, filtersByDomain, filterKeyBySelector, | 87 for (let collection of [keyByFilter, filtersByDomain, filterKeyBySelector, |
95 knownExceptions, exceptions]) | 88 knownExceptions, exceptions]) |
96 { | 89 { |
97 collection.clear(); | 90 collection.clear(); |
98 } | 91 } |
99 filterByKey = []; | 92 filterByKey = []; |
100 unconditionalSelectors = unconditionalFilterKeys = null; | 93 unconditionalSelectors = null; |
101 FilterNotifier.emit("elemhideupdate"); | 94 FilterNotifier.emit("elemhideupdate"); |
102 }, | 95 }, |
103 | 96 |
104 _addToFiltersByDomain(key, filter) | 97 _addToFiltersByDomain(key, filter) |
105 { | 98 { |
106 let domains = filter.domains || defaultDomains; | 99 let domains = filter.domains || defaultDomains; |
107 for (let [domain, isIncluded] of domains) | 100 for (let [domain, isIncluded] of domains) |
108 { | 101 { |
109 let filters = filtersByDomain.get(domain); | 102 let filters = filtersByDomain.get(domain); |
110 if (!filters) | 103 if (!filters) |
(...skipping 21 matching lines...) Expand all Loading... |
132 exceptions.set(selector, [filter]); | 125 exceptions.set(selector, [filter]); |
133 | 126 |
134 // If this is the first exception for a previously unconditionally | 127 // If this is the first exception for a previously unconditionally |
135 // applied element hiding selector we need to take care to update the | 128 // applied element hiding selector we need to take care to update the |
136 // lookups. | 129 // lookups. |
137 let filterKey = filterKeyBySelector.get(selector); | 130 let filterKey = filterKeyBySelector.get(selector); |
138 if (typeof filterKey != "undefined") | 131 if (typeof filterKey != "undefined") |
139 { | 132 { |
140 this._addToFiltersByDomain(filterKey, filterByKey[filterKey]); | 133 this._addToFiltersByDomain(filterKey, filterByKey[filterKey]); |
141 filterKeyBySelector.delete(selector); | 134 filterKeyBySelector.delete(selector); |
142 unconditionalSelectors = unconditionalFilterKeys = null; | 135 unconditionalSelectors = null; |
143 } | 136 } |
144 | 137 |
145 knownExceptions.add(filter.text); | 138 knownExceptions.add(filter.text); |
146 } | 139 } |
147 else | 140 else |
148 { | 141 { |
149 if (keyByFilter.has(filter)) | 142 if (keyByFilter.has(filter)) |
150 return; | 143 return; |
151 | 144 |
152 let key = filterByKey.push(filter) - 1; | 145 let key = filterByKey.push(filter) - 1; |
153 keyByFilter.set(filter, key); | 146 keyByFilter.set(filter, key); |
154 | 147 |
155 if (!(filter.domains || exceptions.has(filter.selector))) | 148 if (!(filter.domains || exceptions.has(filter.selector))) |
156 { | 149 { |
157 // The new filter's selector is unconditionally applied to all domains | 150 // The new filter's selector is unconditionally applied to all domains |
158 filterKeyBySelector.set(filter.selector, key); | 151 filterKeyBySelector.set(filter.selector, key); |
159 unconditionalSelectors = unconditionalFilterKeys = null; | 152 unconditionalSelectors = null; |
160 } | 153 } |
161 else | 154 else |
162 { | 155 { |
163 // The new filter's selector only applies to some domains | 156 // The new filter's selector only applies to some domains |
164 this._addToFiltersByDomain(key, filter); | 157 this._addToFiltersByDomain(key, filter); |
165 } | 158 } |
166 } | 159 } |
167 | 160 |
168 FilterNotifier.emit("elemhideupdate"); | 161 FilterNotifier.emit("elemhideupdate"); |
169 }, | 162 }, |
170 | 163 |
171 _removeFilterKey(key, filter) | 164 _removeFilterKey(key, filter) |
172 { | 165 { |
173 if (filterKeyBySelector.get(filter.selector) == key) | 166 if (filterKeyBySelector.get(filter.selector) == key) |
174 { | 167 { |
175 filterKeyBySelector.delete(filter.selector); | 168 filterKeyBySelector.delete(filter.selector); |
176 unconditionalSelectors = unconditionalFilterKeys = null; | 169 unconditionalSelectors = null; |
177 return; | 170 return; |
178 } | 171 } |
179 | 172 |
180 // We haven't found this filter in unconditional filters, look in | 173 // We haven't found this filter in unconditional filters, look in |
181 // filtersByDomain. | 174 // filtersByDomain. |
182 let domains = filter.domains || defaultDomains; | 175 let domains = filter.domains || defaultDomains; |
183 for (let domain of domains.keys()) | 176 for (let domain of domains.keys()) |
184 { | 177 { |
185 let filters = filtersByDomain.get(domain); | 178 let filters = filtersByDomain.get(domain); |
186 if (filters) | 179 if (filters) |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
282 * @returns {string[]} | 275 * @returns {string[]} |
283 */ | 276 */ |
284 getUnconditionalSelectors() | 277 getUnconditionalSelectors() |
285 { | 278 { |
286 if (!unconditionalSelectors) | 279 if (!unconditionalSelectors) |
287 unconditionalSelectors = [...filterKeyBySelector.keys()]; | 280 unconditionalSelectors = [...filterKeyBySelector.keys()]; |
288 return unconditionalSelectors.slice(); | 281 return unconditionalSelectors.slice(); |
289 }, | 282 }, |
290 | 283 |
291 /** | 284 /** |
292 * Returns a list of filter keys for selectors which apply to all websites | |
293 * without exception. | |
294 * @returns {number[]} | |
295 */ | |
296 getUnconditionalFilterKeys() | |
297 { | |
298 if (!unconditionalFilterKeys) | |
299 { | |
300 let selectors = this.getUnconditionalSelectors(); | |
301 unconditionalFilterKeys = []; | |
302 for (let selector of selectors) | |
303 unconditionalFilterKeys.push(filterKeyBySelector.get(selector)); | |
304 } | |
305 return unconditionalFilterKeys.slice(); | |
306 }, | |
307 | |
308 | |
309 /** | |
310 * Constant used by getSelectorsForDomain to return all selectors applying to | 285 * Constant used by getSelectorsForDomain to return all selectors applying to |
311 * a particular hostname. | 286 * a particular hostname. |
312 */ | 287 */ |
313 ALL_MATCHING: 0, | 288 ALL_MATCHING: 0, |
314 | 289 |
315 /** | 290 /** |
316 * Constant used by getSelectorsForDomain to exclude selectors which apply to | 291 * Constant used by getSelectorsForDomain to exclude selectors which apply to |
317 * all websites without exception. | 292 * all websites without exception. |
318 */ | 293 */ |
319 NO_UNCONDITIONAL: 1, | 294 NO_UNCONDITIONAL: 1, |
320 | 295 |
321 /** | 296 /** |
322 * Constant used by getSelectorsForDomain to return only selectors for filters | 297 * Constant used by getSelectorsForDomain to return only selectors for filters |
323 * which specifically match the given host name. | 298 * which specifically match the given host name. |
324 */ | 299 */ |
325 SPECIFIC_ONLY: 2, | 300 SPECIFIC_ONLY: 2, |
326 | 301 |
327 /** | 302 /** |
328 * Determines from the current filter list which selectors should be applied | 303 * Determines from the current filter list which selectors should be applied |
329 * on a particular host name. Optionally returns the corresponding filter | 304 * on a particular host name. |
330 * keys. | |
331 * @param {string} domain | 305 * @param {string} domain |
332 * @param {number} [criteria] | 306 * @param {number} [criteria] |
333 * One of the following: ElemHide.ALL_MATCHING, ElemHide.NO_UNCONDITIONAL or | 307 * One of the following: ElemHide.ALL_MATCHING, ElemHide.NO_UNCONDITIONAL or |
334 * ElemHide.SPECIFIC_ONLY. | 308 * ElemHide.SPECIFIC_ONLY. |
335 * @param {boolean} [provideFilterKeys] | 309 * @returns {string[]} |
336 * If true, the function will return a list of corresponding filter keys in | 310 * List of selectors. |
337 * addition to selectors. | |
338 * @returns {string[]|Array.<string[]>} | |
339 * List of selectors or an array with two elements (list of selectors and | |
340 * list of corresponding keys) if provideFilterKeys is true. | |
341 */ | 311 */ |
342 getSelectorsForDomain(domain, criteria, provideFilterKeys) | 312 getSelectorsForDomain(domain, criteria) |
343 { | 313 { |
344 let filterKeys = []; | |
345 let selectors = []; | 314 let selectors = []; |
346 | 315 |
347 if (typeof criteria == "undefined") | 316 if (typeof criteria == "undefined") |
348 criteria = ElemHide.ALL_MATCHING; | 317 criteria = ElemHide.ALL_MATCHING; |
349 if (criteria < ElemHide.NO_UNCONDITIONAL) | 318 if (criteria < ElemHide.NO_UNCONDITIONAL) |
350 { | |
351 selectors = this.getUnconditionalSelectors(); | 319 selectors = this.getUnconditionalSelectors(); |
352 if (provideFilterKeys) | |
353 filterKeys = this.getUnconditionalFilterKeys(); | |
354 } | |
355 | 320 |
356 let specificOnly = (criteria >= ElemHide.SPECIFIC_ONLY); | 321 let specificOnly = (criteria >= ElemHide.SPECIFIC_ONLY); |
357 let seenFilters = new Set(); | 322 let seenFilters = new Set(); |
358 let currentDomain = domain ? domain.toUpperCase() : ""; | 323 let currentDomain = domain ? domain.toUpperCase() : ""; |
359 while (true) | 324 while (true) |
360 { | 325 { |
361 if (specificOnly && currentDomain == "") | 326 if (specificOnly && currentDomain == "") |
362 break; | 327 break; |
363 | 328 |
364 let filters = filtersByDomain.get(currentDomain); | 329 let filters = filtersByDomain.get(currentDomain); |
365 if (filters) | 330 if (filters) |
366 { | 331 { |
367 for (let [filterKey, filter] of filters) | 332 for (let [filterKey, filter] of filters) |
368 { | 333 { |
369 if (seenFilters.has(filterKey)) | 334 if (seenFilters.has(filterKey)) |
370 continue; | 335 continue; |
371 seenFilters.add(filterKey); | 336 seenFilters.add(filterKey); |
372 | 337 |
373 if (filter && !this.getException(filter, domain)) | 338 if (filter && !this.getException(filter, domain)) |
374 { | |
375 selectors.push(filter.selector); | 339 selectors.push(filter.selector); |
376 // It is faster to always push the key, even if not required. | |
377 filterKeys.push(filterKey); | |
378 } | |
379 } | 340 } |
380 } | 341 } |
381 | 342 |
382 if (currentDomain == "") | 343 if (currentDomain == "") |
383 break; | 344 break; |
384 | 345 |
385 let nextDot = currentDomain.indexOf("."); | 346 let nextDot = currentDomain.indexOf("."); |
386 currentDomain = nextDot == -1 ? "" : currentDomain.substr(nextDot + 1); | 347 currentDomain = nextDot == -1 ? "" : currentDomain.substr(nextDot + 1); |
387 } | 348 } |
388 | 349 |
389 if (provideFilterKeys) | |
390 return [selectors, filterKeys]; | |
391 return selectors; | 350 return selectors; |
392 } | 351 } |
393 }; | 352 }; |
OLD | NEW |