Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: lib/filterStorage.js

Issue 29854572: Issue 6857 - Do not serialize empty special subscriptions (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Left Patch Set: Created Aug. 12, 2018, 10:28 a.m.
Right Patch Set: Use temporary Set object in unit test Created Oct. 3, 2018, 3:56 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | test/filterStorage_readwrite.js » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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
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"; 18 "use strict";
19 19
20 /** 20 /**
21 * @fileOverview FilterStorage class responsible for managing user's 21 * @fileOverview FilterStorage class responsible for managing user's
22 * subscriptions and filters. 22 * subscriptions and filters.
23 */ 23 */
24 24
25 const {IO} = require("io"); 25 const {IO} = require("io");
26 const {Prefs} = require("prefs"); 26 const {Prefs} = require("prefs");
27 const {Filter, ActiveFilter} = require("./filterClasses"); 27 const {Filter, ActiveFilter} = require("./filterClasses");
28 const {Subscription, SpecialSubscription, 28 const {Subscription, SpecialSubscription,
29 ExternalSubscription} = require("./subscriptionClasses"); 29 ExternalSubscription} = require("./subscriptionClasses");
30 const {FilterNotifier} = require("./filterNotifier"); 30 const {filterNotifier} = require("./filterNotifier");
31 const {INIParser} = require("./iniParser");
31 32
32 /** 33 /**
33 * Version number of the filter storage file format. 34 * Version number of the filter storage file format.
34 * @type {number} 35 * @type {number}
35 */ 36 */
36 let formatVersion = 5; 37 let formatVersion = 5;
37 38
38 /** 39 /**
39 * This class reads user's filters from disk, manages them in memory 40 * This class reads user's filters from disk, manages them in memory
40 * and writes them back. 41 * and writes them back.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 */ 73 */
73 firstRun: false, 74 firstRun: false,
74 75
75 /** 76 /**
76 * Map of properties listed in the filter storage file before the sections 77 * Map of properties listed in the filter storage file before the sections
77 * start. Right now this should be only the format version. 78 * start. Right now this should be only the format version.
78 */ 79 */
79 fileProperties: Object.create(null), 80 fileProperties: Object.create(null),
80 81
81 /** 82 /**
82 * List of filter subscriptions containing all filters 83 * Yields subscriptions containing all filters
83 * @type {Subscription[]} 84 * @yields {Subscription}
84 */ 85 */
85 subscriptions: [], 86 *subscriptions()
87 {
88 yield* this.knownSubscriptions.values();
89 },
90
91 /**
92 * Number of known subscriptions.
93 * @type {number}
94 */
95 get subscriptionCount()
96 {
97 return this.knownSubscriptions.size;
98 },
86 99
87 /** 100 /**
88 * Map of subscriptions already on the list, by their URL/identifier 101 * Map of subscriptions already on the list, by their URL/identifier
89 * @type {Map.<string,Subscription>} 102 * @type {Map.<string,Subscription>}
90 */ 103 */
91 knownSubscriptions: new Map(), 104 knownSubscriptions: new Map(),
92 105
93 /** 106 /**
94 * Finds the filter group that a filter should be added to by default. Will 107 * Finds the filter group that a filter should be added to by default. Will
95 * return null if this group doesn't exist yet. 108 * return null if this group doesn't exist yet.
96 * @param {Filter} filter 109 * @param {Filter} filter
97 * @return {?SpecialSubscription} 110 * @return {?SpecialSubscription}
98 */ 111 */
99 getGroupForFilter(filter) 112 getGroupForFilter(filter)
100 { 113 {
101 let generalSubscription = null; 114 let generalSubscription = null;
102 for (let subscription of FilterStorage.subscriptions) 115 for (let subscription of FilterStorage.knownSubscriptions.values())
103 { 116 {
104 if (subscription instanceof SpecialSubscription && !subscription.disabled) 117 if (subscription instanceof SpecialSubscription && !subscription.disabled)
105 { 118 {
106 // Always prefer specialized subscriptions 119 // Always prefer specialized subscriptions
107 if (subscription.isDefaultFor(filter)) 120 if (subscription.isDefaultFor(filter))
108 return subscription; 121 return subscription;
109 122
110 // If this is a general subscription - store it as fallback 123 // If this is a general subscription - store it as fallback
111 if (!generalSubscription && 124 if (!generalSubscription &&
112 (!subscription.defaults || !subscription.defaults.length)) 125 (!subscription.defaults || !subscription.defaults.length))
113 { 126 {
114 generalSubscription = subscription; 127 generalSubscription = subscription;
115 } 128 }
116 } 129 }
117 } 130 }
118 return generalSubscription; 131 return generalSubscription;
119 }, 132 },
120 133
121 /** 134 /**
122 * Adds a filter subscription to the list 135 * Adds a filter subscription to the list
123 * @param {Subscription} subscription filter subscription to be added 136 * @param {Subscription} subscription filter subscription to be added
124 */ 137 */
125 addSubscription(subscription) 138 addSubscription(subscription)
126 { 139 {
127 if (FilterStorage.knownSubscriptions.has(subscription.url)) 140 if (FilterStorage.knownSubscriptions.has(subscription.url))
128 return; 141 return;
129 142
130 FilterStorage.subscriptions.push(subscription);
131 FilterStorage.knownSubscriptions.set(subscription.url, subscription); 143 FilterStorage.knownSubscriptions.set(subscription.url, subscription);
132 addSubscriptionFilters(subscription); 144 addSubscriptionFilters(subscription);
133 145
134 FilterNotifier.triggerListeners("subscription.added", subscription); 146 filterNotifier.emit("subscription.added", subscription);
135 }, 147 },
136 148
137 /** 149 /**
138 * Removes a filter subscription from the list 150 * Removes a filter subscription from the list
139 * @param {Subscription} subscription filter subscription to be removed 151 * @param {Subscription} subscription filter subscription to be removed
140 */ 152 */
141 removeSubscription(subscription) 153 removeSubscription(subscription)
142 { 154 {
143 for (let i = 0; i < FilterStorage.subscriptions.length; i++) 155 if (!FilterStorage.knownSubscriptions.has(subscription.url))
144 {
145 if (FilterStorage.subscriptions[i].url == subscription.url)
146 {
147 removeSubscriptionFilters(subscription);
148
149 FilterStorage.subscriptions.splice(i--, 1);
150 FilterStorage.knownSubscriptions.delete(subscription.url);
151 FilterNotifier.triggerListeners("subscription.removed", subscription);
152 return;
153 }
154 }
155 },
156
157 /**
158 * Moves a subscription in the list to a new position.
159 * @param {Subscription} subscription filter subscription to be moved
160 * @param {Subscription} [insertBefore] filter subscription to insert before
161 * (if omitted the subscription will be put at the end of the list)
162 */
163 moveSubscription(subscription, insertBefore)
164 {
165 let currentPos = FilterStorage.subscriptions.indexOf(subscription);
166 if (currentPos < 0)
167 return; 156 return;
168 157
169 let newPos = -1; 158 removeSubscriptionFilters(subscription);
170 if (insertBefore) 159
171 newPos = FilterStorage.subscriptions.indexOf(insertBefore); 160 FilterStorage.knownSubscriptions.delete(subscription.url);
172 161
173 if (newPos < 0) 162 // This should be the last remaining reference to the Subscription
174 newPos = FilterStorage.subscriptions.length; 163 // object.
175 164 Subscription.knownSubscriptions.delete(subscription.url);
176 if (currentPos < newPos) 165
177 newPos--; 166 filterNotifier.emit("subscription.removed", subscription);
178 if (currentPos == newPos)
179 return;
180
181 FilterStorage.subscriptions.splice(currentPos, 1);
182 FilterStorage.subscriptions.splice(newPos, 0, subscription);
183 FilterNotifier.triggerListeners("subscription.moved", subscription);
184 }, 167 },
185 168
186 /** 169 /**
187 * Replaces the list of filters in a subscription by a new list 170 * Replaces the list of filters in a subscription by a new list
188 * @param {Subscription} subscription filter subscription to be updated 171 * @param {Subscription} subscription filter subscription to be updated
189 * @param {Filter[]} filters new filter list 172 * @param {Filter[]} filters new filter list
190 */ 173 */
191 updateSubscriptionFilters(subscription, filters) 174 updateSubscriptionFilters(subscription, filters)
192 { 175 {
193 removeSubscriptionFilters(subscription); 176 removeSubscriptionFilters(subscription);
194 subscription.oldFilters = subscription.filters; 177 let oldFilters = subscription.filters;
195 subscription.filters = filters; 178 subscription.filters = filters;
196 addSubscriptionFilters(subscription); 179 addSubscriptionFilters(subscription);
197 FilterNotifier.triggerListeners("subscription.updated", subscription); 180 filterNotifier.emit("subscription.updated", subscription, oldFilters);
198 delete subscription.oldFilters;
199 }, 181 },
200 182
201 /** 183 /**
202 * Adds a user-defined filter to the list 184 * Adds a user-defined filter to the list
203 * @param {Filter} filter 185 * @param {Filter} filter
204 * @param {SpecialSubscription} [subscription] 186 * @param {SpecialSubscription} [subscription]
205 * particular group that the filter should be added to 187 * particular group that the filter should be added to
206 * @param {number} [position] 188 * @param {number} [position]
207 * position within the subscription at which the filter should be added 189 * position within the subscription at which the filter should be added
208 */ 190 */
209 addFilter(filter, subscription, position) 191 addFilter(filter, subscription, position)
210 { 192 {
211 if (!subscription) 193 if (!subscription)
212 { 194 {
213 if (filter.subscriptions.some(s => s instanceof SpecialSubscription && 195 for (let currentSubscription of filter.subscriptions())
214 !s.disabled)) 196 {
215 { 197 if (currentSubscription instanceof SpecialSubscription &&
216 return; // No need to add 198 !currentSubscription.disabled)
199 {
200 return; // No need to add
201 }
217 } 202 }
218 subscription = FilterStorage.getGroupForFilter(filter); 203 subscription = FilterStorage.getGroupForFilter(filter);
219 } 204 }
220 if (!subscription) 205 if (!subscription)
221 { 206 {
222 // No group for this filter exists, create one 207 // No group for this filter exists, create one
223 subscription = SpecialSubscription.createForFilter(filter); 208 subscription = SpecialSubscription.createForFilter(filter);
224 this.addSubscription(subscription); 209 this.addSubscription(subscription);
225 return; 210 return;
226 } 211 }
227 212
228 if (typeof position == "undefined") 213 if (typeof position == "undefined")
229 position = subscription.filters.length; 214 position = subscription.filters.length;
230 215
231 if (filter.subscriptions.indexOf(subscription) < 0) 216 filter.addSubscription(subscription);
232 filter.subscriptions.push(subscription);
233 subscription.filters.splice(position, 0, filter); 217 subscription.filters.splice(position, 0, filter);
234 FilterNotifier.triggerListeners("filter.added", filter, subscription, 218 filterNotifier.emit("filter.added", filter, subscription, position);
235 position);
236 }, 219 },
237 220
238 /** 221 /**
239 * Removes a user-defined filter from the list 222 * Removes a user-defined filter from the list
240 * @param {Filter} filter 223 * @param {Filter} filter
241 * @param {SpecialSubscription} [subscription] a particular filter group that 224 * @param {SpecialSubscription} [subscription] a particular filter group that
242 * the filter should be removed from (if ommited will be removed from all 225 * the filter should be removed from (if ommited will be removed from all
243 * subscriptions) 226 * subscriptions)
244 * @param {number} [position] position inside the filter group at which the 227 * @param {number} [position] position inside the filter group at which the
245 * filter should be removed (if ommited all instances will be removed) 228 * filter should be removed (if ommited all instances will be removed)
246 */ 229 */
247 removeFilter(filter, subscription, position) 230 removeFilter(filter, subscription, position)
248 { 231 {
249 let subscriptions = ( 232 let subscriptions = (
250 subscription ? [subscription] : filter.subscriptions.slice() 233 subscription ? [subscription] : filter.subscriptions()
251 ); 234 );
252 for (let i = 0; i < subscriptions.length; i++) 235 for (let currentSubscription of subscriptions)
253 { 236 {
254 let currentSubscription = subscriptions[i];
255 if (currentSubscription instanceof SpecialSubscription) 237 if (currentSubscription instanceof SpecialSubscription)
256 { 238 {
257 let positions = []; 239 let positions = [];
258 if (typeof position == "undefined") 240 if (typeof position == "undefined")
259 { 241 {
260 let index = -1; 242 let index = -1;
261 do 243 do
262 { 244 {
263 index = currentSubscription.filters.indexOf(filter, index + 1); 245 index = currentSubscription.filters.indexOf(filter, index + 1);
264 if (index >= 0) 246 if (index >= 0)
265 positions.push(index); 247 positions.push(index);
266 } while (index >= 0); 248 } while (index >= 0);
267 } 249 }
268 else 250 else
269 positions.push(position); 251 positions.push(position);
270 252
271 for (let j = positions.length - 1; j >= 0; j--) 253 for (let j = positions.length - 1; j >= 0; j--)
272 { 254 {
273 let currentPosition = positions[j]; 255 let currentPosition = positions[j];
274 if (currentSubscription.filters[currentPosition] == filter) 256 if (currentSubscription.filters[currentPosition] == filter)
275 { 257 {
276 currentSubscription.filters.splice(currentPosition, 1); 258 currentSubscription.filters.splice(currentPosition, 1);
277 if (currentSubscription.filters.indexOf(filter) < 0) 259 if (currentSubscription.filters.indexOf(filter) < 0)
278 { 260 filter.removeSubscription(currentSubscription);
279 let index = filter.subscriptions.indexOf(currentSubscription); 261 filterNotifier.emit("filter.removed", filter, currentSubscription,
280 if (index >= 0) 262 currentPosition);
281 filter.subscriptions.splice(index, 1);
282 }
283 FilterNotifier.triggerListeners(
284 "filter.removed", filter, currentSubscription, currentPosition
285 );
286 } 263 }
287 } 264 }
288 } 265 }
289 } 266 }
290 }, 267 },
291 268
292 /** 269 /**
293 * Moves a user-defined filter to a new position 270 * Moves a user-defined filter to a new position
294 * @param {Filter} filter 271 * @param {Filter} filter
295 * @param {SpecialSubscription} subscription filter group where the filter is 272 * @param {SpecialSubscription} subscription filter group where the filter is
296 * located 273 * located
297 * @param {number} oldPosition current position of the filter 274 * @param {number} oldPosition current position of the filter
298 * @param {number} newPosition new position of the filter 275 * @param {number} newPosition new position of the filter
299 */ 276 */
300 moveFilter(filter, subscription, oldPosition, newPosition) 277 moveFilter(filter, subscription, oldPosition, newPosition)
301 { 278 {
302 if (!(subscription instanceof SpecialSubscription) || 279 if (!(subscription instanceof SpecialSubscription) ||
303 subscription.filters[oldPosition] != filter) 280 subscription.filters[oldPosition] != filter)
304 { 281 {
305 return; 282 return;
306 } 283 }
307 284
308 newPosition = Math.min(Math.max(newPosition, 0), 285 newPosition = Math.min(Math.max(newPosition, 0),
309 subscription.filters.length - 1); 286 subscription.filters.length - 1);
310 if (oldPosition == newPosition) 287 if (oldPosition == newPosition)
311 return; 288 return;
312 289
313 subscription.filters.splice(oldPosition, 1); 290 subscription.filters.splice(oldPosition, 1);
314 subscription.filters.splice(newPosition, 0, filter); 291 subscription.filters.splice(newPosition, 0, filter);
315 FilterNotifier.triggerListeners("filter.moved", filter, subscription, 292 filterNotifier.emit("filter.moved", filter, subscription, oldPosition,
316 oldPosition, newPosition); 293 newPosition);
317 }, 294 },
318 295
319 /** 296 /**
320 * Increases the hit count for a filter by one 297 * Increases the hit count for a filter by one
321 * @param {Filter} filter 298 * @param {Filter} filter
322 */ 299 */
323 increaseHitCount(filter) 300 increaseHitCount(filter)
324 { 301 {
325 if (!Prefs.savestats || !(filter instanceof ActiveFilter)) 302 if (!Prefs.savestats || !(filter instanceof ActiveFilter))
326 return; 303 return;
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
366 return line => 343 return line =>
367 { 344 {
368 parser.process(line); 345 parser.process(line);
369 if (line === null) 346 if (line === null)
370 { 347 {
371 let knownSubscriptions = new Map(); 348 let knownSubscriptions = new Map();
372 for (let subscription of parser.subscriptions) 349 for (let subscription of parser.subscriptions)
373 knownSubscriptions.set(subscription.url, subscription); 350 knownSubscriptions.set(subscription.url, subscription);
374 351
375 this.fileProperties = parser.fileProperties; 352 this.fileProperties = parser.fileProperties;
376 this.subscriptions = parser.subscriptions;
377 this.knownSubscriptions = knownSubscriptions; 353 this.knownSubscriptions = knownSubscriptions;
378 Filter.knownFilters = parser.knownFilters; 354 Filter.knownFilters = parser.knownFilters;
379 Subscription.knownSubscriptions = parser.knownSubscriptions; 355 Subscription.knownSubscriptions = parser.knownSubscriptions;
380 356
381 if (!silent) 357 if (!silent)
382 FilterNotifier.triggerListeners("load"); 358 filterNotifier.emit("load");
383 } 359 }
384 }; 360 };
385 }, 361 },
386 362
387 /** 363 /**
388 * Loads all subscriptions from the disk. 364 * Loads all subscriptions from the disk.
389 * @return {Promise} promise resolved or rejected when loading is complete 365 * @return {Promise} promise resolved or rejected when loading is complete
390 */ 366 */
391 loadFromDisk() 367 loadFromDisk()
392 { 368 {
393 let tryBackup = backupIndex => 369 let tryBackup = backupIndex =>
394 { 370 {
395 return this.restoreBackup(backupIndex, true).then(() => 371 return this.restoreBackup(backupIndex, true).then(() =>
396 { 372 {
397 if (this.subscriptions.length == 0) 373 if (this.knownSubscriptions.size == 0)
398 return tryBackup(backupIndex + 1); 374 return tryBackup(backupIndex + 1);
399 }).catch(error => 375 }).catch(error =>
400 { 376 {
401 // Give up 377 // Give up
402 }); 378 });
403 }; 379 };
404 380
405 return IO.statFile(this.sourceFile).then(statData => 381 return IO.statFile(this.sourceFile).then(statData =>
406 { 382 {
407 if (!statData.exists) 383 if (!statData.exists)
408 { 384 {
409 this.firstRun = true; 385 this.firstRun = true;
410 return; 386 return;
411 } 387 }
412 388
413 let parser = this.importData(true); 389 let parser = this.importData(true);
414 return IO.readFromFile(this.sourceFile, parser).then(() => 390 return IO.readFromFile(this.sourceFile, parser).then(() =>
415 { 391 {
416 parser(null); 392 parser(null);
417 if (this.subscriptions.length == 0) 393 if (this.knownSubscriptions.size == 0)
418 { 394 {
419 // No filter subscriptions in the file, this isn't right. 395 // No filter subscriptions in the file, this isn't right.
420 throw new Error("No data in the file"); 396 throw new Error("No data in the file");
421 } 397 }
422 }); 398 });
423 }).catch(error => 399 }).catch(error =>
424 { 400 {
425 Cu.reportError(error); 401 Cu.reportError(error);
426 return tryBackup(1); 402 return tryBackup(1);
427 }).then(() => 403 }).then(() =>
428 { 404 {
429 this.initialized = true; 405 this.initialized = true;
430 FilterNotifier.triggerListeners("load"); 406 filterNotifier.emit("load");
431 }); 407 });
432 }, 408 },
433 409
434 /** 410 /**
435 * Constructs the file name for a patterns.ini backup. 411 * Constructs the file name for a patterns.ini backup.
436 * @param {number} backupIndex 412 * @param {number} backupIndex
437 * number of the backup file (1 being the most recent) 413 * number of the backup file (1 being the most recent)
438 * @return {string} backup file name 414 * @return {string} backup file name
439 */ 415 */
440 getBackupName(backupIndex) 416 getBackupName(backupIndex)
(...skipping 20 matching lines...) Expand all
461 return this.saveToDisk(); 437 return this.saveToDisk();
462 }); 438 });
463 }, 439 },
464 440
465 /** 441 /**
466 * Generator serializing filter data and yielding it line by line. 442 * Generator serializing filter data and yielding it line by line.
467 */ 443 */
468 *exportData() 444 *exportData()
469 { 445 {
470 // Do not persist external subscriptions 446 // Do not persist external subscriptions
471 let subscriptions = this.subscriptions.filter( 447 let subscriptions = [];
472 s => !(s instanceof ExternalSubscription) && 448 for (let subscription of this.subscriptions())
473 !(s instanceof SpecialSubscription && s.filters.length == 0) 449 {
474 ); 450 if (!(subscription instanceof ExternalSubscription) &&
451 !(subscription instanceof SpecialSubscription &&
452 subscription.filters.length == 0))
453 {
454 subscriptions.push(subscription);
455 }
456 }
475 457
476 yield "# Adblock Plus preferences"; 458 yield "# Adblock Plus preferences";
477 yield "version=" + formatVersion; 459 yield "version=" + formatVersion;
478 460
479 let saved = new Set(); 461 let saved = new Set();
480 let buf = []; 462 let buf = [];
481 463
482 // Save subscriptions 464 // Save subscriptions
483 for (let subscription of subscriptions) 465 for (let subscription of subscriptions)
484 { 466 {
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
589 return renameBackup(Prefs.patternsbackups - 1); 571 return renameBackup(Prefs.patternsbackups - 1);
590 }).catch(error => 572 }).catch(error =>
591 { 573 {
592 // Errors during backup creation shouldn't prevent writing filters. 574 // Errors during backup creation shouldn't prevent writing filters.
593 Cu.reportError(error); 575 Cu.reportError(error);
594 }).then(() => 576 }).then(() =>
595 { 577 {
596 return IO.writeToFile(this.sourceFile, this.exportData()); 578 return IO.writeToFile(this.sourceFile, this.exportData());
597 }).then(() => 579 }).then(() =>
598 { 580 {
599 FilterNotifier.triggerListeners("save"); 581 filterNotifier.emit("save");
600 }).catch(error => 582 }).catch(error =>
601 { 583 {
602 // If saving failed, report error but continue - we still have to process 584 // If saving failed, report error but continue - we still have to process
603 // flags. 585 // flags.
604 Cu.reportError(error); 586 Cu.reportError(error);
605 }).then(() => 587 }).then(() =>
606 { 588 {
607 this._saving = false; 589 this._saving = false;
608 if (this._needsSave) 590 if (this._needsSave)
609 { 591 {
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
656 * Joins subscription's filters to the subscription without any notifications. 638 * Joins subscription's filters to the subscription without any notifications.
657 * @param {Subscription} subscription 639 * @param {Subscription} subscription
658 * filter subscription that should be connected to its filters 640 * filter subscription that should be connected to its filters
659 */ 641 */
660 function addSubscriptionFilters(subscription) 642 function addSubscriptionFilters(subscription)
661 { 643 {
662 if (!FilterStorage.knownSubscriptions.has(subscription.url)) 644 if (!FilterStorage.knownSubscriptions.has(subscription.url))
663 return; 645 return;
664 646
665 for (let filter of subscription.filters) 647 for (let filter of subscription.filters)
666 filter.subscriptions.push(subscription); 648 filter.addSubscription(subscription);
667 } 649 }
668 650
669 /** 651 /**
670 * Removes subscription's filters from the subscription without any 652 * Removes subscription's filters from the subscription without any
671 * notifications. 653 * notifications.
672 * @param {Subscription} subscription filter subscription to be removed 654 * @param {Subscription} subscription filter subscription to be removed
673 */ 655 */
674 function removeSubscriptionFilters(subscription) 656 function removeSubscriptionFilters(subscription)
675 { 657 {
676 if (!FilterStorage.knownSubscriptions.has(subscription.url)) 658 if (!FilterStorage.knownSubscriptions.has(subscription.url))
677 return; 659 return;
678 660
679 for (let filter of subscription.filters) 661 for (let filter of subscription.filters)
680 { 662 filter.removeSubscription(subscription);
681 let i = filter.subscriptions.indexOf(subscription);
682 if (i >= 0)
683 filter.subscriptions.splice(i, 1);
684 }
685 } 663 }
686
687 /**
688 * Listener returned by FilterStorage.importData(), parses filter data.
689 * @constructor
690 */
691 function INIParser()
692 {
693 this.fileProperties = this.curObj = {};
694 this.subscriptions = [];
695 this.knownFilters = new Map();
696 this.knownSubscriptions = new Map();
697 }
698 INIParser.prototype =
699 {
700 linesProcessed: 0,
701 subscriptions: null,
702 knownFilters: null,
703 knownSubscriptions: null,
704 wantObj: true,
705 fileProperties: null,
706 curObj: null,
707 curSection: null,
708
709 process(val)
710 {
711 let origKnownFilters = Filter.knownFilters;
712 Filter.knownFilters = this.knownFilters;
713 let origKnownSubscriptions = Subscription.knownSubscriptions;
714 Subscription.knownSubscriptions = this.knownSubscriptions;
715 let match;
716 try
717 {
718 if (this.wantObj === true && (match = /^(\w+)=(.*)$/.exec(val)))
719 this.curObj[match[1]] = match[2];
720 else if (val === null || (match = /^\s*\[(.+)\]\s*$/.exec(val)))
721 {
722 if (this.curObj)
723 {
724 // Process current object before going to next section
725 switch (this.curSection)
726 {
727 case "filter":
728 if ("text" in this.curObj)
729 Filter.fromObject(this.curObj);
730 break;
731 case "subscription": {
732 let subscription = Subscription.fromObject(this.curObj);
733 if (subscription)
734 this.subscriptions.push(subscription);
735 break;
736 }
737 case "subscription filters":
738 if (this.subscriptions.length)
739 {
740 let subscription = this.subscriptions[
741 this.subscriptions.length - 1
742 ];
743 for (let text of this.curObj)
744 {
745 let filter = Filter.fromText(text);
746 subscription.filters.push(filter);
747 filter.subscriptions.push(subscription);
748 }
749 }
750 break;
751 }
752 }
753
754 if (val === null)
755 return;
756
757 this.curSection = match[1].toLowerCase();
758 switch (this.curSection)
759 {
760 case "filter":
761 case "subscription":
762 this.wantObj = true;
763 this.curObj = {};
764 break;
765 case "subscription filters":
766 this.wantObj = false;
767 this.curObj = [];
768 break;
769 default:
770 this.wantObj = null;
771 this.curObj = null;
772 }
773 }
774 else if (this.wantObj === false && val)
775 this.curObj.push(val.replace(/\\\[/g, "["));
776 }
777 finally
778 {
779 Filter.knownFilters = origKnownFilters;
780 Subscription.knownSubscriptions = origKnownSubscriptions;
781 }
782 }
783 };
LEFTRIGHT

Powered by Google App Engine
This is Rietveld