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