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

Side by Side Diff: lib/notification.js

Issue 29375915: Issue 4878 - Start using ESLint for adblockpluscore (Closed)
Patch Set: Addressed Sebastian's initial feedback Created Feb. 21, 2017, 6:12 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
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 Handles notifications. 21 * @fileOverview Handles notifications.
20 */ 22 */
21 23
22 Cu.import("resource://gre/modules/Services.jsm"); 24 Cu.import("resource://gre/modules/Services.jsm");
23 25
24 var {Prefs} = require("prefs"); 26 let {Prefs} = require("prefs");
Sebastian Noack 2017/02/21 09:19:31 Didn't we just agree to use const for module impor
kzar 2017/02/21 10:37:01 Done.
25 var {Downloader, Downloadable, MILLIS_IN_MINUTE, MILLIS_IN_HOUR, MILLIS_IN_DAY} = require("downloader"); 27 let {Downloader, Downloadable,
26 var {Utils} = require("utils"); 28 MILLIS_IN_MINUTE, MILLIS_IN_HOUR, MILLIS_IN_DAY} = require("downloader");
27 var {Matcher, defaultMatcher} = require("matcher"); 29 let {Utils} = require("utils");
28 var {Filter, RegExpFilter, WhitelistFilter} = require("filterClasses"); 30 let {Matcher, defaultMatcher} = require("matcher");
31 let {Filter, RegExpFilter, WhitelistFilter} = require("filterClasses");
29 32
30 var INITIAL_DELAY = 1 * MILLIS_IN_MINUTE; 33 let INITIAL_DELAY = 1 * MILLIS_IN_MINUTE;
31 var CHECK_INTERVAL = 1 * MILLIS_IN_HOUR; 34 let CHECK_INTERVAL = 1 * MILLIS_IN_HOUR;
32 var EXPIRATION_INTERVAL = 1 * MILLIS_IN_DAY; 35 let EXPIRATION_INTERVAL = 1 * MILLIS_IN_DAY;
33 var TYPE = { 36 let TYPE = {
34 information: 0, 37 information: 0,
35 question: 1, 38 question: 1,
36 relentless: 2, 39 relentless: 2,
37 critical: 3 40 critical: 3
38 }; 41 };
39 42
40 var showListeners = []; 43 let showListeners = [];
41 var questionListeners = {}; 44 let questionListeners = {};
42 45
43 function getNumericalSeverity(notification) 46 function getNumericalSeverity(notification)
44 { 47 {
45 return (notification.type in TYPE ? TYPE[notification.type] : TYPE.information ); 48 if (notification.type in TYPE)
49 return TYPE[notification.type];
50 return TYPE.information;
46 } 51 }
47 52
48 function saveNotificationData() 53 function saveNotificationData()
49 { 54 {
50 // HACK: JSON values aren't saved unless they are assigned a different object. 55 // HACK: JSON values aren't saved unless they are assigned a different object.
51 Prefs.notificationdata = JSON.parse(JSON.stringify(Prefs.notificationdata)); 56 Prefs.notificationdata = JSON.parse(JSON.stringify(Prefs.notificationdata));
52 } 57 }
53 58
54 function localize(translations, locale) 59 function localize(translations, locale)
55 { 60 {
56 if (locale in translations) 61 if (locale in translations)
57 return translations[locale]; 62 return translations[locale];
58 63
59 let languagePart = locale.substring(0, locale.indexOf("-")); 64 let languagePart = locale.substring(0, locale.indexOf("-"));
60 if (languagePart && languagePart in translations) 65 if (languagePart && languagePart in translations)
61 return translations[languagePart]; 66 return translations[languagePart];
62 67
63 let defaultLocale = "en-US"; 68 let defaultLocale = "en-US";
64 return translations[defaultLocale]; 69 return translations[defaultLocale];
65 } 70 }
66 71
67 /** 72 /**
68 * The object providing actual downloading functionality. 73 * The object providing actual downloading functionality.
69 * @type Downloader 74 * @type {Downloader}
70 */ 75 */
71 var downloader = null; 76 let downloader = null;
72 var localData = []; 77 let localData = [];
73 78
74 /** 79 /**
75 * Regularly fetches notifications and decides which to show. 80 * Regularly fetches notifications and decides which to show.
76 * @class 81 * @class
77 */ 82 */
78 var Notification = exports.Notification = 83 let Notification = exports.Notification =
79 { 84 {
80 /** 85 /**
81 * Called on module startup. 86 * Called on module startup.
82 */ 87 */
83 init: function() 88 init()
84 { 89 {
85 downloader = new Downloader(this._getDownloadables.bind(this), INITIAL_DELAY , CHECK_INTERVAL); 90 downloader = new Downloader(this._getDownloadables.bind(this),
91 INITIAL_DELAY, CHECK_INTERVAL);
86 downloader.onExpirationChange = this._onExpirationChange.bind(this); 92 downloader.onExpirationChange = this._onExpirationChange.bind(this);
87 downloader.onDownloadSuccess = this._onDownloadSuccess.bind(this); 93 downloader.onDownloadSuccess = this._onDownloadSuccess.bind(this);
88 downloader.onDownloadError = this._onDownloadError.bind(this); 94 downloader.onDownloadError = this._onDownloadError.bind(this);
89 onShutdown.add(() => downloader.cancel()); 95 onShutdown.add(() => downloader.cancel());
90 }, 96 },
91 97
92 /** 98 /**
93 * Yields a Downloadable instances for the notifications download. 99 * Yields a Downloadable instances for the notifications download.
94 */ 100 */
95 _getDownloadables: function*() 101 *_getDownloadables()
96 { 102 {
97 let downloadable = new Downloadable(Prefs.notificationurl); 103 let downloadable = new Downloadable(Prefs.notificationurl);
98 if (typeof Prefs.notificationdata.lastError === "number") 104 if (typeof Prefs.notificationdata.lastError === "number")
99 downloadable.lastError = Prefs.notificationdata.lastError; 105 downloadable.lastError = Prefs.notificationdata.lastError;
100 if (typeof Prefs.notificationdata.lastCheck === "number") 106 if (typeof Prefs.notificationdata.lastCheck === "number")
101 downloadable.lastCheck = Prefs.notificationdata.lastCheck; 107 downloadable.lastCheck = Prefs.notificationdata.lastCheck;
102 if (typeof Prefs.notificationdata.data === "object" && "version" in Prefs.no tificationdata.data) 108 if (typeof Prefs.notificationdata.data === "object" &&
109 "version" in Prefs.notificationdata.data)
103 downloadable.lastVersion = Prefs.notificationdata.data.version; 110 downloadable.lastVersion = Prefs.notificationdata.data.version;
104 if (typeof Prefs.notificationdata.softExpiration === "number") 111 if (typeof Prefs.notificationdata.softExpiration === "number")
105 downloadable.softExpiration = Prefs.notificationdata.softExpiration; 112 downloadable.softExpiration = Prefs.notificationdata.softExpiration;
106 if (typeof Prefs.notificationdata.hardExpiration === "number") 113 if (typeof Prefs.notificationdata.hardExpiration === "number")
107 downloadable.hardExpiration = Prefs.notificationdata.hardExpiration; 114 downloadable.hardExpiration = Prefs.notificationdata.hardExpiration;
108 if (typeof Prefs.notificationdata.downloadCount === "number") 115 if (typeof Prefs.notificationdata.downloadCount === "number")
109 downloadable.downloadCount = Prefs.notificationdata.downloadCount; 116 downloadable.downloadCount = Prefs.notificationdata.downloadCount;
110 yield downloadable; 117 yield downloadable;
111 }, 118 },
112 119
113 _onExpirationChange: function(downloadable) 120 _onExpirationChange(downloadable)
114 { 121 {
115 Prefs.notificationdata.lastCheck = downloadable.lastCheck; 122 Prefs.notificationdata.lastCheck = downloadable.lastCheck;
116 Prefs.notificationdata.softExpiration = downloadable.softExpiration; 123 Prefs.notificationdata.softExpiration = downloadable.softExpiration;
117 Prefs.notificationdata.hardExpiration = downloadable.hardExpiration; 124 Prefs.notificationdata.hardExpiration = downloadable.hardExpiration;
118 saveNotificationData(); 125 saveNotificationData();
119 }, 126 },
120 127
121 _onDownloadSuccess: function(downloadable, responseText, errorCallback, redire ctCallback) 128 _onDownloadSuccess(downloadable, responseText, errorCallback,
129 redirectCallback)
122 { 130 {
123 try 131 try
124 { 132 {
125 let data = JSON.parse(responseText); 133 let data = JSON.parse(responseText);
126 for (let notification of data.notifications) 134 for (let notification of data.notifications)
127 { 135 {
128 if ("severity" in notification) 136 if ("severity" in notification)
129 { 137 {
130 if (!("type" in notification)) 138 if (!("type" in notification))
131 notification.type = notification.severity; 139 notification.type = notification.severity;
132 delete notification.severity; 140 delete notification.severity;
133 } 141 }
134 } 142 }
135 Prefs.notificationdata.data = data; 143 Prefs.notificationdata.data = data;
136 } 144 }
137 catch (e) 145 catch (e)
138 { 146 {
139 Cu.reportError(e); 147 Cu.reportError(e);
140 errorCallback("synchronize_invalid_data"); 148 errorCallback("synchronize_invalid_data");
141 return; 149 return;
142 } 150 }
143 151
144 Prefs.notificationdata.lastError = 0; 152 Prefs.notificationdata.lastError = 0;
145 Prefs.notificationdata.downloadStatus = "synchronize_ok"; 153 Prefs.notificationdata.downloadStatus = "synchronize_ok";
146 [Prefs.notificationdata.softExpiration, Prefs.notificationdata.hardExpiratio n] = downloader.processExpirationInterval(EXPIRATION_INTERVAL); 154 [Prefs.notificationdata.softExpiration,
155 Prefs.notificationdata.hardExpiration] =
156 downloader.processExpirationInterval(EXPIRATION_INTERVAL);
147 Prefs.notificationdata.downloadCount = downloadable.downloadCount; 157 Prefs.notificationdata.downloadCount = downloadable.downloadCount;
148 saveNotificationData(); 158 saveNotificationData();
149 159
150 Notification.showNext(); 160 Notification.showNext();
151 }, 161 },
152 162
153 _onDownloadError: function(downloadable, downloadURL, error, channelStatus, re sponseStatus, redirectCallback) 163 _onDownloadError(downloadable, downloadURL, error, channelStatus,
164 responseStatus, redirectCallback)
154 { 165 {
155 Prefs.notificationdata.lastError = Date.now(); 166 Prefs.notificationdata.lastError = Date.now();
156 Prefs.notificationdata.downloadStatus = error; 167 Prefs.notificationdata.downloadStatus = error;
157 saveNotificationData(); 168 saveNotificationData();
158 }, 169 },
159 170
160 /** 171 /**
161 * Adds a listener for notifications to be shown. 172 * Adds a listener for notifications to be shown.
162 * @param {Function} listener Listener to be invoked when a notification is 173 * @param {Function} listener Listener to be invoked when a notification is
163 * to be shown 174 * to be shown
164 */ 175 */
165 addShowListener: function(listener) 176 addShowListener(listener)
166 { 177 {
167 if (showListeners.indexOf(listener) == -1) 178 if (showListeners.indexOf(listener) == -1)
168 showListeners.push(listener); 179 showListeners.push(listener);
169 }, 180 },
170 181
171 /** 182 /**
172 * Removes the supplied listener. 183 * Removes the supplied listener.
173 * @param {Function} listener Listener that was added via addShowListener() 184 * @param {Function} listener Listener that was added via addShowListener()
174 */ 185 */
175 removeShowListener: function(listener) 186 removeShowListener(listener)
176 { 187 {
177 let index = showListeners.indexOf(listener); 188 let index = showListeners.indexOf(listener);
178 if (index != -1) 189 if (index != -1)
179 showListeners.splice(index, 1); 190 showListeners.splice(index, 1);
180 }, 191 },
181 192
182 /** 193 /**
183 * Determines which notification is to be shown next. 194 * Determines which notification is to be shown next.
184 * @param {String} url URL to match notifications to (optional) 195 * @param {string} url URL to match notifications to (optional)
185 * @return {Object} notification to be shown, or null if there is none 196 * @return {Object} notification to be shown, or null if there is none
186 */ 197 */
187 _getNextToShow: function(url) 198 _getNextToShow(url)
188 { 199 {
189 function checkTarget(target, parameter, name, version) 200 function checkTarget(target, parameter, name, version)
190 { 201 {
191 let minVersionKey = parameter + "MinVersion"; 202 let minVersionKey = parameter + "MinVersion";
192 let maxVersionKey = parameter + "MaxVersion"; 203 let maxVersionKey = parameter + "MaxVersion";
193 return !((parameter in target && target[parameter] != name) || 204 return !((parameter in target && target[parameter] != name) ||
194 (minVersionKey in target && Services.vc.compare(version, target[m inVersionKey]) < 0) || 205 (minVersionKey in target &&
195 (maxVersionKey in target && Services.vc.compare(version, target[m axVersionKey]) > 0)); 206 Services.vc.compare(version, target[minVersionKey]) < 0) ||
207 (maxVersionKey in target &&
208 Services.vc.compare(version, target[maxVersionKey]) > 0));
196 } 209 }
197 210
198 let remoteData = []; 211 let remoteData = [];
199 if (typeof Prefs.notificationdata.data == "object" && Prefs.notificationdata .data.notifications instanceof Array) 212 if (typeof Prefs.notificationdata.data == "object" &&
213 Prefs.notificationdata.data.notifications instanceof Array)
200 remoteData = Prefs.notificationdata.data.notifications; 214 remoteData = Prefs.notificationdata.data.notifications;
201 215
202 let notifications = localData.concat(remoteData); 216 let notifications = localData.concat(remoteData);
203 if (notifications.length === 0) 217 if (notifications.length === 0)
204 return null; 218 return null;
205 219
206 let {addonName, addonVersion, application, applicationVersion, platform, pla tformVersion} = require("info"); 220 let {addonName, addonVersion, application,
221 applicationVersion, platform, platformVersion} = require("info");
207 let notificationToShow = null; 222 let notificationToShow = null;
208 for (let notification of notifications) 223 for (let notification of notifications)
209 { 224 {
210 if (typeof notification.type === "undefined" || notification.type !== "cri tical") 225 if (typeof notification.type === "undefined" ||
226 notification.type !== "critical")
211 { 227 {
212 let shown; 228 let shown;
213 if (typeof Prefs.notificationdata.shown == "object") 229 if (typeof Prefs.notificationdata.shown == "object")
214 shown = Prefs.notificationdata.shown[notification.id]; 230 shown = Prefs.notificationdata.shown[notification.id];
215 231
216 if (typeof shown != "undefined") 232 if (typeof shown != "undefined")
217 { 233 {
218 if (typeof notification.interval == "number") 234 if (typeof notification.interval == "number")
219 { 235 {
220 if (shown + notification.interval > Date.now()) 236 if (shown + notification.interval > Date.now())
221 continue; 237 continue;
222 } 238 }
223 else if (shown) 239 else if (shown)
224 continue; 240 continue;
225 } 241 }
226 242
227 if (notification.type !== "relentless" && Prefs.notifications_ignoredcat egories.indexOf("*") != -1) 243 if (notification.type !== "relentless" &&
244 Prefs.notifications_ignoredcategories.indexOf("*") != -1)
228 continue; 245 continue;
229 } 246 }
230 247
231 if (typeof url === "string" || notification.urlFilters instanceof Array) 248 if (typeof url === "string" || notification.urlFilters instanceof Array)
232 { 249 {
233 if (Prefs.enabled && typeof url === "string" && notification.urlFilters instanceof Array) 250 if (Prefs.enabled && typeof url === "string" &&
251 notification.urlFilters instanceof Array)
234 { 252 {
235 let host; 253 let host;
236 try 254 try
237 { 255 {
238 host = new URL(url).hostname; 256 host = new URL(url).hostname;
239 } 257 }
240 catch (e) 258 catch (e)
241 { 259 {
242 host = ""; 260 host = "";
243 } 261 }
244 262
245 let exception = defaultMatcher.matchesAny(url, RegExpFilter.typeMap.DO CUMENT, host, false, null); 263 let exception = defaultMatcher.matchesAny(
264 url, RegExpFilter.typeMap.DOCUMENT, host, false, null
265 );
246 if (exception instanceof WhitelistFilter) 266 if (exception instanceof WhitelistFilter)
247 continue; 267 continue;
248 268
249 let matcher = new Matcher(); 269 let matcher = new Matcher();
250 for (let urlFilter of notification.urlFilters) 270 for (let urlFilter of notification.urlFilters)
251 matcher.add(Filter.fromText(urlFilter)); 271 matcher.add(Filter.fromText(urlFilter));
252 if (!matcher.matchesAny(url, RegExpFilter.typeMap.DOCUMENT, host, fals e, null)) 272 if (!matcher.matchesAny(url, RegExpFilter.typeMap.DOCUMENT, host,
273 false, null))
253 continue; 274 continue;
254 } 275 }
255 else 276 else
256 continue; 277 continue;
257 } 278 }
258 279
259 if (notification.targets instanceof Array) 280 if (notification.targets instanceof Array)
260 { 281 {
261 let match = false; 282 let match = false;
262 for (let target of notification.targets) 283 for (let target of notification.targets)
263 { 284 {
264 if (checkTarget(target, "extension", addonName, addonVersion) && 285 if (checkTarget(target, "extension", addonName, addonVersion) &&
265 checkTarget(target, "application", application, applicationVersion ) && 286 checkTarget(target, "application", application,
287 applicationVersion) &&
266 checkTarget(target, "platform", platform, platformVersion)) 288 checkTarget(target, "platform", platform, platformVersion))
267 { 289 {
268 match = true; 290 match = true;
269 break; 291 break;
270 } 292 }
271 } 293 }
272 if (!match) 294 if (!match)
273 continue; 295 continue;
274 } 296 }
275 297
276 if (!notificationToShow 298 if (!notificationToShow ||
277 || getNumericalSeverity(notification) > getNumericalSeverity(notificat ionToShow)) 299 getNumericalSeverity(notification) >
300 getNumericalSeverity(notificationToShow))
278 notificationToShow = notification; 301 notificationToShow = notification;
279 } 302 }
280 303
281 return notificationToShow; 304 return notificationToShow;
282 }, 305 },
283 306
284 /** 307 /**
285 * Invokes the listeners added via addShowListener() with the next 308 * Invokes the listeners added via addShowListener() with the next
286 * notification to be shown. 309 * notification to be shown.
287 * @param {String} url URL to match notifications to (optional) 310 * @param {string} url URL to match notifications to (optional)
288 */ 311 */
289 showNext: function(url) 312 showNext(url)
290 { 313 {
291 let notification = Notification._getNextToShow(url); 314 let notification = Notification._getNextToShow(url);
292 if (notification) 315 if (notification)
316 {
293 for (let showListener of showListeners) 317 for (let showListener of showListeners)
294 showListener(notification); 318 showListener(notification);
319 }
295 }, 320 },
296 321
297 /** 322 /**
298 * Marks a notification as shown. 323 * Marks a notification as shown.
299 * @param {String} id ID of the notification to be marked as shown 324 * @param {string} id ID of the notification to be marked as shown
300 */ 325 */
301 markAsShown: function(id) 326 markAsShown(id)
302 { 327 {
303 let now = Date.now(); 328 let now = Date.now();
304 let data = Prefs.notificationdata; 329 let data = Prefs.notificationdata;
305 330
306 if (data.shown instanceof Array) 331 if (data.shown instanceof Array)
307 { 332 {
308 let newShown = {}; 333 let newShown = {};
309 for (let oldId of data.shown) 334 for (let oldId of data.shown)
310 newShown[oldId] = now; 335 newShown[oldId] = now;
311 data.shown = newShown; 336 data.shown = newShown;
312 } 337 }
313 338
314 if (typeof data.shown != "object") 339 if (typeof data.shown != "object")
315 data.shown = {}; 340 data.shown = {};
316 341
317 data.shown[id] = now; 342 data.shown[id] = now;
318 343
319 saveNotificationData(); 344 saveNotificationData();
320 }, 345 },
321 346
322 /** 347 /**
323 * Localizes the texts of the supplied notification. 348 * Localizes the texts of the supplied notification.
324 * @param {Object} notification notification to translate 349 * @param {Object} notification notification to translate
325 * @param {String} locale the target locale (optional, defaults to the 350 * @param {string} locale the target locale (optional, defaults to the
326 * application locale) 351 * application locale)
327 * @return {Object} the translated texts 352 * @return {Object} the translated texts
328 */ 353 */
329 getLocalizedTexts: function(notification, locale) 354 getLocalizedTexts(notification, locale)
330 { 355 {
331 locale = locale || Utils.appLocale; 356 locale = locale || Utils.appLocale;
332 let textKeys = ["title", "message"]; 357 let textKeys = ["title", "message"];
333 let localizedTexts = []; 358 let localizedTexts = [];
334 for (let key of textKeys) 359 for (let key of textKeys)
335 { 360 {
336 if (key in notification) 361 if (key in notification)
337 { 362 {
338 if (typeof notification[key] == "string") 363 if (typeof notification[key] == "string")
339 localizedTexts[key] = notification[key]; 364 localizedTexts[key] = notification[key];
340 else 365 else
341 localizedTexts[key] = localize(notification[key], locale); 366 localizedTexts[key] = localize(notification[key], locale);
342 } 367 }
343 } 368 }
344 return localizedTexts; 369 return localizedTexts;
345 }, 370 },
346 371
347 /** 372 /**
348 * Adds a local notification. 373 * Adds a local notification.
349 * @param {Object} notification notification to add 374 * @param {Object} notification notification to add
350 */ 375 */
351 addNotification: function(notification) 376 addNotification(notification)
352 { 377 {
353 if (localData.indexOf(notification) == -1) 378 if (localData.indexOf(notification) == -1)
354 localData.push(notification); 379 localData.push(notification);
355 }, 380 },
356 381
357 /** 382 /**
358 * Removes an existing local notification. 383 * Removes an existing local notification.
359 * @param {Object} notification notification to remove 384 * @param {Object} notification notification to remove
360 */ 385 */
361 removeNotification: function(notification) 386 removeNotification(notification)
362 { 387 {
363 let index = localData.indexOf(notification); 388 let index = localData.indexOf(notification);
364 if (index > -1) 389 if (index > -1)
365 localData.splice(index, 1); 390 localData.splice(index, 1);
366 }, 391 },
367 392
368 /** 393 /**
394 * A callback function which listens to see if notifications were approved.
395 *
396 * @callback approvedListener
397 * @param {boolean} approved
398 */
399
400 /**
369 * Adds a listener for question-type notifications 401 * Adds a listener for question-type notifications
402 * @param {string} id
403 * @param {approvedListener} listener
370 */ 404 */
371 addQuestionListener: function(/**string*/ id, /**function(approved)*/ listener ) 405 addQuestionListener(id, listener)
372 { 406 {
373 if (!(id in questionListeners)) 407 if (!(id in questionListeners))
374 questionListeners[id] = []; 408 questionListeners[id] = [];
375 if (questionListeners[id].indexOf(listener) === -1) 409 if (questionListeners[id].indexOf(listener) === -1)
376 questionListeners[id].push(listener); 410 questionListeners[id].push(listener);
377 }, 411 },
378 412
379 /** 413 /**
380 * Removes a listener that was previously added via addQuestionListener 414 * Removes a listener that was previously added via addQuestionListener
415 * @param {string} id
416 * @param {approvedListener} listener
381 */ 417 */
382 removeQuestionListener: function(/**string*/ id, /**function(approved)*/ liste ner) 418 removeQuestionListener(id, listener)
383 { 419 {
384 if (!(id in questionListeners)) 420 if (!(id in questionListeners))
385 return; 421 return;
386 let index = questionListeners[id].indexOf(listener); 422 let index = questionListeners[id].indexOf(listener);
387 if (index > -1) 423 if (index > -1)
388 questionListeners[id].splice(index, 1); 424 questionListeners[id].splice(index, 1);
389 if (questionListeners[id].length === 0) 425 if (questionListeners[id].length === 0)
390 delete questionListeners[id]; 426 delete questionListeners[id];
391 }, 427 },
392 428
393 /** 429 /**
394 * Notifies question listeners about interactions with a notification 430 * Notifies question listeners about interactions with a notification
395 * @param {String} id notification ID 431 * @param {string} id notification ID
396 * @param {Boolean} approved indicator whether notification has been approved or not 432 * @param {boolean} approved indicator whether notification has been approved
397 */ 433 */
398 triggerQuestionListeners: function(id, approved) 434 triggerQuestionListeners(id, approved)
399 { 435 {
400 if (!(id in questionListeners)) 436 if (!(id in questionListeners))
401 return; 437 return;
402 let listeners = questionListeners[id]; 438 let listeners = questionListeners[id];
403 for (let listener of listeners) 439 for (let listener of listeners)
404 listener(approved); 440 listener(approved);
405 }, 441 },
406 442
407 /** 443 /**
408 * Toggles whether notifications of a specific category should be ignored 444 * Toggles whether notifications of a specific category should be ignored
409 * @param {String} category notification category identifier 445 * @param {string} category notification category identifier
410 * @param {Boolean} [forceValue] force specified value 446 * @param {boolean} [forceValue] force specified value
411 */ 447 */
412 toggleIgnoreCategory: function(category, forceValue) 448 toggleIgnoreCategory(category, forceValue)
413 { 449 {
414 let categories = Prefs.notifications_ignoredcategories; 450 let categories = Prefs.notifications_ignoredcategories;
415 let index = categories.indexOf(category); 451 let index = categories.indexOf(category);
416 if (index == -1 && forceValue !== false) 452 if (index == -1 && forceValue !== false)
417 { 453 {
418 categories.push(category); 454 categories.push(category);
419 Prefs.notifications_showui = true; 455 Prefs.notifications_showui = true;
420 } 456 }
421 else if (index != -1 && forceValue !== true) 457 else if (index != -1 && forceValue !== true)
422 categories.splice(index, 1); 458 categories.splice(index, 1);
423 459
424 // HACK: JSON values aren't saved unless they are assigned a different objec t. 460 // HACK: JSON values aren't saved unless they are assigned a
425 Prefs.notifications_ignoredcategories = JSON.parse(JSON.stringify(categories )); 461 // different object.
462 Prefs.notifications_ignoredcategories =
463 JSON.parse(JSON.stringify(categories));
426 } 464 }
427 }; 465 };
428 Notification.init(); 466 Notification.init();
OLDNEW

Powered by Google App Engine
This is Rietveld