| Left: | ||
| Right: | 
| LEFT | RIGHT | 
|---|---|
| 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 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 121 /** | 121 /** | 
| 122 * The number of subscriptions in the storage. | 122 * The number of subscriptions in the storage. | 
| 123 * @type {number} | 123 * @type {number} | 
| 124 */ | 124 */ | 
| 125 get subscriptionCount() | 125 get subscriptionCount() | 
| 126 { | 126 { | 
| 127 return this.knownSubscriptions.size; | 127 return this.knownSubscriptions.size; | 
| 128 } | 128 } | 
| 129 | 129 | 
| 130 /** | 130 /** | 
| 131 * Adds any subscriptions to which a filter belongs to the filter. | 131 * Yields subscriptions in the storage to which the given filter belongs. | 
| 132 * @param {Filter} filter | 132 * @param {Filter} filter | 
| 133 */ | 133 * @yields {Subscription} | 
| 134 addSubscriptionsToFilter(filter) | 134 */ | 
| 135 { | 135 *subscriptionsForFilter(filter) | 
| 136 for (let subscription of this.subscriptions()) | 136 { | 
| 137 { | 137 if (!filter.subscriptionsAdded) | 
| 138 if (subscription.filters.indexOf(filter) != -1) | 138 addSubscriptionsToFilter(filter); | 
| 
 
hub
2018/11/10 04:33:21
this is quite an expensive search, isn't it?
 
Manish Jethani
2018/11/15 22:58:52
Yes, so here's the thing:
 1.  This function will
 
hub
2018/11/16 17:04:39
So shall we make sure the review 29934588 lands fi
 
Manish Jethani
2018/11/17 19:49:17
OK, let's do this one first instead, it's easier:
 
 | |
| 139 filter.addSubscription(subscription); | 139 | 
| 140 } | 140 yield* filter.subscriptions(); | 
| 141 | 141 } | 
| 142 filter.subscriptionsAssigned = true; | 142 | 
| 143 /** | |
| 144 * Returns the number of subscriptions in the storage to which the given | |
| 145 * filter belongs. | |
| 146 * @param {Filter} filter | |
| 147 * @return {number} | |
| 148 */ | |
| 149 getSubscriptionCountForFilter(filter) | |
| 150 { | |
| 151 if (!filter.subscriptionsAdded) | |
| 152 addSubscriptionsToFilter(filter); | |
| 153 | |
| 154 return filter.subscriptionCount; | |
| 143 } | 155 } | 
| 144 | 156 | 
| 145 /** | 157 /** | 
| 146 * Finds the filter group that a filter should be added to by default. Will | 158 * Finds the filter group that a filter should be added to by default. Will | 
| 147 * return <code>null</code> if this group doesn't exist yet. | 159 * return <code>null</code> if this group doesn't exist yet. | 
| 148 * @param {Filter} filter | 160 * @param {Filter} filter | 
| 149 * @returns {?SpecialSubscription} | 161 * @returns {?SpecialSubscription} | 
| 150 */ | 162 */ | 
| 151 getGroupForFilter(filter) | 163 getGroupForFilter(filter) | 
| 152 { | 164 { | 
| (...skipping 23 matching lines...) Expand all Loading... | |
| 176 */ | 188 */ | 
| 177 addSubscription(subscription) | 189 addSubscription(subscription) | 
| 178 { | 190 { | 
| 179 if (this.knownSubscriptions.has(subscription.url)) | 191 if (this.knownSubscriptions.has(subscription.url)) | 
| 180 return; | 192 return; | 
| 181 | 193 | 
| 182 this.knownSubscriptions.set(subscription.url, subscription); | 194 this.knownSubscriptions.set(subscription.url, subscription); | 
| 183 connectSubscriptionFilters(subscription); | 195 connectSubscriptionFilters(subscription); | 
| 184 | 196 | 
| 185 filterNotifier.emit("subscription.added", subscription); | 197 filterNotifier.emit("subscription.added", subscription); | 
| 198 | |
| 199 subscription.clearCaches(); | |
| 186 } | 200 } | 
| 187 | 201 | 
| 188 /** | 202 /** | 
| 189 * Removes a subscription from the storage. | 203 * Removes a subscription from the storage. | 
| 190 * @param {Subscription} subscription The subscription to be removed. | 204 * @param {Subscription} subscription The subscription to be removed. | 
| 191 */ | 205 */ | 
| 192 removeSubscription(subscription) | 206 removeSubscription(subscription) | 
| 193 { | 207 { | 
| 194 if (!this.knownSubscriptions.has(subscription.url)) | 208 if (!this.knownSubscriptions.has(subscription.url)) | 
| 195 return; | 209 return; | 
| 196 | 210 | 
| 197 disconnectSubscriptionFilters(subscription); | 211 disconnectSubscriptionFilters(subscription); | 
| 198 | 212 | 
| 199 this.knownSubscriptions.delete(subscription.url); | 213 this.knownSubscriptions.delete(subscription.url); | 
| 200 | 214 | 
| 201 // This should be the last remaining reference to the Subscription | 215 // This should be the last remaining reference to the Subscription | 
| 202 // object. | 216 // object. | 
| 203 Subscription.knownSubscriptions.delete(subscription.url); | 217 Subscription.knownSubscriptions.delete(subscription.url); | 
| 204 | 218 | 
| 205 filterNotifier.emit("subscription.removed", subscription); | 219 filterNotifier.emit("subscription.removed", subscription); | 
| 206 } | 220 } | 
| 207 | 221 | 
| 208 /** | 222 /** | 
| 209 * Replaces the list of filters in a subscription with a new list. | 223 * Replaces the list of filters in a subscription with a new list. | 
| 210 * @param {Subscription} subscription The subscription to be updated. | 224 * @param {Subscription} subscription The subscription to be updated. | 
| 211 * @param {Array.<Filter>} filters The new list of filters. | 225 * @param {Array.<Filter>} filters The new list of filters. | 
| 212 */ | 226 */ | 
| 213 updateSubscriptionFilters(subscription, filters) | 227 updateSubscriptionFilters(subscription, filters) | 
| 214 { | 228 { | 
| 215 disconnectSubscriptionFilters(subscription); | 229 let oldFilters = [...subscription.filters()]; | 
| 216 let oldFilters = subscription.filters; | 230 disconnectSubscriptionFilters(subscription, oldFilters); | 
| 217 subscription.filters = filters; | 231 subscription.clearFilters(); | 
| 218 connectSubscriptionFilters(subscription); | 232 | 
| 233 for (let filter of filters) | |
| 234 subscription.addFilter(filter); | |
| 235 | |
| 236 connectSubscriptionFilters(subscription, filters); | |
| 237 | |
| 219 filterNotifier.emit("subscription.updated", subscription, oldFilters); | 238 filterNotifier.emit("subscription.updated", subscription, oldFilters); | 
| 239 | |
| 240 subscription.clearCaches(); | |
| 220 } | 241 } | 
| 221 | 242 | 
| 222 /** | 243 /** | 
| 223 * Adds a user-defined filter to the storage. | 244 * Adds a user-defined filter to the storage. | 
| 224 * @param {Filter} filter | 245 * @param {Filter} filter | 
| 225 * @param {?SpecialSubscription} [subscription] The subscription that the | 246 * @param {?SpecialSubscription} [subscription] The subscription that the | 
| 226 * filter should be added to. | 247 * filter should be added to. | 
| 227 * @param {number} [position] The position within the subscription at which | 248 * @param {number} [position] The position within the subscription at which | 
| 228 * the filter should be added. If not specified, the filter is added at the | 249 * the filter should be added. If not specified, the filter is added at the | 
| 229 * end of the subscription. | 250 * end of the subscription. | 
| 230 */ | 251 */ | 
| 231 addFilter(filter, subscription, position) | 252 addFilter(filter, subscription, position) | 
| 232 { | 253 { | 
| 233 if (!subscription) | 254 if (!subscription) | 
| 234 { | 255 { | 
| 235 for (let currentSubscription of filter.subscriptions()) | 256 for (let currentSubscription of this.subscriptionsForFilter(filter)) | 
| 236 { | 257 { | 
| 237 if (currentSubscription instanceof SpecialSubscription && | 258 if (currentSubscription instanceof SpecialSubscription && | 
| 238 !currentSubscription.disabled) | 259 !currentSubscription.disabled) | 
| 239 { | 260 { | 
| 240 return; // No need to add | 261 return; // No need to add | 
| 241 } | 262 } | 
| 242 } | 263 } | 
| 243 subscription = this.getGroupForFilter(filter); | 264 subscription = this.getGroupForFilter(filter); | 
| 244 } | 265 } | 
| 245 if (!subscription) | 266 if (!subscription) | 
| 246 { | 267 { | 
| 247 // No group for this filter exists, create one | 268 // No group for this filter exists, create one | 
| 248 subscription = SpecialSubscription.createForFilter(filter); | 269 subscription = SpecialSubscription.createForFilter(filter); | 
| 249 this.addSubscription(subscription); | 270 this.addSubscription(subscription); | 
| 250 return; | 271 return; | 
| 251 } | 272 } | 
| 252 | 273 | 
| 253 if (typeof position == "undefined") | 274 if (typeof position == "undefined") | 
| 254 position = subscription.filters.length; | 275 position = subscription.filterCount; | 
| 255 | 276 | 
| 256 filter.addSubscription(subscription); | 277 filter.addSubscription(subscription); | 
| 257 subscription.filters.splice(position, 0, filter); | 278 subscription.insertFilterAt(filter, position); | 
| 258 filterNotifier.emit("filter.added", filter, subscription, position); | 279 filterNotifier.emit("filter.added", filter, subscription, position); | 
| 259 } | 280 } | 
| 260 | 281 | 
| 261 /** | 282 /** | 
| 262 * Removes a user-defined filter from the storage. | 283 * Removes a user-defined filter from the storage. | 
| 263 * @param {Filter} filter | 284 * @param {Filter} filter | 
| 264 * @param {?SpecialSubscription} [subscription] The subscription that the | 285 * @param {?SpecialSubscription} [subscription] The subscription that the | 
| 265 * filter should be removed from. If not specified, the filter will be | 286 * filter should be removed from. If not specified, the filter will be | 
| 266 * removed from all subscriptions. | 287 * removed from all subscriptions. | 
| 267 * @param {number} [position] The position within the subscription at which | 288 * @param {number} [position] The position within the subscription at which | 
| 268 * the filter should be removed. If not specified, all instances of the | 289 * the filter should be removed. If not specified, all instances of the | 
| 269 * filter will be removed. | 290 * filter will be removed. | 
| 270 */ | 291 */ | 
| 271 removeFilter(filter, subscription, position) | 292 removeFilter(filter, subscription, position) | 
| 272 { | 293 { | 
| 273 let subscriptions = ( | 294 let subscriptions = ( | 
| 274 subscription ? [subscription] : filter.subscriptions() | 295 subscription ? [subscription] : this.subscriptionsForFilter(filter) | 
| 275 ); | 296 ); | 
| 276 for (let currentSubscription of subscriptions) | 297 for (let currentSubscription of subscriptions) | 
| 277 { | 298 { | 
| 278 if (currentSubscription instanceof SpecialSubscription) | 299 if (currentSubscription instanceof SpecialSubscription) | 
| 279 { | 300 { | 
| 280 let positions = []; | 301 let positions = []; | 
| 281 if (typeof position == "undefined") | 302 if (typeof position == "undefined") | 
| 282 { | 303 { | 
| 283 let index = -1; | 304 let index = -1; | 
| 284 do | 305 do | 
| 285 { | 306 { | 
| 286 index = currentSubscription.filters.indexOf(filter, index + 1); | 307 index = currentSubscription.searchFilter(filter, index + 1); | 
| 287 if (index >= 0) | 308 if (index >= 0) | 
| 288 positions.push(index); | 309 positions.push(index); | 
| 289 } while (index >= 0); | 310 } while (index >= 0); | 
| 290 } | 311 } | 
| 291 else | 312 else | 
| 292 positions.push(position); | 313 positions.push(position); | 
| 293 | 314 | 
| 294 for (let j = positions.length - 1; j >= 0; j--) | 315 for (let j = positions.length - 1; j >= 0; j--) | 
| 295 { | 316 { | 
| 296 let currentPosition = positions[j]; | 317 let currentPosition = positions[j]; | 
| 297 if (currentSubscription.filters[currentPosition] == filter) | 318 let currentFilter = currentSubscription.filterAt(currentPosition); | 
| 319 if (currentFilter && currentFilter.text == filter.text) | |
| 298 { | 320 { | 
| 299 currentSubscription.filters.splice(currentPosition, 1); | 321 currentSubscription.deleteFilterAt(currentPosition); | 
| 300 if (currentSubscription.filters.indexOf(filter) < 0) | 322 if (currentSubscription.searchFilter(filter) < 0) | 
| 301 filter.removeSubscription(currentSubscription); | 323 filter.removeSubscription(currentSubscription); | 
| 302 filterNotifier.emit("filter.removed", filter, currentSubscription, | 324 filterNotifier.emit("filter.removed", filter, currentSubscription, | 
| 303 currentPosition); | 325 currentPosition); | 
| 304 } | 326 } | 
| 305 } | 327 } | 
| 306 } | 328 } | 
| 307 } | 329 } | 
| 308 } | 330 } | 
| 309 | 331 | 
| 310 /** | 332 /** | 
| 311 * Moves a user-defined filter to a new position. | 333 * Moves a user-defined filter to a new position. | 
| 312 * @param {Filter} filter | 334 * @param {Filter} filter | 
| 313 * @param {SpecialSubscription} subscription The subscription where the | 335 * @param {SpecialSubscription} subscription The subscription where the | 
| 314 * filter is located. | 336 * filter is located. | 
| 315 * @param {number} oldPosition The current position of the filter. | 337 * @param {number} oldPosition The current position of the filter. | 
| 316 * @param {number} newPosition The new position of the filter. | 338 * @param {number} newPosition The new position of the filter. | 
| 317 */ | 339 */ | 
| 318 moveFilter(filter, subscription, oldPosition, newPosition) | 340 moveFilter(filter, subscription, oldPosition, newPosition) | 
| 319 { | 341 { | 
| 320 if (!(subscription instanceof SpecialSubscription) || | 342 if (!(subscription instanceof SpecialSubscription)) | 
| 321 subscription.filters[oldPosition] != filter) | |
| 322 { | |
| 323 return; | 343 return; | 
| 324 } | 344 | 
| 345 let currentFilter = subscription.filterAt(oldPosition); | |
| 346 if (!currentFilter || currentFilter.text != filter.text) | |
| 347 return; | |
| 325 | 348 | 
| 326 newPosition = Math.min(Math.max(newPosition, 0), | 349 newPosition = Math.min(Math.max(newPosition, 0), | 
| 327 subscription.filters.length - 1); | 350 subscription.filterCount - 1); | 
| 328 if (oldPosition == newPosition) | 351 if (oldPosition == newPosition) | 
| 329 return; | 352 return; | 
| 330 | 353 | 
| 331 subscription.filters.splice(oldPosition, 1); | 354 subscription.deleteFilterAt(oldPosition); | 
| 332 subscription.filters.splice(newPosition, 0, filter); | 355 subscription.insertFilterAt(filter, newPosition); | 
| 333 filterNotifier.emit("filter.moved", filter, subscription, oldPosition, | 356 filterNotifier.emit("filter.moved", filter, subscription, oldPosition, | 
| 334 newPosition); | 357 newPosition); | 
| 335 } | 358 } | 
| 336 | 359 | 
| 337 /** | 360 /** | 
| 338 * Increases the hit count for a filter by one. | 361 * Increases the hit count for a filter by one. | 
| 339 * @param {Filter} filter | 362 * @param {Filter} filter | 
| 340 */ | 363 */ | 
| 341 increaseHitCount(filter) | 364 increaseHitCount(filter) | 
| 342 { | 365 { | 
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 388 let knownSubscriptions = new Map(); | 411 let knownSubscriptions = new Map(); | 
| 389 for (let subscription of parser.subscriptions) | 412 for (let subscription of parser.subscriptions) | 
| 390 knownSubscriptions.set(subscription.url, subscription); | 413 knownSubscriptions.set(subscription.url, subscription); | 
| 391 | 414 | 
| 392 this.fileProperties = parser.fileProperties; | 415 this.fileProperties = parser.fileProperties; | 
| 393 this.knownSubscriptions = knownSubscriptions; | 416 this.knownSubscriptions = knownSubscriptions; | 
| 394 Filter.knownFilters = parser.knownFilters; | 417 Filter.knownFilters = parser.knownFilters; | 
| 395 Subscription.knownSubscriptions = parser.knownSubscriptions; | 418 Subscription.knownSubscriptions = parser.knownSubscriptions; | 
| 396 | 419 | 
| 397 if (!silent) | 420 if (!silent) | 
| 421 { | |
| 398 filterNotifier.emit("load"); | 422 filterNotifier.emit("load"); | 
| 423 | |
| 424 // Clear any in-memory caches that may have been created during | |
| 425 // initialization. | |
| 426 clearSubscriptionCaches(); | |
| 427 } | |
| 399 } | 428 } | 
| 400 }; | 429 }; | 
| 401 } | 430 } | 
| 402 | 431 | 
| 403 /** | 432 /** | 
| 404 * Loads all subscriptions from disk. | 433 * Loads all subscriptions from disk. | 
| 405 * @returns {Promise} A promise resolved or rejected when loading is complete. | 434 * @returns {Promise} A promise resolved or rejected when loading is complete. | 
| 406 */ | 435 */ | 
| 407 loadFromDisk() | 436 loadFromDisk() | 
| 408 { | 437 { | 
| (...skipping 28 matching lines...) Expand all Loading... | |
| 437 } | 466 } | 
| 438 }); | 467 }); | 
| 439 }).catch(error => | 468 }).catch(error => | 
| 440 { | 469 { | 
| 441 Cu.reportError(error); | 470 Cu.reportError(error); | 
| 442 return tryBackup(1); | 471 return tryBackup(1); | 
| 443 }).then(() => | 472 }).then(() => | 
| 444 { | 473 { | 
| 445 this.initialized = true; | 474 this.initialized = true; | 
| 446 filterNotifier.emit("load"); | 475 filterNotifier.emit("load"); | 
| 476 clearSubscriptionCaches(); | |
| 447 }); | 477 }); | 
| 448 } | 478 } | 
| 449 | 479 | 
| 450 /** | 480 /** | 
| 451 * Constructs the file name for a <code>patterns.ini</code> backup. | 481 * Constructs the file name for a <code>patterns.ini</code> backup. | 
| 452 * @param {number} backupIndex Number of the backup file (1 being the most | 482 * @param {number} backupIndex Number of the backup file (1 being the most | 
| 453 * recent). | 483 * recent). | 
| 454 * @returns {string} Backup file name. | 484 * @returns {string} Backup file name. | 
| 455 */ | 485 */ | 
| 456 getBackupName(backupIndex) | 486 getBackupName(backupIndex) | 
| (...skipping 27 matching lines...) Expand all Loading... | |
| 484 * @yields {string} | 514 * @yields {string} | 
| 485 */ | 515 */ | 
| 486 *exportData() | 516 *exportData() | 
| 487 { | 517 { | 
| 488 // Do not persist external subscriptions | 518 // Do not persist external subscriptions | 
| 489 let subscriptions = []; | 519 let subscriptions = []; | 
| 490 for (let subscription of this.subscriptions()) | 520 for (let subscription of this.subscriptions()) | 
| 491 { | 521 { | 
| 492 if (!(subscription instanceof ExternalSubscription) && | 522 if (!(subscription instanceof ExternalSubscription) && | 
| 493 !(subscription instanceof SpecialSubscription && | 523 !(subscription instanceof SpecialSubscription && | 
| 494 subscription.filters.length == 0)) | 524 subscription.filterCount == 0)) | 
| 495 { | 525 { | 
| 496 subscriptions.push(subscription); | 526 subscriptions.push(subscription); | 
| 497 } | 527 } | 
| 498 } | 528 } | 
| 499 | 529 | 
| 500 yield "# Adblock Plus preferences"; | 530 yield "# Adblock Plus preferences"; | 
| 501 yield "version=" + this.formatVersion; | 531 yield "version=" + this.formatVersion; | 
| 502 | 532 | 
| 503 let saved = new Set(); | 533 let saved = new Set(); | 
| 504 | 534 | 
| 505 // Save subscriptions | 535 // Save subscriptions | 
| 506 for (let subscription of subscriptions) | 536 for (let subscription of subscriptions) | 
| 507 { | 537 { | 
| 508 yield* subscription.serialize(); | 538 yield* subscription.serialize(); | 
| 509 yield* subscription.serializeFilters(); | 539 yield* subscription.serializeFilters(); | 
| 510 } | 540 } | 
| 511 | 541 | 
| 512 // Save filter data | 542 // Save filter data | 
| 513 for (let subscription of subscriptions) | 543 for (let subscription of subscriptions) | 
| 514 { | 544 { | 
| 515 for (let filter of subscription.filters) | 545 for (let filter of subscription.filters()) | 
| 516 { | 546 { | 
| 517 if (!saved.has(filter.text)) | 547 if (!saved.has(filter.text)) | 
| 518 { | 548 { | 
| 519 yield* filter.serialize(); | 549 yield* filter.serialize(); | 
| 520 saved.add(filter.text); | 550 saved.add(filter.text); | 
| 521 } | 551 } | 
| 522 } | 552 } | 
| 523 } | 553 } | 
| 524 } | 554 } | 
| 525 | 555 | 
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 652 | 682 | 
| 653 /** | 683 /** | 
| 654 * Reads the user's filters from disk, manages them in memory, and writes them | 684 * Reads the user's filters from disk, manages them in memory, and writes them | 
| 655 * back to disk. | 685 * back to disk. | 
| 656 */ | 686 */ | 
| 657 let filterStorage = new FilterStorage(); | 687 let filterStorage = new FilterStorage(); | 
| 658 | 688 | 
| 659 exports.filterStorage = filterStorage; | 689 exports.filterStorage = filterStorage; | 
| 660 | 690 | 
| 661 /** | 691 /** | 
| 692 * Adds to a filter any subscriptions in the storage to which the filter | |
| 693 * belongs. | |
| 694 * @param {Filter} filter | |
| 695 */ | |
| 696 function addSubscriptionsToFilter(filter) | |
| 697 { | |
| 698 for (let subscription of filterStorage.subscriptions()) | |
| 699 { | |
| 700 if (subscription.hasFilter(filter)) | |
| 701 filter.addSubscription(subscription); | |
| 702 } | |
| 703 | |
| 704 filter.subscriptionsAdded = true; | |
| 705 } | |
| 706 | |
| 707 /** | |
| 662 * Connects a subscription to its filters without any notifications. | 708 * Connects a subscription to its filters without any notifications. | 
| 663 * @param {Subscription} subscription The subscription that should be | 709 * @param {Subscription} subscription The subscription that should be | 
| 664 * connected to its filters. | 710 * connected to its filters. | 
| 665 */ | 711 * @param {?Array.<Filter>} [filters] A list of filters to which the | 
| 666 function connectSubscriptionFilters(subscription) | 712 * subscription should be connected. If this is not given, the subscription | 
| 713 * is connected to its own filters. | |
| 714 */ | |
| 715 function connectSubscriptionFilters(subscription, filters) | |
| 667 { | 716 { | 
| 668 if (!filterStorage.knownSubscriptions.has(subscription.url)) | 717 if (!filterStorage.knownSubscriptions.has(subscription.url)) | 
| 669 return; | 718 return; | 
| 670 | 719 | 
| 671 for (let filter of subscription.filters) | 720 for (let filter of filters || subscription.filters()) | 
| 672 filter.addSubscription(subscription); | 721 filter.addSubscription(subscription); | 
| 673 } | 722 } | 
| 674 | 723 | 
| 675 /** | 724 /** | 
| 676 * Disconnects a subscription from its filters without any notifications. | 725 * Disconnects a subscription from its filters without any notifications. | 
| 677 * @param {Subscription} subscription The subscription that should be | 726 * @param {Subscription} subscription The subscription that should be | 
| 678 * disconnected from its filters. | 727 * disconnected from its filters. | 
| 679 */ | 728 * @param {?Array.<Filter>} [filters] A list of filters from which the | 
| 680 function disconnectSubscriptionFilters(subscription) | 729 * subscription should be disconnected. If this is not given, the | 
| 730 * subscription is disconnected from its own filters. | |
| 731 */ | |
| 732 function disconnectSubscriptionFilters(subscription, filters) | |
| 681 { | 733 { | 
| 682 if (!filterStorage.knownSubscriptions.has(subscription.url)) | 734 if (!filterStorage.knownSubscriptions.has(subscription.url)) | 
| 683 return; | 735 return; | 
| 684 | 736 | 
| 685 for (let filter of subscription.filters) | 737 for (let filter of filters || subscription.filters()) | 
| 686 filter.removeSubscription(subscription); | 738 filter.removeSubscription(subscription); | 
| 687 } | 739 } | 
| 740 | |
| 741 /** | |
| 742 * Clears any in-memory caches held by subscriptions in the storage. | |
| 743 */ | |
| 744 function clearSubscriptionCaches() | |
| 745 { | |
| 746 for (let subscription of filterStorage.subscriptions()) | |
| 747 subscription.clearCaches(); | |
| 748 } | |
| LEFT | RIGHT |