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

Delta Between Two Patch Sets: lib/notification.js

Issue 5538776168267776: Implemented anti-adblock message notification (Closed)
Left Patch Set: Created Feb. 7, 2014, 5:08 p.m.
Right Patch Set: Created Feb. 13, 2014, 12:50 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « defaults/prefs.js ('k') | lib/ui.js » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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
(...skipping 13 matching lines...) Expand all
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"); 28 let {Matcher} = require("matcher");
29 let {Filter} = require("filterClasses"); 29 let {Filter} = require("filterClasses");
30 30
31 let INITIAL_DELAY = 12 * MILLIS_IN_MINUTE; 31 let INITIAL_DELAY = 12 * MILLIS_IN_MINUTE;
32 let CHECK_INTERVAL = 1 * MILLIS_IN_HOUR; 32 let CHECK_INTERVAL = 1 * MILLIS_IN_HOUR;
33 let EXPIRATION_INTERVAL = 1 * MILLIS_IN_DAY; 33 let EXPIRATION_INTERVAL = 1 * MILLIS_IN_DAY;
34 let TYPES = { 34 let TYPE = {
35 information: 0, 35 information: 0,
36 question: 1, 36 question: 1,
37 critical: 2 37 critical: 2
38 }; 38 };
39 39
40 let listeners = {};
41
40 function getNumericalSeverity(notification) 42 function getNumericalSeverity(notification)
41 { 43 {
42 return (notification.type in TYPES ? TYPES[notification.type] : TYPES.informat ion); 44 return (notification.type in TYPE ? TYPE[notification.type] : TYPE.information );
Felix Dahlke 2014/02/11 10:35:27 I think we should be backwards compatible here, we
Thomas Greiner 2014/02/11 16:53:31 Done.
43 } 45 }
44 46
45 function saveNotificationData() 47 function saveNotificationData()
46 { 48 {
47 // 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.
48 Prefs.notificationdata = JSON.parse(JSON.stringify(Prefs.notificationdata)); 50 Prefs.notificationdata = JSON.parse(JSON.stringify(Prefs.notificationdata));
49 } 51 }
50 52
51 function localize(translations, locale) 53 function localize(translations, locale)
52 { 54 {
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 Prefs.notificationdata.lastCheck = downloadable.lastCheck; 120 Prefs.notificationdata.lastCheck = downloadable.lastCheck;
119 Prefs.notificationdata.softExpiration = downloadable.softExpiration; 121 Prefs.notificationdata.softExpiration = downloadable.softExpiration;
120 Prefs.notificationdata.hardExpiration = downloadable.hardExpiration; 122 Prefs.notificationdata.hardExpiration = downloadable.hardExpiration;
121 saveNotificationData(); 123 saveNotificationData();
122 }, 124 },
123 125
124 _onDownloadSuccess: function(downloadable, responseText, errorCallback, redire ctCallback) 126 _onDownloadSuccess: function(downloadable, responseText, errorCallback, redire ctCallback)
125 { 127 {
126 try 128 try
127 { 129 {
128 Prefs.notificationdata.data = JSON.parse(responseText); 130 let data = JSON.parse(responseText);
131 for each (let notification in data.notifications)
132 {
133 if ("severity" in notification)
134 {
135 if (!("type" in notification))
136 notification.type = notification.severity;
137 delete notification.severity;
138 }
139 }
140 Prefs.notificationdata.data = data;
129 } 141 }
130 catch (e) 142 catch (e)
131 { 143 {
132 Cu.reportError(e); 144 Cu.reportError(e);
133 errorCallback("synchronize_invalid_data"); 145 errorCallback("synchronize_invalid_data");
134 return; 146 return;
135 } 147 }
136 148
137 Prefs.notificationdata.lastError = 0; 149 Prefs.notificationdata.lastError = 0;
138 Prefs.notificationdata.downloadStatus = "synchronize_ok"; 150 Prefs.notificationdata.downloadStatus = "synchronize_ok";
139 [Prefs.notificationdata.softExpiration, Prefs.notificationdata.hardExpiratio n] = downloader.processExpirationInterval(EXPIRATION_INTERVAL); 151 [Prefs.notificationdata.softExpiration, Prefs.notificationdata.hardExpiratio n] = downloader.processExpirationInterval(EXPIRATION_INTERVAL);
140 saveNotificationData(); 152 saveNotificationData();
141 }, 153 },
142 154
143 _onDownloadError: function(downloadable, downloadURL, error, channelStatus, re sponseStatus, redirectCallback) 155 _onDownloadError: function(downloadable, downloadURL, error, channelStatus, re sponseStatus, redirectCallback)
144 { 156 {
145 Prefs.notificationdata.lastError = Date.now(); 157 Prefs.notificationdata.lastError = Date.now();
146 Prefs.notificationdata.downloadStatus = error; 158 Prefs.notificationdata.downloadStatus = error;
147 saveNotificationData(); 159 saveNotificationData();
148 }, 160 },
149 161
150 /** 162 /**
151 * Determines which notification is to be shown next. 163 * Determines which notification is to be shown next.
152 * @param {String} url URL to match notifications to 164 * @param {String} url URL to match notifications to (optional)
153 * @return {Array of Object} active notifications 165 * @return {Object} notification to be shown, or null if there is none
154 */ 166 */
155 _getActiveNotifications: function(url) 167 getNextToShow: function(url)
156 { 168 {
157 function checkTarget(target, parameter, name, version) 169 function checkTarget(target, parameter, name, version)
158 { 170 {
159 let minVersionKey = parameter + "MinVersion"; 171 let minVersionKey = parameter + "MinVersion";
160 let maxVersionKey = parameter + "MaxVersion"; 172 let maxVersionKey = parameter + "MaxVersion";
161 return !((parameter in target && target[parameter] != name) || 173 return !((parameter in target && target[parameter] != name) ||
162 (minVersionKey in target && Services.vc.compare(version, target[m inVersionKey]) < 0) || 174 (minVersionKey in target && Services.vc.compare(version, target[m inVersionKey]) < 0) ||
163 (maxVersionKey in target && Services.vc.compare(version, target[m axVersionKey]) > 0)); 175 (maxVersionKey in target && Services.vc.compare(version, target[m axVersionKey]) > 0));
164 } 176 }
165 177
166 let remoteData = []; 178 let remoteData = [];
167 if (typeof Prefs.notificationdata.data == "object" && Prefs.notificationdata .data.notifications instanceof Array) 179 if (typeof Prefs.notificationdata.data == "object" && Prefs.notificationdata .data.notifications instanceof Array)
168 remoteData = Prefs.notificationdata.data.notifications; 180 remoteData = Prefs.notificationdata.data.notifications;
169 181
170 if (!(Prefs.notificationdata.shown instanceof Array)) 182 if (!(Prefs.notificationdata.shown instanceof Array))
171 { 183 {
172 Prefs.notificationdata.shown = []; 184 Prefs.notificationdata.shown = [];
173 saveNotificationData(); 185 saveNotificationData();
174 } 186 }
175 187
188 let notifications = localData.concat(remoteData);
189 if (notifications.length === 0)
190 return null;
191
176 let {addonName, addonVersion, application, applicationVersion, platform, pla tformVersion} = require("info"); 192 let {addonName, addonVersion, application, applicationVersion, platform, pla tformVersion} = require("info");
177 let notifications = localData.concat(remoteData); 193 let notificationToShow = null;
178 let activeNotifications = [];
179 for each (let notification in notifications) 194 for each (let notification in notifications)
180 { 195 {
181 if ((typeof notification.type === "undefined" || notification.type === "in formation" || notification.type === "question") 196 if ((typeof notification.type === "undefined" || notification.type !== "cr itical")
Felix Dahlke 2014/02/11 10:35:27 I think this would make more sense now: if ((type
Thomas Greiner 2014/02/11 16:53:31 Done.
182 && Prefs.notificationdata.shown.indexOf(notification.id) !== -1) 197 && Prefs.notificationdata.shown.indexOf(notification.id) !== -1)
183 continue; 198 continue;
184 199
185 if (typeof url === "string" || notification.domains instanceof Array) 200 if (typeof url === "string" || notification.urlFilters instanceof Array)
Felix Dahlke 2014/02/11 10:35:27 notification.domains are not necessarily domains i
Thomas Greiner 2014/02/11 16:53:31 Done.
186 { 201 {
187 if (typeof url === "string" && notification.domains instanceof Array) 202 if (typeof url === "string" && notification.urlFilters instanceof Array)
188 { 203 {
189 let matcher = new Matcher(); 204 let matcher = new Matcher();
Thomas Greiner 2014/02/07 17:29:17 Let me know if you don't like this approach. Howev
Felix Dahlke 2014/02/11 10:35:27 Pretty fine to me, wouldn't like to complicate thi
190 for each (let filter in notification.domains) 205 for each (let urlFilter in notification.urlFilters)
191 matcher.add(Filter.fromText(filter)); 206 matcher.add(Filter.fromText(urlFilter));
192 if (!matcher.matchesAny(url, "DOCUMENT", url)) 207 if (!matcher.matchesAny(url, "DOCUMENT", url))
193 continue; 208 continue;
194 } 209 }
195 else 210 else
196 continue; 211 continue;
Felix Dahlke 2014/02/11 10:35:27 So if the url parameter is passed, we ignore all n
Thomas Greiner 2014/02/11 16:53:31 This means that some notifications could be shown
Felix Dahlke 2014/02/11 17:11:12 Ah, I thought I'd change my mind on this after rev
197 } 212 }
198 213
199 if (notification.targets instanceof Array) 214 if (notification.targets instanceof Array)
200 { 215 {
201 let match = false; 216 let match = false;
202 for each (let target in notification.targets) 217 for each (let target in notification.targets)
203 { 218 {
204 if (checkTarget(target, "extension", addonName, addonVersion) && 219 if (checkTarget(target, "extension", addonName, addonVersion) &&
205 checkTarget(target, "application", application, applicationVersion ) && 220 checkTarget(target, "application", application, applicationVersion ) &&
206 checkTarget(target, "platform", platform, platformVersion)) 221 checkTarget(target, "platform", platform, platformVersion))
207 { 222 {
208 match = true; 223 match = true;
209 break; 224 break;
210 } 225 }
211 } 226 }
212 if (!match) 227 if (!match)
213 continue; 228 continue;
214 } 229 }
215 230
216 activeNotifications.push(notification); 231 if (!notificationToShow
Felix Dahlke 2014/02/11 10:35:27 Why did you change this logic? It looks to me like
Thomas Greiner 2014/02/11 16:53:31 Done.
217 } 232 || getNumericalSeverity(notification) > getNumericalSeverity(notificat ionToShow))
218 233 notificationToShow = notification;
219 return activeNotifications.sort(function(a, b) 234 }
220 { 235
221 return getNumericalSeverity(b) - getNumericalSeverity(a);
222 });
223 },
224
225 /**
226 * Determines which notification is to be shown next.
227 * @param {String} url URL to match notification to (optional)
228 * @return {Object} notification to be shown, or null if there is none
229 */
230 getNextToShow: function(url)
231 {
232 let [notificationToShow] = this._getActiveNotifications(url);
233 if (notificationToShow && "id" in notificationToShow) 236 if (notificationToShow && "id" in notificationToShow)
234 { 237 {
235 if (notificationToShow.type !== "question") 238 if (notificationToShow.type !== "question")
236 this.markAsShown(notificationToShow.id); 239 this.markAsShown(notificationToShow.id);
237 } 240 }
238 else
239 notificationToShow = null;
240 241
241 return notificationToShow; 242 return notificationToShow;
242 }, 243 },
243 244
244 markAsShown: function(id) 245 markAsShown: function(id)
245 { 246 {
246 if (Prefs.notificationdata.shown.indexOf(id) > -1) 247 if (Prefs.notificationdata.shown.indexOf(id) > -1)
247 return; 248 return;
248 249
249 Prefs.notificationdata.shown.push(id); 250 Prefs.notificationdata.shown.push(id);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
284 if (localData.indexOf(notification) == -1) 285 if (localData.indexOf(notification) == -1)
285 localData.push(notification); 286 localData.push(notification);
286 }, 287 },
287 288
288 /** 289 /**
289 * Removes an existing local notification. 290 * Removes an existing local notification.
290 * @param {Object} notification notification to remove 291 * @param {Object} notification notification to remove
291 */ 292 */
292 removeNotification: function(notification) 293 removeNotification: function(notification)
293 { 294 {
294 if (localData.indexOf(notification) > -1) 295 let index = localData.indexOf(notification);
Felix Dahlke 2014/02/11 10:35:27 Nit: Save the index to a temp instead of calling i
Thomas Greiner 2014/02/11 16:53:31 Done.
295 localData.splice(localData.indexOf(notification), 1); 296 if (index > -1)
297 localData.splice(index, 1);
298 },
299
300 /**
301 * Adds a listener for question-type notifications
302 */
303 addQuestionListener: function(/**string*/ id, /**function(approved)*/ listener )
304 {
305 if (!(id in listeners))
306 listeners[id] = [];
307 if (listeners[id].indexOf(listener) === -1)
308 listeners[id].push(listener);
309 },
310
311 /**
312 * Removes a listener that was previously added via addQuestionListener
313 */
314 removeQuestionListener: function(/**string*/ id, /**function(approved)*/ liste ner)
315 {
316 if (!(id in listeners))
317 return;
318 let index = listeners[id].indexOf(listener);
319 if (index > -1)
320 listeners[id].splice(index, 1);
321 if (listeners[id].length === 0)
322 delete listeners[id];
323 },
324
325 /**
326 * Notifies listeners about interactions with a notification
327 * @param {String} id notification ID
328 * @param {Boolean} approved indicator whether notification has been approved or not
329 */
330 triggerQuestionListeners: function(id, approved)
331 {
332 if (!(id in listeners))
333 return;
334 for each (let listener in listeners[id])
335 listener(approved);
296 } 336 }
297 }; 337 };
298 Notification.init(); 338 Notification.init();
LEFTRIGHT

Powered by Google App Engine
This is Rietveld