| 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-2016 Eyeo GmbH | 3  * Copyright (C) 2006-2016 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 | 
| 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
| 12  * GNU General Public License for more details. | 12  * GNU General Public License for more details. | 
| 13  * | 13  * | 
| 14  * You should have received a copy of the GNU General Public License | 14  * You should have received a copy of the GNU General Public License | 
| 15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
| 16  */ | 16  */ | 
| 17 | 17 | 
|  | 18 "use strict"; | 
|  | 19 | 
| 18 /** | 20 /** | 
| 19  * @fileOverview Element hiding implementation. | 21  * @fileOverview Element hiding implementation. | 
| 20  */ | 22  */ | 
| 21 | 23 | 
| 22 let {Utils} = require("utils"); | 24 const {Utils} = require("utils"); | 
| 23 let {ElemHideException} = require("filterClasses"); | 25 const {ElemHideException} = require("filterClasses"); | 
| 24 let {FilterNotifier} = require("filterNotifier"); | 26 const {FilterNotifier} = require("filterNotifier"); | 
| 25 | 27 | 
| 26 /** | 28 /** | 
| 27  * Lookup table, filters by their associated key | 29  * Lookup table, filters by their associated key | 
| 28  * @type Object | 30  * @type {Object} | 
| 29  */ | 31  */ | 
| 30 var filterByKey = []; | 32 let filterByKey = []; | 
| 31 | 33 | 
| 32 /** | 34 /** | 
| 33  * Lookup table, keys of the filters by filter text | 35  * Lookup table, keys of the filters by filter text | 
| 34  * @type Object | 36  * @type {Object} | 
| 35  */ | 37  */ | 
| 36 var keyByFilter = Object.create(null); | 38 let keyByFilter = Object.create(null); | 
| 37 | 39 | 
| 38 /** | 40 /** | 
| 39  * Nested lookup table, filter (or false if inactive) by filter key by domain. | 41  * Nested lookup table, filter (or false if inactive) by filter key by domain. | 
| 40  * (Only contains filters that aren't unconditionally matched for all domains.) | 42  * (Only contains filters that aren't unconditionally matched for all domains.) | 
| 41  * @type Object | 43  * @type {Object} | 
| 42  */ | 44  */ | 
| 43 var filtersByDomain = Object.create(null); | 45 let filtersByDomain = Object.create(null); | 
| 44 | 46 | 
| 45 /** | 47 /** | 
| 46  * Lookup table, filter key by selector. (Only used for selectors that are | 48  * Lookup table, filter key by selector. (Only used for selectors that are | 
| 47  * unconditionally matched for all domains.) | 49  * unconditionally matched for all domains.) | 
| 48  */ | 50  */ | 
| 49 var filterKeyBySelector = Object.create(null); | 51 let filterKeyBySelector = Object.create(null); | 
| 50 | 52 | 
| 51 /** | 53 /** | 
| 52  * This array caches the keys of filterKeyBySelector table (selectors which | 54  * This array caches the keys of filterKeyBySelector table (selectors which | 
| 53  * 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 | 
| 54  * be rebuilt. | 56  * be rebuilt. | 
| 55  */ | 57  */ | 
| 56 var unconditionalSelectors = null; | 58 let unconditionalSelectors = null; | 
| 57 | 59 | 
| 58 /** | 60 /** | 
| 59  * This array caches the values of filterKeyBySelector table (filterIds for | 61  * This array caches the values of filterKeyBySelector table (filterIds for | 
| 60  * selectors which unconditionally apply on all domains). It will be null if the | 62  * selectors which unconditionally apply on all domains). It will be null if the | 
| 61  * cache needs to be rebuilt. | 63  * cache needs to be rebuilt. | 
| 62  */ | 64  */ | 
| 63 var unconditionalFilterKeys = null; | 65 let unconditionalFilterKeys = null; | 
| 64 | 66 | 
| 65 /** | 67 /** | 
| 66  * Object to be used instead when a filter has a blank domains property. | 68  * Object to be used instead when a filter has a blank domains property. | 
| 67  */ | 69  */ | 
| 68 var defaultDomains = Object.create(null); | 70 let defaultDomains = Object.create(null); | 
| 69 defaultDomains[""] = true; | 71 defaultDomains[""] = true; | 
| 70 | 72 | 
| 71 /** | 73 /** | 
| 72  * Lookup table, keys are known element hiding exceptions | 74  * Lookup table, keys are known element hiding exceptions | 
| 73  * @type Object | 75  * @type {Object} | 
| 74  */ | 76  */ | 
| 75 var knownExceptions = Object.create(null); | 77 let knownExceptions = Object.create(null); | 
| 76 | 78 | 
| 77 /** | 79 /** | 
| 78  * Lookup table, lists of element hiding exceptions by selector | 80  * Lookup table, lists of element hiding exceptions by selector | 
| 79  * @type Object | 81  * @type {Object} | 
| 80  */ | 82  */ | 
| 81 var exceptions = Object.create(null); | 83 let exceptions = Object.create(null); | 
| 82 | 84 | 
| 83 /** | 85 /** | 
| 84  * Container for element hiding filters | 86  * Container for element hiding filters | 
| 85  * @class | 87  * @class | 
| 86  */ | 88  */ | 
| 87 var ElemHide = exports.ElemHide = | 89 let ElemHide = exports.ElemHide = { | 
| 88 { |  | 
| 89   /** | 90   /** | 
| 90    * Removes all known filters | 91    * Removes all known filters | 
| 91    */ | 92    */ | 
| 92   clear: function() | 93   clear() | 
| 93   { | 94   { | 
| 94     filterByKey = []; | 95     filterByKey = []; | 
| 95     keyByFilter = Object.create(null); | 96     keyByFilter = Object.create(null); | 
| 96     filtersByDomain = Object.create(null); | 97     filtersByDomain = Object.create(null); | 
| 97     filterKeyBySelector = Object.create(null); | 98     filterKeyBySelector = Object.create(null); | 
| 98     unconditionalSelectors = unconditionalFilterKeys = null; | 99     unconditionalSelectors = unconditionalFilterKeys = null; | 
| 99     knownExceptions = Object.create(null); | 100     knownExceptions = Object.create(null); | 
| 100     exceptions = Object.create(null); | 101     exceptions = Object.create(null); | 
| 101     FilterNotifier.emit("elemhideupdate"); | 102     FilterNotifier.emit("elemhideupdate"); | 
| 102   }, | 103   }, | 
| 103 | 104 | 
| 104   _addToFiltersByDomain: function(key, filter) | 105   _addToFiltersByDomain(key, filter) | 
| 105   { | 106   { | 
| 106     let domains = filter.domains || defaultDomains; | 107     let domains = filter.domains || defaultDomains; | 
| 107     for (let domain in domains) | 108     for (let domain in domains) | 
| 108     { | 109     { | 
| 109       let filters = filtersByDomain[domain]; | 110       let filters = filtersByDomain[domain]; | 
| 110       if (!filters) | 111       if (!filters) | 
| 111         filters = filtersByDomain[domain] = Object.create(null); | 112         filters = filtersByDomain[domain] = Object.create(null); | 
| 112 | 113 | 
| 113       if (domains[domain]) | 114       if (domains[domain]) | 
| 114         filters[key] = filter; | 115         filters[key] = filter; | 
| 115       else | 116       else | 
| 116         filters[key] = false; | 117         filters[key] = false; | 
| 117     } | 118     } | 
| 118   }, | 119   }, | 
| 119 | 120 | 
| 120   /** | 121   /** | 
| 121    * Add a new element hiding filter | 122    * Add a new element hiding filter | 
| 122    * @param {ElemHideFilter} filter | 123    * @param {ElemHideFilter} filter | 
| 123    */ | 124    */ | 
| 124   add: function(filter) | 125   add(filter) | 
| 125   { | 126   { | 
| 126     if (filter instanceof ElemHideException) | 127     if (filter instanceof ElemHideException) | 
| 127     { | 128     { | 
| 128       if (filter.text in knownExceptions) | 129       if (filter.text in knownExceptions) | 
| 129         return; | 130         return; | 
| 130 | 131 | 
| 131       let selector = filter.selector; | 132       let {selector} = filter; | 
| 132       if (!(selector in exceptions)) | 133       if (!(selector in exceptions)) | 
| 133         exceptions[selector] = []; | 134         exceptions[selector] = []; | 
| 134       exceptions[selector].push(filter); | 135       exceptions[selector].push(filter); | 
| 135 | 136 | 
| 136       // If this is the first exception for a previously unconditionally | 137       // If this is the first exception for a previously unconditionally | 
| 137       // applied element hiding selector we need to take care to update the | 138       // applied element hiding selector we need to take care to update the | 
| 138       // lookups. | 139       // lookups. | 
| 139       let filterKey = filterKeyBySelector[selector]; | 140       let filterKey = filterKeyBySelector[selector]; | 
| 140       if (typeof filterKey != "undefined") | 141       if (typeof filterKey != "undefined") | 
| 141       { | 142       { | 
| (...skipping 21 matching lines...) Expand all  Loading... | 
| 163       else | 164       else | 
| 164       { | 165       { | 
| 165         // The new filter's selector only applies to some domains | 166         // The new filter's selector only applies to some domains | 
| 166         this._addToFiltersByDomain(key, filter); | 167         this._addToFiltersByDomain(key, filter); | 
| 167       } | 168       } | 
| 168     } | 169     } | 
| 169 | 170 | 
| 170     FilterNotifier.emit("elemhideupdate"); | 171     FilterNotifier.emit("elemhideupdate"); | 
| 171   }, | 172   }, | 
| 172 | 173 | 
| 173   _removeFilterKey: function(key, filter) | 174   _removeFilterKey(key, filter) | 
| 174   { | 175   { | 
| 175     if (filterKeyBySelector[filter.selector] == key) | 176     if (filterKeyBySelector[filter.selector] == key) | 
| 176     { | 177     { | 
| 177       delete filterKeyBySelector[filter.selector]; | 178       delete filterKeyBySelector[filter.selector]; | 
| 178       unconditionalSelectors = unconditionalFilterKeys = null; | 179       unconditionalSelectors = unconditionalFilterKeys = null; | 
| 179       return; | 180       return; | 
| 180     } | 181     } | 
| 181 | 182 | 
| 182     // We haven't found this filter in unconditional filters, look in | 183     // We haven't found this filter in unconditional filters, look in | 
| 183     // filtersByDomain. | 184     // filtersByDomain. | 
| 184     let domains = filter.domains || defaultDomains; | 185     let domains = filter.domains || defaultDomains; | 
| 185     for (let domain in domains) | 186     for (let domain in domains) | 
| 186     { | 187     { | 
| 187       let filters = filtersByDomain[domain]; | 188       let filters = filtersByDomain[domain]; | 
| 188       if (filters) | 189       if (filters) | 
| 189         delete filters[key]; | 190         delete filters[key]; | 
| 190     } | 191     } | 
| 191   }, | 192   }, | 
| 192 | 193 | 
| 193   /** | 194   /** | 
| 194    * Removes an element hiding filter | 195    * Removes an element hiding filter | 
| 195    * @param {ElemHideFilter} filter | 196    * @param {ElemHideFilter} filter | 
| 196    */ | 197    */ | 
| 197   remove: function(filter) | 198   remove(filter) | 
| 198   { | 199   { | 
| 199     if (filter instanceof ElemHideException) | 200     if (filter instanceof ElemHideException) | 
| 200     { | 201     { | 
| 201       if (!(filter.text in knownExceptions)) | 202       if (!(filter.text in knownExceptions)) | 
| 202         return; | 203         return; | 
| 203 | 204 | 
| 204       let list = exceptions[filter.selector]; | 205       let list = exceptions[filter.selector]; | 
| 205       let index = list.indexOf(filter); | 206       let index = list.indexOf(filter); | 
| 206       if (index >= 0) | 207       if (index >= 0) | 
| 207         list.splice(index, 1); | 208         list.splice(index, 1); | 
| 208       delete knownExceptions[filter.text]; | 209       delete knownExceptions[filter.text]; | 
| 209     } | 210     } | 
| 210     else | 211     else | 
| 211     { | 212     { | 
| 212       if (!(filter.text in keyByFilter)) | 213       if (!(filter.text in keyByFilter)) | 
| 213         return; | 214         return; | 
| 214 | 215 | 
| 215       let key = keyByFilter[filter.text]; | 216       let key = keyByFilter[filter.text]; | 
| 216       delete filterByKey[key]; | 217       delete filterByKey[key]; | 
| 217       delete keyByFilter[filter.text]; | 218       delete keyByFilter[filter.text]; | 
| 218       this._removeFilterKey(key, filter); | 219       this._removeFilterKey(key, filter); | 
| 219     } | 220     } | 
| 220 | 221 | 
| 221     FilterNotifier.emit("elemhideupdate"); | 222     FilterNotifier.emit("elemhideupdate"); | 
| 222   }, | 223   }, | 
| 223 | 224 | 
| 224   /** | 225   /** | 
| 225    * Checks whether an exception rule is registered for a filter on a particular | 226    * Checks whether an exception rule is registered for a filter on a particular | 
| 226    * domain. | 227    * domain. | 
|  | 228    * @param {Filter} filter | 
|  | 229    * @param {string} docDomain | 
|  | 230    * @return {ElemHideException} | 
| 227    */ | 231    */ | 
| 228   getException: function(/**Filter*/ filter, /**String*/ docDomain) /**ElemHideE
     xception*/ | 232   getException(filter, docDomain) | 
| 229   { | 233   { | 
| 230     if (!(filter.selector in exceptions)) | 234     if (!(filter.selector in exceptions)) | 
| 231       return null; | 235       return null; | 
| 232 | 236 | 
| 233     let list = exceptions[filter.selector]; | 237     let list = exceptions[filter.selector]; | 
| 234     for (let i = list.length - 1; i >= 0; i--) | 238     for (let i = list.length - 1; i >= 0; i--) | 
|  | 239     { | 
| 235       if (list[i].isActiveOnDomain(docDomain)) | 240       if (list[i].isActiveOnDomain(docDomain)) | 
| 236         return list[i]; | 241         return list[i]; | 
|  | 242     } | 
| 237 | 243 | 
| 238     return null; | 244     return null; | 
| 239   }, | 245   }, | 
| 240 | 246 | 
| 241   /** | 247   /** | 
| 242    * Retrieves an element hiding filter by the corresponding protocol key | 248    * Retrieves an element hiding filter by the corresponding protocol key | 
|  | 249    * @param {number} key | 
|  | 250    * @return {Filter} | 
| 243    */ | 251    */ | 
| 244   getFilterByKey: function(/**Number*/ key) /**Filter*/ | 252   getFilterByKey(key) | 
| 245   { | 253   { | 
| 246     return (key in filterByKey ? filterByKey[key] : null); | 254     return (key in filterByKey ? filterByKey[key] : null); | 
| 247   }, | 255   }, | 
| 248 | 256 | 
| 249   /** | 257   /** | 
| 250    * Returns a list of all selectors as a nested map. On first level, the keys | 258    * Returns a list of all selectors as a nested map. On first level, the keys | 
| 251    * are all values of `ElemHideBase.selectorDomain` (domains on which these | 259    * are all values of `ElemHideBase.selectorDomain` (domains on which these | 
| 252    * selectors should apply, ignoring exceptions). The values are maps again, | 260    * selectors should apply, ignoring exceptions). The values are maps again, | 
| 253    * with the keys being selectors and values the corresponding filter keys. | 261    * with the keys being selectors and values the corresponding filter keys. | 
| 254    * @returns {Map.<String,Map<String,String>>} | 262    * @returns {Map.<String,Map<String,String>>} | 
| 255    */ | 263    */ | 
| 256   getSelectors: function() | 264   getSelectors() | 
| 257   { | 265   { | 
| 258     let domains = new Map(); | 266     let domains = new Map(); | 
| 259     for (let key in filterByKey) | 267     for (let key in filterByKey) | 
| 260     { | 268     { | 
| 261       let filter = filterByKey[key]; | 269       let filter = filterByKey[key]; | 
| 262       let selector = filter.selector; | 270       if (!filter.selector) | 
| 263       if (!selector) |  | 
| 264         continue; | 271         continue; | 
| 265 | 272 | 
| 266       let domain = filter.selectorDomain || ""; | 273       let domain = filter.selectorDomain || ""; | 
| 267 | 274 | 
| 268       if (!domains.has(domain)) | 275       if (!domains.has(domain)) | 
| 269         domains.set(domain, new Map()); | 276         domains.set(domain, new Map()); | 
| 270       domains.get(domain).set(selector, key); | 277       domains.get(domain).set(filter.selector, key); | 
| 271     } | 278     } | 
| 272 | 279 | 
| 273     return domains; | 280     return domains; | 
| 274   }, | 281   }, | 
| 275 | 282 | 
| 276   /** | 283   /** | 
| 277    * Returns a list of selectors that apply on each website unconditionally. | 284    * Returns a list of selectors that apply on each website unconditionally. | 
| 278    * @returns {String[]} | 285    * @returns {string[]} | 
| 279    */ | 286    */ | 
| 280   getUnconditionalSelectors: function() | 287   getUnconditionalSelectors() | 
| 281   { | 288   { | 
| 282     if (!unconditionalSelectors) | 289     if (!unconditionalSelectors) | 
| 283       unconditionalSelectors = Object.keys(filterKeyBySelector); | 290       unconditionalSelectors = Object.keys(filterKeyBySelector); | 
| 284     return unconditionalSelectors.slice(); | 291     return unconditionalSelectors.slice(); | 
| 285   }, | 292   }, | 
| 286 | 293 | 
| 287   /** | 294   /** | 
| 288    * Returns a list of filter keys for selectors which apply to all websites | 295    * Returns a list of filter keys for selectors which apply to all websites | 
| 289    * without exception. | 296    * without exception. | 
| 290    * @returns {Number[]} | 297    * @returns {number[]} | 
| 291    */ | 298    */ | 
| 292   getUnconditionalFilterKeys: function() | 299   getUnconditionalFilterKeys() | 
| 293   { | 300   { | 
| 294     if (!unconditionalFilterKeys) | 301     if (!unconditionalFilterKeys) | 
| 295     { | 302     { | 
| 296       let selectors = this.getUnconditionalSelectors(); | 303       let selectors = this.getUnconditionalSelectors(); | 
| 297       unconditionalFilterKeys = []; | 304       unconditionalFilterKeys = []; | 
| 298       for (let selector of selectors) | 305       for (let selector of selectors) | 
| 299         unconditionalFilterKeys.push(filterKeyBySelector[selector]); | 306         unconditionalFilterKeys.push(filterKeyBySelector[selector]); | 
| 300     } | 307     } | 
| 301     return unconditionalFilterKeys.slice(); | 308     return unconditionalFilterKeys.slice(); | 
| 302   }, | 309   }, | 
| (...skipping 14 matching lines...) Expand all  Loading... | 
| 317   /** | 324   /** | 
| 318    * Constant used by getSelectorsForDomain to return only selectors for filters | 325    * Constant used by getSelectorsForDomain to return only selectors for filters | 
| 319    * which specifically match the given host name. | 326    * which specifically match the given host name. | 
| 320    */ | 327    */ | 
| 321   SPECIFIC_ONLY: 2, | 328   SPECIFIC_ONLY: 2, | 
| 322 | 329 | 
| 323   /** | 330   /** | 
| 324    * Determines from the current filter list which selectors should be applied | 331    * Determines from the current filter list which selectors should be applied | 
| 325    * on a particular host name. Optionally returns the corresponding filter | 332    * on a particular host name. Optionally returns the corresponding filter | 
| 326    * keys. | 333    * keys. | 
| 327    * @param {String} domain | 334    * @param {string} domain | 
| 328    * @param {Number} [criteria] | 335    * @param {number} [criteria] | 
| 329    *   One of the following: ElemHide.ALL_MATCHING, ElemHide.NO_UNCONDITIONAL or | 336    *   One of the following: ElemHide.ALL_MATCHING, ElemHide.NO_UNCONDITIONAL or | 
| 330    *                         ElemHide.SPECIFIC_ONLY. | 337    *                         ElemHide.SPECIFIC_ONLY. | 
| 331    * @param {Boolean} [provideFilterKeys] | 338    * @param {boolean} [provideFilterKeys] | 
| 332    *   If true, the function will return a list of corresponding filter keys in | 339    *   If true, the function will return a list of corresponding filter keys in | 
| 333    *   addition to selectors. | 340    *   addition to selectors. | 
| 334    * @returns {string[]|Array.<string[]>} | 341    * @returns {string[]|Array.<string[]>} | 
| 335    *   List of selectors or an array with two elements (list of selectors and | 342    *   List of selectors or an array with two elements (list of selectors and | 
| 336    *   list of corresponding keys) if provideFilterKeys is true. | 343    *   list of corresponding keys) if provideFilterKeys is true. | 
| 337    */ | 344    */ | 
| 338   getSelectorsForDomain: function(domain, criteria, provideFilterKeys) | 345   getSelectorsForDomain(domain, criteria, provideFilterKeys) | 
| 339   { | 346   { | 
| 340     let filterKeys = []; | 347     let filterKeys = []; | 
| 341     let selectors = []; | 348     let selectors = []; | 
| 342 | 349 | 
| 343     if (typeof criteria == "undefined") | 350     if (typeof criteria == "undefined") | 
| 344       criteria = ElemHide.ALL_MATCHING; | 351       criteria = ElemHide.ALL_MATCHING; | 
| 345     if (criteria < ElemHide.NO_UNCONDITIONAL) | 352     if (criteria < ElemHide.NO_UNCONDITIONAL) | 
| 346     { | 353     { | 
| 347       selectors = this.getUnconditionalSelectors(); | 354       selectors = this.getUnconditionalSelectors(); | 
| 348       if (provideFilterKeys) | 355       if (provideFilterKeys) | 
| (...skipping 29 matching lines...) Expand all  Loading... | 
| 378 | 385 | 
| 379       if (currentDomain == "") | 386       if (currentDomain == "") | 
| 380         break; | 387         break; | 
| 381 | 388 | 
| 382       let nextDot = currentDomain.indexOf("."); | 389       let nextDot = currentDomain.indexOf("."); | 
| 383       currentDomain = nextDot == -1 ? "" : currentDomain.substr(nextDot + 1); | 390       currentDomain = nextDot == -1 ? "" : currentDomain.substr(nextDot + 1); | 
| 384     } | 391     } | 
| 385 | 392 | 
| 386     if (provideFilterKeys) | 393     if (provideFilterKeys) | 
| 387       return [selectors, filterKeys]; | 394       return [selectors, filterKeys]; | 
| 388     else | 395     return selectors; | 
| 389       return selectors; |  | 
| 390   } | 396   } | 
| 391 }; | 397 }; | 
| OLD | NEW | 
|---|