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: Remove the arrow-parens rule Created March 9, 2017, 10:23 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 const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
23 25
24 var {Prefs} = require("prefs"); 26 const {Prefs} = require("prefs");
25 var {Downloader, Downloadable, MILLIS_IN_MINUTE, MILLIS_IN_HOUR, MILLIS_IN_DAY} = require("downloader"); 27 const {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 const {Utils} = require("utils");
28 var {Filter, RegExpFilter, WhitelistFilter} = require("filterClasses"); 30 const {Matcher, defaultMatcher} = require("matcher");
31 const {Filter, RegExpFilter, WhitelistFilter} = require("filterClasses");
29 32
30 var INITIAL_DELAY = 1 * MILLIS_IN_MINUTE; 33 const INITIAL_DELAY = 1 * MILLIS_IN_MINUTE;
31 var CHECK_INTERVAL = 1 * MILLIS_IN_HOUR; 34 const CHECK_INTERVAL = 1 * MILLIS_IN_HOUR;
32 var EXPIRATION_INTERVAL = 1 * MILLIS_IN_DAY; 35 const EXPIRATION_INTERVAL = 1 * MILLIS_IN_DAY;
33 var TYPE = { 36 const 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)
110 {
103 downloadable.lastVersion = Prefs.notificationdata.data.version; 111 downloadable.lastVersion = Prefs.notificationdata.data.version;
112 }
104 if (typeof Prefs.notificationdata.softExpiration === "number") 113 if (typeof Prefs.notificationdata.softExpiration === "number")
105 downloadable.softExpiration = Prefs.notificationdata.softExpiration; 114 downloadable.softExpiration = Prefs.notificationdata.softExpiration;
106 if (typeof Prefs.notificationdata.hardExpiration === "number") 115 if (typeof Prefs.notificationdata.hardExpiration === "number")
107 downloadable.hardExpiration = Prefs.notificationdata.hardExpiration; 116 downloadable.hardExpiration = Prefs.notificationdata.hardExpiration;
108 if (typeof Prefs.notificationdata.downloadCount === "number") 117 if (typeof Prefs.notificationdata.downloadCount === "number")
109 downloadable.downloadCount = Prefs.notificationdata.downloadCount; 118 downloadable.downloadCount = Prefs.notificationdata.downloadCount;
110 yield downloadable; 119 yield downloadable;
111 }, 120 },
112 121
113 _onExpirationChange: function(downloadable) 122 _onExpirationChange(downloadable)
114 { 123 {
115 Prefs.notificationdata.lastCheck = downloadable.lastCheck; 124 Prefs.notificationdata.lastCheck = downloadable.lastCheck;
116 Prefs.notificationdata.softExpiration = downloadable.softExpiration; 125 Prefs.notificationdata.softExpiration = downloadable.softExpiration;
117 Prefs.notificationdata.hardExpiration = downloadable.hardExpiration; 126 Prefs.notificationdata.hardExpiration = downloadable.hardExpiration;
118 saveNotificationData(); 127 saveNotificationData();
119 }, 128 },
120 129
121 _onDownloadSuccess: function(downloadable, responseText, errorCallback, redire ctCallback) 130 _onDownloadSuccess(downloadable, responseText, errorCallback,
131 redirectCallback)
122 { 132 {
123 try 133 try
124 { 134 {
125 let data = JSON.parse(responseText); 135 let data = JSON.parse(responseText);
126 for (let notification of data.notifications) 136 for (let notification of data.notifications)
127 { 137 {
128 if ("severity" in notification) 138 if ("severity" in notification)
129 { 139 {
130 if (!("type" in notification)) 140 if (!("type" in notification))
131 notification.type = notification.severity; 141 notification.type = notification.severity;
132 delete notification.severity; 142 delete notification.severity;
133 } 143 }
134 } 144 }
135 Prefs.notificationdata.data = data; 145 Prefs.notificationdata.data = data;
136 } 146 }
137 catch (e) 147 catch (e)
138 { 148 {
139 Cu.reportError(e); 149 Cu.reportError(e);
140 errorCallback("synchronize_invalid_data"); 150 errorCallback("synchronize_invalid_data");
141 return; 151 return;
142 } 152 }
143 153
144 Prefs.notificationdata.lastError = 0; 154 Prefs.notificationdata.lastError = 0;
145 Prefs.notificationdata.downloadStatus = "synchronize_ok"; 155 Prefs.notificationdata.downloadStatus = "synchronize_ok";
146 [Prefs.notificationdata.softExpiration, Prefs.notificationdata.hardExpiratio n] = downloader.processExpirationInterval(EXPIRATION_INTERVAL); 156 [
157 Prefs.notificationdata.softExpiration,
158 Prefs.notificationdata.hardExpiration
159 ] = downloader.processExpirationInterval(EXPIRATION_INTERVAL);
147 Prefs.notificationdata.downloadCount = downloadable.downloadCount; 160 Prefs.notificationdata.downloadCount = downloadable.downloadCount;
148 saveNotificationData(); 161 saveNotificationData();
149 162
150 Notification.showNext(); 163 Notification.showNext();
151 }, 164 },
152 165
153 _onDownloadError: function(downloadable, downloadURL, error, channelStatus, re sponseStatus, redirectCallback) 166 _onDownloadError(downloadable, downloadURL, error, channelStatus,
167 responseStatus, redirectCallback)
154 { 168 {
155 Prefs.notificationdata.lastError = Date.now(); 169 Prefs.notificationdata.lastError = Date.now();
156 Prefs.notificationdata.downloadStatus = error; 170 Prefs.notificationdata.downloadStatus = error;
157 saveNotificationData(); 171 saveNotificationData();
158 }, 172 },
159 173
160 /** 174 /**
161 * Adds a listener for notifications to be shown. 175 * Adds a listener for notifications to be shown.
162 * @param {Function} listener Listener to be invoked when a notification is 176 * @param {Function} listener Listener to be invoked when a notification is
163 * to be shown 177 * to be shown
164 */ 178 */
165 addShowListener: function(listener) 179 addShowListener(listener)
166 { 180 {
167 if (showListeners.indexOf(listener) == -1) 181 if (showListeners.indexOf(listener) == -1)
168 showListeners.push(listener); 182 showListeners.push(listener);
169 }, 183 },
170 184
171 /** 185 /**
172 * Removes the supplied listener. 186 * Removes the supplied listener.
173 * @param {Function} listener Listener that was added via addShowListener() 187 * @param {Function} listener Listener that was added via addShowListener()
174 */ 188 */
175 removeShowListener: function(listener) 189 removeShowListener(listener)
176 { 190 {
177 let index = showListeners.indexOf(listener); 191 let index = showListeners.indexOf(listener);
178 if (index != -1) 192 if (index != -1)
179 showListeners.splice(index, 1); 193 showListeners.splice(index, 1);
180 }, 194 },
181 195
182 /** 196 /**
183 * Determines which notification is to be shown next. 197 * Determines which notification is to be shown next.
184 * @param {String} url URL to match notifications to (optional) 198 * @param {string} url URL to match notifications to (optional)
185 * @return {Object} notification to be shown, or null if there is none 199 * @return {Object} notification to be shown, or null if there is none
186 */ 200 */
187 _getNextToShow: function(url) 201 _getNextToShow(url)
188 { 202 {
189 function checkTarget(target, parameter, name, version) 203 function checkTarget(target, parameter, name, version)
190 { 204 {
191 let minVersionKey = parameter + "MinVersion"; 205 let minVersionKey = parameter + "MinVersion";
192 let maxVersionKey = parameter + "MaxVersion"; 206 let maxVersionKey = parameter + "MaxVersion";
193 return !((parameter in target && target[parameter] != name) || 207 return !((parameter in target && target[parameter] != name) ||
194 (minVersionKey in target && Services.vc.compare(version, target[m inVersionKey]) < 0) || 208 (minVersionKey in target &&
195 (maxVersionKey in target && Services.vc.compare(version, target[m axVersionKey]) > 0)); 209 Services.vc.compare(version, target[minVersionKey]) < 0) ||
210 (maxVersionKey in target &&
211 Services.vc.compare(version, target[maxVersionKey]) > 0));
196 } 212 }
197 213
198 let remoteData = []; 214 let remoteData = [];
199 if (typeof Prefs.notificationdata.data == "object" && Prefs.notificationdata .data.notifications instanceof Array) 215 if (typeof Prefs.notificationdata.data == "object" &&
216 Prefs.notificationdata.data.notifications instanceof Array)
217 {
200 remoteData = Prefs.notificationdata.data.notifications; 218 remoteData = Prefs.notificationdata.data.notifications;
219 }
201 220
202 let notifications = localData.concat(remoteData); 221 let notifications = localData.concat(remoteData);
203 if (notifications.length === 0) 222 if (notifications.length === 0)
204 return null; 223 return null;
205 224
206 let {addonName, addonVersion, application, applicationVersion, platform, pla tformVersion} = require("info"); 225 const {addonName, addonVersion, application,
226 applicationVersion, platform, platformVersion} = require("info");
207 let notificationToShow = null; 227 let notificationToShow = null;
208 for (let notification of notifications) 228 for (let notification of notifications)
209 { 229 {
210 if (typeof notification.type === "undefined" || notification.type !== "cri tical") 230 if (typeof notification.type === "undefined" ||
231 notification.type !== "critical")
211 { 232 {
212 let shown; 233 let shown;
213 if (typeof Prefs.notificationdata.shown == "object") 234 if (typeof Prefs.notificationdata.shown == "object")
214 shown = Prefs.notificationdata.shown[notification.id]; 235 shown = Prefs.notificationdata.shown[notification.id];
215 236
216 if (typeof shown != "undefined") 237 if (typeof shown != "undefined")
217 { 238 {
218 if (typeof notification.interval == "number") 239 if (typeof notification.interval == "number")
219 { 240 {
220 if (shown + notification.interval > Date.now()) 241 if (shown + notification.interval > Date.now())
221 continue; 242 continue;
222 } 243 }
223 else if (shown) 244 else if (shown)
224 continue; 245 continue;
225 } 246 }
226 247
227 if (notification.type !== "relentless" && Prefs.notifications_ignoredcat egories.indexOf("*") != -1) 248 if (notification.type !== "relentless" &&
249 Prefs.notifications_ignoredcategories.indexOf("*") != -1)
250 {
228 continue; 251 continue;
252 }
229 } 253 }
230 254
231 if (typeof url === "string" || notification.urlFilters instanceof Array) 255 if (typeof url === "string" || notification.urlFilters instanceof Array)
232 { 256 {
233 if (Prefs.enabled && typeof url === "string" && notification.urlFilters instanceof Array) 257 if (Prefs.enabled && typeof url === "string" &&
258 notification.urlFilters instanceof Array)
234 { 259 {
235 let host; 260 let host;
236 try 261 try
237 { 262 {
238 host = new URL(url).hostname; 263 host = new URL(url).hostname;
239 } 264 }
240 catch (e) 265 catch (e)
241 { 266 {
242 host = ""; 267 host = "";
243 } 268 }
244 269
245 let exception = defaultMatcher.matchesAny(url, RegExpFilter.typeMap.DO CUMENT, host, false, null); 270 let exception = defaultMatcher.matchesAny(
271 url, RegExpFilter.typeMap.DOCUMENT, host, false, null
272 );
246 if (exception instanceof WhitelistFilter) 273 if (exception instanceof WhitelistFilter)
247 continue; 274 continue;
248 275
249 let matcher = new Matcher(); 276 let matcher = new Matcher();
250 for (let urlFilter of notification.urlFilters) 277 for (let urlFilter of notification.urlFilters)
251 matcher.add(Filter.fromText(urlFilter)); 278 matcher.add(Filter.fromText(urlFilter));
252 if (!matcher.matchesAny(url, RegExpFilter.typeMap.DOCUMENT, host, fals e, null)) 279 if (!matcher.matchesAny(url, RegExpFilter.typeMap.DOCUMENT, host,
280 false, null))
281 {
253 continue; 282 continue;
283 }
254 } 284 }
255 else 285 else
256 continue; 286 continue;
257 } 287 }
258 288
259 if (notification.targets instanceof Array) 289 if (notification.targets instanceof Array)
260 { 290 {
261 let match = false; 291 let match = false;
262 for (let target of notification.targets) 292 for (let target of notification.targets)
263 { 293 {
264 if (checkTarget(target, "extension", addonName, addonVersion) && 294 if (checkTarget(target, "extension", addonName, addonVersion) &&
265 checkTarget(target, "application", application, applicationVersion ) && 295 checkTarget(target, "application", application,
296 applicationVersion) &&
266 checkTarget(target, "platform", platform, platformVersion)) 297 checkTarget(target, "platform", platform, platformVersion))
267 { 298 {
268 match = true; 299 match = true;
269 break; 300 break;
270 } 301 }
271 } 302 }
272 if (!match) 303 if (!match)
273 continue; 304 continue;
274 } 305 }
275 306
276 if (!notificationToShow 307 if (!notificationToShow ||
277 || getNumericalSeverity(notification) > getNumericalSeverity(notificat ionToShow)) 308 getNumericalSeverity(notification) >
309 getNumericalSeverity(notificationToShow))
278 notificationToShow = notification; 310 notificationToShow = notification;
279 } 311 }
280 312
281 return notificationToShow; 313 return notificationToShow;
282 }, 314 },
283 315
284 /** 316 /**
285 * Invokes the listeners added via addShowListener() with the next 317 * Invokes the listeners added via addShowListener() with the next
286 * notification to be shown. 318 * notification to be shown.
287 * @param {String} url URL to match notifications to (optional) 319 * @param {string} url URL to match notifications to (optional)
288 */ 320 */
289 showNext: function(url) 321 showNext(url)
290 { 322 {
291 let notification = Notification._getNextToShow(url); 323 let notification = Notification._getNextToShow(url);
292 if (notification) 324 if (notification)
325 {
293 for (let showListener of showListeners) 326 for (let showListener of showListeners)
294 showListener(notification); 327 showListener(notification);
328 }
295 }, 329 },
296 330
297 /** 331 /**
298 * Marks a notification as shown. 332 * Marks a notification as shown.
299 * @param {String} id ID of the notification to be marked as shown 333 * @param {string} id ID of the notification to be marked as shown
300 */ 334 */
301 markAsShown: function(id) 335 markAsShown(id)
302 { 336 {
303 let now = Date.now(); 337 let now = Date.now();
304 let data = Prefs.notificationdata; 338 let data = Prefs.notificationdata;
305 339
306 if (data.shown instanceof Array) 340 if (data.shown instanceof Array)
307 { 341 {
308 let newShown = {}; 342 let newShown = {};
309 for (let oldId of data.shown) 343 for (let oldId of data.shown)
310 newShown[oldId] = now; 344 newShown[oldId] = now;
311 data.shown = newShown; 345 data.shown = newShown;
312 } 346 }
313 347
314 if (typeof data.shown != "object") 348 if (typeof data.shown != "object")
315 data.shown = {}; 349 data.shown = {};
316 350
317 data.shown[id] = now; 351 data.shown[id] = now;
318 352
319 saveNotificationData(); 353 saveNotificationData();
320 }, 354 },
321 355
322 /** 356 /**
323 * Localizes the texts of the supplied notification. 357 * Localizes the texts of the supplied notification.
324 * @param {Object} notification notification to translate 358 * @param {Object} notification notification to translate
325 * @param {String} locale the target locale (optional, defaults to the 359 * @param {string} locale the target locale (optional, defaults to the
326 * application locale) 360 * application locale)
327 * @return {Object} the translated texts 361 * @return {Object} the translated texts
328 */ 362 */
329 getLocalizedTexts: function(notification, locale) 363 getLocalizedTexts(notification, locale)
330 { 364 {
331 locale = locale || Utils.appLocale; 365 locale = locale || Utils.appLocale;
332 let textKeys = ["title", "message"]; 366 let textKeys = ["title", "message"];
333 let localizedTexts = []; 367 let localizedTexts = [];
334 for (let key of textKeys) 368 for (let key of textKeys)
335 { 369 {
336 if (key in notification) 370 if (key in notification)
337 { 371 {
338 if (typeof notification[key] == "string") 372 if (typeof notification[key] == "string")
339 localizedTexts[key] = notification[key]; 373 localizedTexts[key] = notification[key];
340 else 374 else
341 localizedTexts[key] = localize(notification[key], locale); 375 localizedTexts[key] = localize(notification[key], locale);
342 } 376 }
343 } 377 }
344 return localizedTexts; 378 return localizedTexts;
345 }, 379 },
346 380
347 /** 381 /**
348 * Adds a local notification. 382 * Adds a local notification.
349 * @param {Object} notification notification to add 383 * @param {Object} notification notification to add
350 */ 384 */
351 addNotification: function(notification) 385 addNotification(notification)
352 { 386 {
353 if (localData.indexOf(notification) == -1) 387 if (localData.indexOf(notification) == -1)
354 localData.push(notification); 388 localData.push(notification);
355 }, 389 },
356 390
357 /** 391 /**
358 * Removes an existing local notification. 392 * Removes an existing local notification.
359 * @param {Object} notification notification to remove 393 * @param {Object} notification notification to remove
360 */ 394 */
361 removeNotification: function(notification) 395 removeNotification(notification)
362 { 396 {
363 let index = localData.indexOf(notification); 397 let index = localData.indexOf(notification);
364 if (index > -1) 398 if (index > -1)
365 localData.splice(index, 1); 399 localData.splice(index, 1);
366 }, 400 },
367 401
368 /** 402 /**
403 * A callback function which listens to see if notifications were approved.
404 *
405 * @callback questionListener
Wladimir Palant 2017/03/09 14:37:13 It's type name, should be uppercased IMHO.
kzar 2017/03/10 06:56:14 Done.
406 * @param {boolean} approved
407 */
408
409 /**
369 * Adds a listener for question-type notifications 410 * Adds a listener for question-type notifications
411 * @param {string} id
412 * @param {questionListener} listener
370 */ 413 */
371 addQuestionListener: function(/**string*/ id, /**function(approved)*/ listener ) 414 addQuestionListener(id, listener)
372 { 415 {
373 if (!(id in questionListeners)) 416 if (!(id in questionListeners))
374 questionListeners[id] = []; 417 questionListeners[id] = [];
375 if (questionListeners[id].indexOf(listener) === -1) 418 if (questionListeners[id].indexOf(listener) === -1)
376 questionListeners[id].push(listener); 419 questionListeners[id].push(listener);
377 }, 420 },
378 421
379 /** 422 /**
380 * Removes a listener that was previously added via addQuestionListener 423 * Removes a listener that was previously added via addQuestionListener
424 * @param {string} id
425 * @param {questionListener} listener
381 */ 426 */
382 removeQuestionListener: function(/**string*/ id, /**function(approved)*/ liste ner) 427 removeQuestionListener(id, listener)
383 { 428 {
384 if (!(id in questionListeners)) 429 if (!(id in questionListeners))
385 return; 430 return;
386 let index = questionListeners[id].indexOf(listener); 431 let index = questionListeners[id].indexOf(listener);
387 if (index > -1) 432 if (index > -1)
388 questionListeners[id].splice(index, 1); 433 questionListeners[id].splice(index, 1);
389 if (questionListeners[id].length === 0) 434 if (questionListeners[id].length === 0)
390 delete questionListeners[id]; 435 delete questionListeners[id];
391 }, 436 },
392 437
393 /** 438 /**
394 * Notifies question listeners about interactions with a notification 439 * Notifies question listeners about interactions with a notification
395 * @param {String} id notification ID 440 * @param {string} id notification ID
396 * @param {Boolean} approved indicator whether notification has been approved or not 441 * @param {boolean} approved indicator whether notification has been approved
397 */ 442 */
398 triggerQuestionListeners: function(id, approved) 443 triggerQuestionListeners(id, approved)
399 { 444 {
400 if (!(id in questionListeners)) 445 if (!(id in questionListeners))
401 return; 446 return;
402 let listeners = questionListeners[id]; 447 let listeners = questionListeners[id];
403 for (let listener of listeners) 448 for (let listener of listeners)
404 listener(approved); 449 listener(approved);
405 }, 450 },
406 451
407 /** 452 /**
408 * Toggles whether notifications of a specific category should be ignored 453 * Toggles whether notifications of a specific category should be ignored
409 * @param {String} category notification category identifier 454 * @param {string} category notification category identifier
410 * @param {Boolean} [forceValue] force specified value 455 * @param {boolean} [forceValue] force specified value
411 */ 456 */
412 toggleIgnoreCategory: function(category, forceValue) 457 toggleIgnoreCategory(category, forceValue)
413 { 458 {
414 let categories = Prefs.notifications_ignoredcategories; 459 let categories = Prefs.notifications_ignoredcategories;
415 let index = categories.indexOf(category); 460 let index = categories.indexOf(category);
416 if (index == -1 && forceValue !== false) 461 if (index == -1 && forceValue !== false)
417 { 462 {
418 categories.push(category); 463 categories.push(category);
419 Prefs.notifications_showui = true; 464 Prefs.notifications_showui = true;
420 } 465 }
421 else if (index != -1 && forceValue !== true) 466 else if (index != -1 && forceValue !== true)
422 categories.splice(index, 1); 467 categories.splice(index, 1);
423 468
424 // HACK: JSON values aren't saved unless they are assigned a different objec t. 469 // HACK: JSON values aren't saved unless they are assigned a
425 Prefs.notifications_ignoredcategories = JSON.parse(JSON.stringify(categories )); 470 // different object.
471 Prefs.notifications_ignoredcategories =
472 JSON.parse(JSON.stringify(categories));
426 } 473 }
427 }; 474 };
428 Notification.init(); 475 Notification.init();
OLDNEW

Powered by Google App Engine
This is Rietveld