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, 11:55 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
« no previous file with comments | « defaults/prefs.js ('k') | lib/ui.js » ('j') | lib/ui.js » ('J')
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 SEVERITY = {
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 return (notification.severity in SEVERITY ? SEVERITY[notification.severity] : SEVERITY.information);
Felix Dahlke 2014/02/12 15:09:27 I actually thought it's fine to call this TYPE, ju
Thomas Greiner 2014/02/12 18:28:02 Done.
36 return (notification.severity in levels ? levels[notification.severity] : leve ls.information);
37 } 45 }
38 46
39 function saveNotificationData() 47 function saveNotificationData()
40 { 48 {
41 // HACK: JSON values aren't saved unless they are assigned a different object. 49 // HACK: JSON values aren't saved unless they are assigned a different object.
42 Prefs.notificationdata = JSON.parse(JSON.stringify(Prefs.notificationdata)); 50 Prefs.notificationdata = JSON.parse(JSON.stringify(Prefs.notificationdata));
43 } 51 }
44 52
45 function localize(translations, locale) 53 function localize(translations, locale)
46 { 54 {
47 if (locale in translations) 55 if (locale in translations)
48 return translations[locale]; 56 return translations[locale];
49 57
50 let languagePart = locale.substring(0, locale.indexOf("-")); 58 let languagePart = locale.substring(0, locale.indexOf("-"));
51 if (languagePart && languagePart in translations) 59 if (languagePart && languagePart in translations)
52 return translations[languagePart]; 60 return translations[languagePart];
53 61
54 let defaultLocale = "en-US"; 62 let defaultLocale = "en-US";
55 return translations[defaultLocale]; 63 return translations[defaultLocale];
56 } 64 }
57 65
58 /** 66 /**
59 * The object providing actual downloading functionality. 67 * The object providing actual downloading functionality.
60 * @type Downloader 68 * @type Downloader
61 */ 69 */
62 let downloader = null; 70 let downloader = null;
71 let localData = [];
63 72
64 /** 73 /**
65 * Regularly fetches notifications and decides which to show. 74 * Regularly fetches notifications and decides which to show.
66 * @class 75 * @class
67 */ 76 */
68 let Notification = exports.Notification = 77 let Notification = exports.Notification =
69 { 78 {
70 /** 79 /**
71 * Called on module startup. 80 * Called on module startup.
72 */ 81 */
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 144
136 _onDownloadError: function(downloadable, downloadURL, error, channelStatus, re sponseStatus, redirectCallback) 145 _onDownloadError: function(downloadable, downloadURL, error, channelStatus, re sponseStatus, redirectCallback)
137 { 146 {
138 Prefs.notificationdata.lastError = Date.now(); 147 Prefs.notificationdata.lastError = Date.now();
139 Prefs.notificationdata.downloadStatus = error; 148 Prefs.notificationdata.downloadStatus = error;
140 saveNotificationData(); 149 saveNotificationData();
141 }, 150 },
142 151
143 /** 152 /**
144 * Determines which notification is to be shown next. 153 * Determines which notification is to be shown next.
145 * @param {Array of Object} notifications active notifications 154 * @param {String} url URL to match notifications to
Felix Dahlke 2014/02/12 15:09:27 Would be nice to point out here that it's optional
Thomas Greiner 2014/02/12 18:28:02 Done.
146 * @return {Object} notification to be shown, or null if there is none 155 * @return {Object} notification to be shown, or null if there is none
147 */ 156 */
148 getNextToShow: function() 157 getNextToShow: function(url)
149 { 158 {
150 function checkTarget(target, parameter, name, version) 159 function checkTarget(target, parameter, name, version)
151 { 160 {
152 let minVersionKey = parameter + "MinVersion"; 161 let minVersionKey = parameter + "MinVersion";
153 let maxVersionKey = parameter + "MaxVersion"; 162 let maxVersionKey = parameter + "MaxVersion";
154 return !((parameter in target && target[parameter] != name) || 163 return !((parameter in target && target[parameter] != name) ||
155 (minVersionKey in target && Services.vc.compare(version, target[m inVersionKey]) < 0) || 164 (minVersionKey in target && Services.vc.compare(version, target[m inVersionKey]) < 0) ||
156 (maxVersionKey in target && Services.vc.compare(version, target[m axVersionKey]) > 0)); 165 (maxVersionKey in target && Services.vc.compare(version, target[m axVersionKey]) > 0));
157
158 } 166 }
159 167
160 if (typeof Prefs.notificationdata.data != "object" || !(Prefs.notificationda ta.data.notifications instanceof Array)) 168 let remoteData = [];
161 return null; 169 if (typeof Prefs.notificationdata.data == "object" && Prefs.notificationdata .data.notifications instanceof Array)
170 remoteData = Prefs.notificationdata.data.notifications;
162 171
163 if (!(Prefs.notificationdata.shown instanceof Array)) 172 if (!(Prefs.notificationdata.shown instanceof Array))
164 { 173 {
165 Prefs.notificationdata.shown = []; 174 Prefs.notificationdata.shown = [];
166 saveNotificationData(); 175 saveNotificationData();
167 } 176 }
168 177
178 let notifications = localData.concat(remoteData);
179 if (notifications.length === 0)
180 return null;
181
169 let {addonName, addonVersion, application, applicationVersion, platform, pla tformVersion} = require("info"); 182 let {addonName, addonVersion, application, applicationVersion, platform, pla tformVersion} = require("info");
170 let notifications = Prefs.notificationdata.data.notifications;
171 let notificationToShow = null; 183 let notificationToShow = null;
172 for each (let notification in notifications) 184 for each (let notification in notifications)
173 { 185 {
174 if ((typeof notification.severity === "undefined" || notification.severity === "information") 186 if ((typeof notification.severity === "undefined" || notification.severity !== "critical")
175 && Prefs.notificationdata.shown.indexOf(notification.id) !== -1) 187 && Prefs.notificationdata.shown.indexOf(notification.id) !== -1)
176 continue; 188 continue;
177 189
190 if (typeof url === "string" || notification.urlFilters instanceof Array)
191 {
192 if (typeof url === "string" && notification.urlFilters instanceof Array)
193 {
194 let matcher = new Matcher();
195 for each (let urlFilter in notification.urlFilters)
196 matcher.add(Filter.fromText(urlFilter));
197 if (!matcher.matchesAny(url, "DOCUMENT", url))
198 continue;
199 }
200 else
201 continue;
202 }
203
178 if (notification.targets instanceof Array) 204 if (notification.targets instanceof Array)
179 { 205 {
180 let match = false; 206 let match = false;
181 for each (let target in notification.targets) 207 for each (let target in notification.targets)
182 { 208 {
183 if (checkTarget(target, "extension", addonName, addonVersion) && 209 if (checkTarget(target, "extension", addonName, addonVersion) &&
184 checkTarget(target, "application", application, applicationVersion ) && 210 checkTarget(target, "application", application, applicationVersion ) &&
185 checkTarget(target, "platform", platform, platformVersion)) 211 checkTarget(target, "platform", platform, platformVersion))
186 { 212 {
187 match = true; 213 match = true;
188 break; 214 break;
189 } 215 }
190 } 216 }
191 if (!match) 217 if (!match)
192 continue; 218 continue;
193 } 219 }
194 220
195 if (!notificationToShow 221 if (!notificationToShow || getNumericalSeverity(notification) > getNumeric alSeverity(notificationToShow))
Felix Dahlke 2014/02/12 15:09:27 Can you restore the line break? To avoid unrelated
Thomas Greiner 2014/02/12 18:28:02 Done.
196 || getNumericalSeverity(notification) > getNumericalSeverity(notificat ionToShow))
197 notificationToShow = notification; 222 notificationToShow = notification;
198 } 223 }
199 224
200 if (notificationToShow && "id" in notificationToShow) 225 if (notificationToShow && "id" in notificationToShow)
201 { 226 {
202 Prefs.notificationdata.shown.push(notificationToShow.id); 227 if (notificationToShow.severity !== "question")
203 saveNotificationData(); 228 this.markAsShown(notificationToShow.id);
204 } 229 }
205 230
206 return notificationToShow; 231 return notificationToShow;
207 }, 232 },
208 233
234 markAsShown: function(id)
235 {
236 if (Prefs.notificationdata.shown.indexOf(id) > -1)
237 return;
238
239 Prefs.notificationdata.shown.push(id);
240 saveNotificationData();
241 },
242
209 /** 243 /**
210 * Localizes the texts of the supplied notification. 244 * Localizes the texts of the supplied notification.
211 * @param {Object} notification notification to translate 245 * @param {Object} notification notification to translate
212 * @param {String} locale the target locale (optional, defaults to the 246 * @param {String} locale the target locale (optional, defaults to the
213 * application locale) 247 * application locale)
214 * @return {Object} the translated texts 248 * @return {Object} the translated texts
215 */ 249 */
216 getLocalizedTexts: function(notification, locale) 250 getLocalizedTexts: function(notification, locale)
217 { 251 {
218 locale = locale || Utils.appLocale; 252 locale = locale || Utils.appLocale;
219 let textKeys = ["title", "message"]; 253 let textKeys = ["title", "message"];
220 let localizedTexts = []; 254 let localizedTexts = [];
221 for each (let key in textKeys) 255 for each (let key in textKeys)
222 { 256 {
223 if (key in notification) 257 if (key in notification)
224 localizedTexts[key] = localize(notification[key], locale); 258 {
259 if (typeof notification[key] == "string")
260 localizedTexts[key] = notification[key];
261 else
262 localizedTexts[key] = localize(notification[key], locale);
263 }
225 } 264 }
226 return localizedTexts; 265 return localizedTexts;
266 },
267
268 /**
269 * Adds a local notification.
270 * @param {Object} notification notification to add
271 */
272 addNotification: function(notification)
273 {
274 if (localData.indexOf(notification) == -1)
275 localData.push(notification);
276 },
277
278 /**
279 * Removes an existing local notification.
280 * @param {Object} notification notification to remove
281 */
282 removeNotification: function(notification)
283 {
284 let index = localData.indexOf(notification);
285 if (index > -1)
286 localData.splice(index, 1);
287 },
288
289 /**
290 * Adds a listener
291 */
292 addListener: function(/**function(id, approved)*/ listener)
Felix Dahlke 2014/02/12 15:09:27 I think it'd make more sense to register listeners
Thomas Greiner 2014/02/12 18:28:02 Done. Although from a consistency standpoint I'm m
293 {
294 if (listeners.indexOf(listener) === -1)
295 listeners.push(listener);
296 },
297
298 /**
299 * Removes a listener that was previously added via addListener
300 */
301 removeListener: function(/**function(id, approved)*/ listener)
302 {
303 let index = listeners.indexOf(listener);
304 if (index > -1)
305 listeners.splice(index, 1);
306 },
307
308 /**
309 * Notifies listeners about interactions with a notification
310 * @param {String} id notification ID
311 * @param {Boolean} approved indicator whether notification has been approved or not
312 */
313 triggerListeners: function(id, approved)
314 {
315 for each (let listener in listeners)
316 listener(id, approved);
227 } 317 }
228 }; 318 };
229 Notification.init(); 319 Notification.init();
OLDNEW
« no previous file with comments | « defaults/prefs.js ('k') | lib/ui.js » ('j') | lib/ui.js » ('J')

Powered by Google App Engine
This is Rietveld