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

Side by Side Diff: lib/notification.js

Issue 5538776168267776: Implemented anti-adblock message notification (Closed)
Patch Set: Created Feb. 12, 2014, 6:22 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « defaults/prefs.js ('k') | lib/ui.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <http://adblockplus.org/>, 2 * This file is part of Adblock Plus <http://adblockplus.org/>,
3 * Copyright (C) 2006-2013 Eyeo GmbH 3 * Copyright (C) 2006-2013 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 /** 18 /**
19 * @fileOverview Handles notifications. 19 * @fileOverview Handles notifications.
20 */ 20 */
21 21
22 Cu.import("resource://gre/modules/Services.jsm"); 22 Cu.import("resource://gre/modules/Services.jsm");
23 23
24 let {TimeLine} = require("timeline"); 24 let {TimeLine} = require("timeline");
25 let {Prefs} = require("prefs"); 25 let {Prefs} = require("prefs");
26 let {Downloader, Downloadable, MILLIS_IN_MINUTE, MILLIS_IN_HOUR, MILLIS_IN_DAY} = require("downloader"); 26 let {Downloader, Downloadable, MILLIS_IN_MINUTE, MILLIS_IN_HOUR, MILLIS_IN_DAY} = require("downloader");
27 let {Utils} = require("utils"); 27 let {Utils} = require("utils");
28 let {Matcher} = require("matcher");
29 let {Filter} = require("filterClasses");
28 30
29 let INITIAL_DELAY = 12 * MILLIS_IN_MINUTE; 31 let INITIAL_DELAY = 12 * MILLIS_IN_MINUTE;
30 let CHECK_INTERVAL = 1 * MILLIS_IN_HOUR; 32 let CHECK_INTERVAL = 1 * MILLIS_IN_HOUR;
31 let EXPIRATION_INTERVAL = 1 * MILLIS_IN_DAY; 33 let EXPIRATION_INTERVAL = 1 * MILLIS_IN_DAY;
34 let TYPES = {
Felix Dahlke 2014/02/13 10:22:04 Maybe we should call this TYPE_SEVERITY since it's
Thomas Greiner 2014/02/13 12:57:54 I don't think we need to make it overly specific g
35 information: 0,
36 question: 1,
37 critical: 2
38 };
39
40 let listeners = {};
32 41
33 function getNumericalSeverity(notification) 42 function getNumericalSeverity(notification)
34 { 43 {
35 let levels = {information: 0, critical: 1}; 44 let type = ("type" in notification) ? notification.type : notification.severit y;
36 return (notification.severity in levels ? levels[notification.severity] : leve ls.information); 45 return (type in TYPES ? TYPES[type] : TYPES.information);
37 } 46 }
38 47
39 function saveNotificationData() 48 function saveNotificationData()
40 { 49 {
41 // HACK: JSON values aren't saved unless they are assigned a different object. 50 // HACK: JSON values aren't saved unless they are assigned a different object.
42 Prefs.notificationdata = JSON.parse(JSON.stringify(Prefs.notificationdata)); 51 Prefs.notificationdata = JSON.parse(JSON.stringify(Prefs.notificationdata));
43 } 52 }
44 53
45 function localize(translations, locale) 54 function localize(translations, locale)
46 { 55 {
47 if (locale in translations) 56 if (locale in translations)
48 return translations[locale]; 57 return translations[locale];
49 58
50 let languagePart = locale.substring(0, locale.indexOf("-")); 59 let languagePart = locale.substring(0, locale.indexOf("-"));
51 if (languagePart && languagePart in translations) 60 if (languagePart && languagePart in translations)
52 return translations[languagePart]; 61 return translations[languagePart];
53 62
54 let defaultLocale = "en-US"; 63 let defaultLocale = "en-US";
55 return translations[defaultLocale]; 64 return translations[defaultLocale];
56 } 65 }
57 66
58 /** 67 /**
59 * The object providing actual downloading functionality. 68 * The object providing actual downloading functionality.
60 * @type Downloader 69 * @type Downloader
61 */ 70 */
62 let downloader = null; 71 let downloader = null;
72 let localData = [];
63 73
64 /** 74 /**
65 * Regularly fetches notifications and decides which to show. 75 * Regularly fetches notifications and decides which to show.
66 * @class 76 * @class
67 */ 77 */
68 let Notification = exports.Notification = 78 let Notification = exports.Notification =
69 { 79 {
70 /** 80 /**
71 * Called on module startup. 81 * Called on module startup.
72 */ 82 */
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 145
136 _onDownloadError: function(downloadable, downloadURL, error, channelStatus, re sponseStatus, redirectCallback) 146 _onDownloadError: function(downloadable, downloadURL, error, channelStatus, re sponseStatus, redirectCallback)
137 { 147 {
138 Prefs.notificationdata.lastError = Date.now(); 148 Prefs.notificationdata.lastError = Date.now();
139 Prefs.notificationdata.downloadStatus = error; 149 Prefs.notificationdata.downloadStatus = error;
140 saveNotificationData(); 150 saveNotificationData();
141 }, 151 },
142 152
143 /** 153 /**
144 * Determines which notification is to be shown next. 154 * Determines which notification is to be shown next.
145 * @param {Array of Object} notifications active notifications 155 * @param {String} url URL to match notifications to (optional)
146 * @return {Object} notification to be shown, or null if there is none 156 * @return {Object} notification to be shown, or null if there is none
147 */ 157 */
148 getNextToShow: function() 158 getNextToShow: function(url)
149 { 159 {
150 function checkTarget(target, parameter, name, version) 160 function checkTarget(target, parameter, name, version)
151 { 161 {
152 let minVersionKey = parameter + "MinVersion"; 162 let minVersionKey = parameter + "MinVersion";
153 let maxVersionKey = parameter + "MaxVersion"; 163 let maxVersionKey = parameter + "MaxVersion";
154 return !((parameter in target && target[parameter] != name) || 164 return !((parameter in target && target[parameter] != name) ||
155 (minVersionKey in target && Services.vc.compare(version, target[m inVersionKey]) < 0) || 165 (minVersionKey in target && Services.vc.compare(version, target[m inVersionKey]) < 0) ||
156 (maxVersionKey in target && Services.vc.compare(version, target[m axVersionKey]) > 0)); 166 (maxVersionKey in target && Services.vc.compare(version, target[m axVersionKey]) > 0));
157
158 } 167 }
159 168
160 if (typeof Prefs.notificationdata.data != "object" || !(Prefs.notificationda ta.data.notifications instanceof Array)) 169 let remoteData = [];
161 return null; 170 if (typeof Prefs.notificationdata.data == "object" && Prefs.notificationdata .data.notifications instanceof Array)
171 remoteData = Prefs.notificationdata.data.notifications;
162 172
163 if (!(Prefs.notificationdata.shown instanceof Array)) 173 if (!(Prefs.notificationdata.shown instanceof Array))
164 { 174 {
165 Prefs.notificationdata.shown = []; 175 Prefs.notificationdata.shown = [];
166 saveNotificationData(); 176 saveNotificationData();
167 } 177 }
168 178
179 let notifications = localData.concat(remoteData);
180 if (notifications.length === 0)
181 return null;
182
169 let {addonName, addonVersion, application, applicationVersion, platform, pla tformVersion} = require("info"); 183 let {addonName, addonVersion, application, applicationVersion, platform, pla tformVersion} = require("info");
170 let notifications = Prefs.notificationdata.data.notifications;
171 let notificationToShow = null; 184 let notificationToShow = null;
172 for each (let notification in notifications) 185 for each (let notification in notifications)
173 { 186 {
174 if ((typeof notification.severity === "undefined" || notification.severity === "information") 187 if ((typeof notification.type === "undefined" || notification.type !== "cr itical")
Felix Dahlke 2014/02/13 10:22:04 I'm sorry, my suggestion for being downwards compa
Thomas Greiner 2014/02/13 12:57:54 Done.
175 && Prefs.notificationdata.shown.indexOf(notification.id) !== -1) 188 && Prefs.notificationdata.shown.indexOf(notification.id) !== -1)
176 continue; 189 continue;
177 190
191 if (typeof url === "string" || notification.urlFilters instanceof Array)
192 {
193 if (typeof url === "string" && notification.urlFilters instanceof Array)
194 {
195 let matcher = new Matcher();
196 for each (let urlFilter in notification.urlFilters)
197 matcher.add(Filter.fromText(urlFilter));
198 if (!matcher.matchesAny(url, "DOCUMENT", url))
199 continue;
200 }
201 else
202 continue;
203 }
204
178 if (notification.targets instanceof Array) 205 if (notification.targets instanceof Array)
179 { 206 {
180 let match = false; 207 let match = false;
181 for each (let target in notification.targets) 208 for each (let target in notification.targets)
182 { 209 {
183 if (checkTarget(target, "extension", addonName, addonVersion) && 210 if (checkTarget(target, "extension", addonName, addonVersion) &&
184 checkTarget(target, "application", application, applicationVersion ) && 211 checkTarget(target, "application", application, applicationVersion ) &&
185 checkTarget(target, "platform", platform, platformVersion)) 212 checkTarget(target, "platform", platform, platformVersion))
186 { 213 {
187 match = true; 214 match = true;
188 break; 215 break;
189 } 216 }
190 } 217 }
191 if (!match) 218 if (!match)
192 continue; 219 continue;
193 } 220 }
194 221
195 if (!notificationToShow 222 if (!notificationToShow
196 || getNumericalSeverity(notification) > getNumericalSeverity(notificat ionToShow)) 223 || getNumericalSeverity(notification) > getNumericalSeverity(notificat ionToShow))
197 notificationToShow = notification; 224 notificationToShow = notification;
198 } 225 }
199 226
200 if (notificationToShow && "id" in notificationToShow) 227 if (notificationToShow && "id" in notificationToShow)
201 { 228 {
202 Prefs.notificationdata.shown.push(notificationToShow.id); 229 if (notificationToShow.type !== "question")
203 saveNotificationData(); 230 this.markAsShown(notificationToShow.id);
204 } 231 }
205 232
206 return notificationToShow; 233 return notificationToShow;
207 }, 234 },
208 235
236 markAsShown: function(id)
237 {
238 if (Prefs.notificationdata.shown.indexOf(id) > -1)
239 return;
240
241 Prefs.notificationdata.shown.push(id);
242 saveNotificationData();
243 },
244
209 /** 245 /**
210 * Localizes the texts of the supplied notification. 246 * Localizes the texts of the supplied notification.
211 * @param {Object} notification notification to translate 247 * @param {Object} notification notification to translate
212 * @param {String} locale the target locale (optional, defaults to the 248 * @param {String} locale the target locale (optional, defaults to the
213 * application locale) 249 * application locale)
214 * @return {Object} the translated texts 250 * @return {Object} the translated texts
215 */ 251 */
216 getLocalizedTexts: function(notification, locale) 252 getLocalizedTexts: function(notification, locale)
217 { 253 {
218 locale = locale || Utils.appLocale; 254 locale = locale || Utils.appLocale;
219 let textKeys = ["title", "message"]; 255 let textKeys = ["title", "message"];
220 let localizedTexts = []; 256 let localizedTexts = [];
221 for each (let key in textKeys) 257 for each (let key in textKeys)
222 { 258 {
223 if (key in notification) 259 if (key in notification)
224 localizedTexts[key] = localize(notification[key], locale); 260 {
261 if (typeof notification[key] == "string")
262 localizedTexts[key] = notification[key];
263 else
264 localizedTexts[key] = localize(notification[key], locale);
265 }
225 } 266 }
226 return localizedTexts; 267 return localizedTexts;
268 },
269
270 /**
271 * Adds a local notification.
272 * @param {Object} notification notification to add
273 */
274 addNotification: function(notification)
275 {
276 if (localData.indexOf(notification) == -1)
277 localData.push(notification);
278 },
279
280 /**
281 * Removes an existing local notification.
282 * @param {Object} notification notification to remove
283 */
284 removeNotification: function(notification)
285 {
286 let index = localData.indexOf(notification);
287 if (index > -1)
288 localData.splice(index, 1);
289 },
290
291 /**
292 * Adds a listener for question-type notifications
293 */
294 addQuestionListener: function(/**string*/ id, /**function(approved)*/ listener )
295 {
296 if (!(id in listeners))
297 listeners[id] = [];
298 if (listeners[id].indexOf(listener) === -1)
299 listeners[id].push(listener);
300 },
301
302 /**
303 * Removes a listener that was previously added via addQuestionListener
304 */
305 removeQuestionListener: function(/**string*/ id, /**function(approved)*/ liste ner)
306 {
307 if (!(id in listeners))
308 return;
309 let index = listeners[id].indexOf(listener);
310 if (index > -1)
311 listeners[id].splice(index, 1);
312 if (listeners[id].length === 0)
313 delete listeners[id];
314 },
315
316 /**
317 * Notifies listeners about interactions with a notification
318 * @param {String} id notification ID
319 * @param {Boolean} approved indicator whether notification has been approved or not
320 */
321 triggerQuestionListeners: function(id, approved)
322 {
323 if (!(id in listeners))
324 return;
325 for each (let listener in listeners[id])
326 listener(approved);
227 } 327 }
228 }; 328 };
229 Notification.init(); 329 Notification.init();
OLDNEW
« no previous file with comments | « defaults/prefs.js ('k') | lib/ui.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld