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

Delta Between Two Patch Sets: background.js

Issue 5464830253203456: Refactored the abstraction layer to address prerendered pages on Safari caused by leaky abstraction (Closed)
Left Patch Set: Created Feb. 22, 2014, 10:45 a.m.
Right Patch Set: Addressed comments Created April 11, 2014, 2:47 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 | « no previous file | chrome/ext/background.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-2014 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 with(require("filterClasses")) 18 with(require("filterClasses"))
19 { 19 {
20 this.Filter = Filter; 20 this.Filter = Filter;
21 this.RegExpFilter = RegExpFilter; 21 this.RegExpFilter = RegExpFilter;
22 this.BlockingFilter = BlockingFilter; 22 this.BlockingFilter = BlockingFilter;
23 this.WhitelistFilter = WhitelistFilter; 23 this.WhitelistFilter = WhitelistFilter;
24
25 // TODO: The import below isn't necessary anymore with
26 // https://hg.adblockplus.org/adblockplus/rev/7eb29729a72c
27 // However due to https://issues.adblockplus.org/ticket/189
28 // we can't update the subrepo yet. So please remove this
29 // line when the issue was fixed and the subrepo was updated.
30 this.ActiveFilter = ActiveFilter;
24 } 31 }
25 with(require("subscriptionClasses")) 32 with(require("subscriptionClasses"))
26 { 33 {
27 this.Subscription = Subscription; 34 this.Subscription = Subscription;
28 this.DownloadableSubscription = DownloadableSubscription; 35 this.DownloadableSubscription = DownloadableSubscription;
29 } 36 }
30 with(require("whitelisting")) 37 with(require("whitelisting"))
31 { 38 {
32 this.isWhitelisted = isWhitelisted; 39 this.isWhitelisted = isWhitelisted;
33 this.isFrameWhitelisted = isFrameWhitelisted; 40 this.isFrameWhitelisted = isFrameWhitelisted;
34 this.processKeyException = processKeyException; 41 this.processKeyException = processKeyException;
35 } 42 }
36 var FilterStorage = require("filterStorage").FilterStorage; 43 var FilterStorage = require("filterStorage").FilterStorage;
37 var ElemHide = require("elemHide").ElemHide; 44 var ElemHide = require("elemHide").ElemHide;
38 var defaultMatcher = require("matcher").defaultMatcher; 45 var defaultMatcher = require("matcher").defaultMatcher;
39 var Prefs = require("prefs").Prefs; 46 var Prefs = require("prefs").Prefs;
40 var Synchronizer = require("synchronizer").Synchronizer; 47 var Synchronizer = require("synchronizer").Synchronizer;
41 var Utils = require("utils").Utils; 48 var Utils = require("utils").Utils;
42 var Notification = require("notification").Notification; 49 var Notification = require("notification").Notification;
50 var initAntiAdblockNotification = require("antiadblockInit").initAntiAdblockNoti fication;
43 51
44 // Some types cannot be distinguished 52 // Some types cannot be distinguished
45 RegExpFilter.typeMap.OBJECT_SUBREQUEST = RegExpFilter.typeMap.OBJECT; 53 RegExpFilter.typeMap.OBJECT_SUBREQUEST = RegExpFilter.typeMap.OBJECT;
46 RegExpFilter.typeMap.MEDIA = RegExpFilter.typeMap.FONT = RegExpFilter.typeMap.OT HER; 54 RegExpFilter.typeMap.MEDIA = RegExpFilter.typeMap.FONT = RegExpFilter.typeMap.OT HER;
47 55
56 // Chrome on Linux does not fully support chrome.notifications until version 35
57 // https://code.google.com/p/chromium/issues/detail?id=291485
58 var canUseChromeNotifications = require("info").platform == "chromium"
59 && "notifications" in chrome
60 && (navigator.platform.indexOf("Linux") == -1 || parseInt(require("info").appl icationVersion) > 34);
61
48 var isFirstRun = false; 62 var isFirstRun = false;
49 var seenDataCorruption = false; 63 var seenDataCorruption = false;
50 require("filterNotifier").FilterNotifier.addListener(function(action) 64 require("filterNotifier").FilterNotifier.addListener(function(action)
51 { 65 {
52 if (action == "load") 66 if (action == "load")
53 { 67 {
54 var importingOldData = importOldData(); 68 var importingOldData = importOldData();
55 69
56 var addonVersion = require("info").addonVersion; 70 var addonVersion = require("info").addonVersion;
57 var prevVersion = localStorage.currentVersion; 71 var prevVersion = ext.storage.currentVersion;
58 if (prevVersion != addonVersion) 72 if (prevVersion != addonVersion)
59 { 73 {
60 isFirstRun = !prevVersion; 74 isFirstRun = !prevVersion;
61 localStorage.currentVersion = addonVersion; 75 ext.storage.currentVersion = addonVersion;
62 if (!importingOldData) 76 if (!importingOldData)
63 addSubscription(prevVersion); 77 addSubscription(prevVersion);
64 } 78 }
79
80 if (canUseChromeNotifications)
81 initChromeNotifications();
82 initAntiAdblockNotification();
83 }
84
85 // update browser actions when whitelisting might have changed,
86 // due to loading filters or saving filter changes
87 if (action == "load" || action == "save")
88 {
89 ext.pages.query({}, function(pages)
90 {
91 pages.forEach(refreshIconAndContextMenu);
92 });
65 } 93 }
66 }); 94 });
67 95
68 // Special-case domains for which we cannot use style-based hiding rules. 96 // Special-case domains for which we cannot use style-based hiding rules.
69 // See http://crbug.com/68705. 97 // See http://crbug.com/68705.
70 var noStyleRulesHosts = ["mail.google.com", "mail.yahoo.com", "www.google.com"]; 98 var noStyleRulesHosts = ["mail.google.com", "mail.yahoo.com", "www.google.com"];
71 99
72 function removeDeprecatedOptions() 100 function removeDeprecatedOptions()
73 { 101 {
74 var deprecatedOptions = ["specialCaseYouTube", "experimental", "disableInlineT extAds"]; 102 var deprecatedOptions = ["specialCaseYouTube", "experimental", "disableInlineT extAds"];
75 deprecatedOptions.forEach(function(option) 103 deprecatedOptions.forEach(function(option)
76 { 104 {
77 if (option in localStorage) 105 if (option in ext.storage)
78 delete localStorage[option]; 106 delete ext.storage[option];
79 }); 107 });
80 } 108 }
81 109
82 // Remove deprecated options before we do anything else. 110 // Remove deprecated options before we do anything else.
83 removeDeprecatedOptions(); 111 removeDeprecatedOptions();
84 112
85 var activeNotification = null; 113 var activeNotification = null;
86 114
87 // Adds or removes browser action icon according to options. 115 // Adds or removes browser action icon according to options.
88 function refreshIconAndContextMenu(page) 116 function refreshIconAndContextMenu(page)
89 { 117 {
90 if(!/^https?:/.test(page.url)) 118 var whitelisted = isWhitelisted(page.url);
91 return;
92 119
93 var iconFilename; 120 var iconFilename;
94 if (require("info").platform == "safari") 121 if (whitelisted && require("info").platform != "safari")
95 // There is no grayscale version of the icon for whitelisted pages 122 // There is no grayscale version of the icon for whitelisted pages
96 // when using Safari, because icons are grayscale already and icons 123 // when using Safari, because icons are grayscale already and icons
97 // aren't per page in Safari. 124 // aren't per page in Safari.
98 iconFilename = "icons/abp-16.png" 125 iconFilename = "icons/abp-$size-whitelisted.png";
99 else 126 else
100 { 127 iconFilename = "icons/abp-$size.png";
101 var excluded = isWhitelisted(page.url);
102 iconFilename = excluded ? "icons/abp-19-whitelisted.png" : "icons/abp-19.png ";
103 }
104 128
105 page.browserAction.setIcon(iconFilename); 129 page.browserAction.setIcon(iconFilename);
106 iconAnimation.registerPage(page, iconFilename); 130 iconAnimation.registerPage(page, iconFilename);
107 131
108 // Set context menu status according to whether the page has a whitelisted dom ain 132 // show or hide the context menu entry dependent on whether
109 if (excluded) 133 // adblocking is active on that page
134 if (whitelisted || !/^https?:/.test(page.url))
110 ext.contextMenus.hideMenuItems(); 135 ext.contextMenus.hideMenuItems();
111 else 136 else
112 ext.contextMenus.showMenuItems(); 137 ext.contextMenus.showMenuItems();
113 } 138 }
114 139
115 /** 140 /**
116 * Old versions for Opera stored patterns.ini in the localStorage object, this 141 * Old versions for Opera stored patterns.ini in the localStorage object, this
117 * will import it into FilterStorage properly. 142 * will import it into FilterStorage properly.
118 * @return {Boolean} true if data import is in progress 143 * @return {Boolean} true if data import is in progress
119 */ 144 */
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
182 { 207 {
183 subscription.title = "Allow non-intrusive advertising"; 208 subscription.title = "Allow non-intrusive advertising";
184 FilterStorage.addSubscription(subscription); 209 FilterStorage.addSubscription(subscription);
185 if (subscription instanceof DownloadableSubscription && !subscription.last Download) 210 if (subscription instanceof DownloadableSubscription && !subscription.last Download)
186 Synchronizer.execute(subscription); 211 Synchronizer.execute(subscription);
187 } 212 }
188 else 213 else
189 addAcceptable = false; 214 addAcceptable = false;
190 } 215 }
191 216
217 // Add "anti-adblock messages" subscription
218 var subscription = Subscription.fromURL(Prefs.subscriptions_antiadblockurl);
219 if (subscription)
220 {
221 subscription.disabled = true;
222 FilterStorage.addSubscription(subscription);
223 if (subscription instanceof DownloadableSubscription && !subscription.lastDo wnload)
224 Synchronizer.execute(subscription);
225 }
226
192 if (!addSubscription && !addAcceptable) 227 if (!addSubscription && !addAcceptable)
193 return; 228 return;
194 229
195 function notifyUser() 230 function notifyUser()
196 { 231 {
197 ext.pages.open(ext.getURL("firstRun.html")); 232 ext.pages.open(ext.getURL("firstRun.html"));
198 } 233 }
199 234
200 if (addSubscription) 235 if (addSubscription)
201 { 236 {
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 }); 281 });
247 setContextMenu(); 282 setContextMenu();
248 283
249 /** 284 /**
250 * Opens options page or focuses an existing one, within the last focused windo w. 285 * Opens options page or focuses an existing one, within the last focused windo w.
251 * @param {Function} callback function to be called with the 286 * @param {Function} callback function to be called with the
252 Page object of the options page 287 Page object of the options page
253 */ 288 */
254 function openOptions(callback) 289 function openOptions(callback)
255 { 290 {
256 ext.pages.query({lastFocusedWindow: true}, function(pages) 291 ext.pages.query({lastFocusedWindow: true}, function(pages)
Wladimir Palant 2014/04/04 14:00:35 The compat info for Chrome needs to be changed - l
Sebastian Noack 2014/04/07 13:15:25 Done.
257 { 292 {
258 var optionsUrl = ext.getURL("options.html"); 293 var optionsUrl = ext.getURL("options.html");
259 294
260 for (var i = 0; i < pages.length; i++) 295 for (var i = 0; i < pages.length; i++)
261 { 296 {
262 var page = pages[i]; 297 var page = pages[i];
263 if (page.url == optionsUrl) 298 if (page.url == optionsUrl)
264 { 299 {
265 page.activate(); 300 page.activate();
266 if (callback) 301 if (callback)
267 callback(page); 302 callback(page);
268 return; 303 return;
269 } 304 }
270 } 305 }
271 306
272 ext.pages.open(optionsUrl, callback); 307 ext.pages.open(optionsUrl, callback);
Wladimir Palant 2014/04/04 14:00:35 Won't this break abp: links? The add-subscription
Sebastian Noack 2014/04/07 13:15:25 It was wishful thinking, that the callback passed
273 }); 308 });
274 } 309 }
275 310
276 function prepareNotificationIconAndPopup() 311 function prepareNotificationIconAndPopup()
277 { 312 {
313 var animateIcon = (activeNotification.type !== "question");
278 activeNotification.onClicked = function() 314 activeNotification.onClicked = function()
279 { 315 {
280 iconAnimation.stop(); 316 if (animateIcon)
281 activeNotification = null; 317 iconAnimation.stop();
318 notificationClosed();
282 }; 319 };
283 320 if (animateIcon)
284 iconAnimation.update(activeNotification.severity); 321 iconAnimation.update(activeNotification.type);
322 }
323
324 function openNotificationLinks()
325 {
326 if (activeNotification.links)
327 {
328 activeNotification.links.forEach(function(link)
329 {
330 ext.windows.getLastFocused(function(win)
331 {
332 win.openTab(Utils.getDocLink(link));
333 });
334 });
335 }
336 }
337
338 function notificationButtonClick(buttonIndex)
339 {
340 if (activeNotification.type === "question")
341 {
342 Notification.triggerQuestionListeners(activeNotification.id, buttonIndex === 0);
343 Notification.markAsShown(activeNotification.id);
344 activeNotification.onClicked();
345 }
346 else if (activeNotification.links && activeNotification.links[buttonIndex])
347 {
348 ext.windows.getLastFocused(function(win)
349 {
350 win.openTab(Utils.getDocLink(activeNotification.links[buttonIndex]));
351 });
352 }
353 }
354
355 function notificationClosed()
356 {
357 activeNotification = null;
358 }
359
360 function imgToBase64(url, callback)
361 {
362 var canvas = document.createElement("canvas"),
363 ctx = canvas.getContext("2d"),
364 img = new Image;
365 img.src = url;
366 img.onload = function()
367 {
368 canvas.height = img.height;
369 canvas.width = img.width;
370 ctx.drawImage(img, 0, 0);
371 callback(canvas.toDataURL("image/png"));
372 canvas = null;
373 };
374 }
375
376 function initChromeNotifications()
377 {
378 // Chrome hides notifications in notification center when clicked so we need t o clear them
379 function clearActiveNotification(notificationId)
380 {
381 if (activeNotification && activeNotification.type != "question" && !("links" in activeNotification))
382 return;
383
384 chrome.notifications.clear(notificationId, function(wasCleared)
385 {
386 if (wasCleared)
387 notificationClosed();
388 });
389 }
390
391 chrome.notifications.onButtonClicked.addListener(function(notificationId, butt onIndex)
392 {
393 notificationButtonClick(buttonIndex);
394 clearActiveNotification(notificationId);
395 });
396 chrome.notifications.onClicked.addListener(clearActiveNotification);
397 chrome.notifications.onClosed.addListener(notificationClosed);
285 } 398 }
286 399
287 function showNotification(notification) 400 function showNotification(notification)
288 { 401 {
402 if (activeNotification && activeNotification.id === notification.id)
403 return;
404
289 activeNotification = notification; 405 activeNotification = notification;
290 406 if (activeNotification.type === "critical" || activeNotification.type === "que stion")
291 if (activeNotification.severity === "critical" 407 {
292 && typeof webkitNotifications !== "undefined") 408 var hasWebkitNotifications = typeof webkitNotifications !== "undefined";
293 { 409 if (hasWebkitNotifications && "createHTMLNotification" in webkitNotification s)
294 var notification = webkitNotifications.createHTMLNotification("notification. html"); 410 {
295 notification.show(); 411 var notification = webkitNotifications.createHTMLNotification("notificatio n.html");
296 notification.addEventListener("close", prepareNotificationIconAndPopup); 412 notification.show();
297 } 413 prepareNotificationIconAndPopup();
298 else 414 return;
299 prepareNotificationIconAndPopup(); 415 }
416
417 var texts = Notification.getLocalizedTexts(notification);
418 var title = texts.title || "";
419 var message = texts.message ? texts.message.replace(/<\/?(a|strong)>/g, "") : "";
420 var iconUrl = ext.getURL("icons/abp-128.png");
421 var hasLinks = activeNotification.links && activeNotification.links.length > 0;
422
423 if (canUseChromeNotifications)
424 {
425 var opts = {
426 type: "basic",
427 title: title,
428 message: message,
429 buttons: [],
430 priority: 2 // We use the highest priority to prevent the notification f rom closing automatically
431 };
432 if (activeNotification.type === "question")
433 {
434 opts.buttons.push({title: ext.i18n.getMessage("overlay_notification_butt on_yes")});
435 opts.buttons.push({title: ext.i18n.getMessage("overlay_notification_butt on_no")});
436 }
437 else
438 {
439 var regex = /<a>(.*?)<\/a>/g;
440 var plainMessage = texts.message || "";
441 var match;
442 while (match = regex.exec(plainMessage))
443 opts.buttons.push({title: match[1]});
444 }
445
446 imgToBase64(iconUrl, function(iconData)
447 {
448 opts["iconUrl"] = iconData;
449 chrome.notifications.create("", opts, function() {});
450 });
451 }
452 else if (hasWebkitNotifications && "createNotification" in webkitNotificatio ns && activeNotification.type !== "question")
453 {
454 if (hasLinks)
455 message += " " + ext.i18n.getMessage("notification_without_buttons");
456
457 imgToBase64(iconUrl, function(iconData)
458 {
459 var notification = webkitNotifications.createNotification(iconData, titl e, message);
460 notification.show();
461 notification.addEventListener("click", openNotificationLinks, false);
462 notification.addEventListener("close", notificationClosed, false);
463 });
464 }
465 else
466 {
467 var message = title + "\n" + message;
468 if (hasLinks)
469 message += "\n\n" + ext.i18n.getMessage("notification_with_buttons");
470
471 var approved = confirm(message);
472 if (activeNotification.type === "question")
473 notificationButtonClick(approved ? 0 : 1);
474 else if (approved)
475 openNotificationLinks();
476 }
477 }
478 prepareNotificationIconAndPopup();
300 } 479 }
301 480
302 ext.onMessage.addListener(function (msg, sender, sendResponse) 481 ext.onMessage.addListener(function (msg, sender, sendResponse)
303 { 482 {
304 switch (msg.type) 483 switch (msg.type)
305 { 484 {
306 case "get-selectors": 485 case "get-selectors":
307 var selectors = null; 486 var selectors = null;
308 487
309 if (!isFrameWhitelisted(sender.page, sender.frame, "DOCUMENT") && 488 if (!isFrameWhitelisted(sender.page, sender.frame, "DOCUMENT") &&
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
386 // sendResponse asynchronously 565 // sendResponse asynchronously
387 return true; 566 return true;
388 } 567 }
389 break; 568 break;
390 default: 569 default:
391 sendResponse({}); 570 sendResponse({});
392 break; 571 break;
393 } 572 }
394 }); 573 });
395 574
396 // Show icon as browser action for all pages that already exist 575 // update icon when page changes location
397 ext.pages.query({}, function(pages)
398 {
399 pages.forEach(refreshIconAndContextMenu);
400 });
401
402 // Update icon for new loaded pages
403 ext.pages.onLoading.addListener(function(page) 576 ext.pages.onLoading.addListener(function(page)
404 { 577 {
405 page.sendMessage({type: "clickhide-deactivate"}); 578 page.sendMessage({type: "clickhide-deactivate"});
406 refreshIconAndContextMenu(page); 579 refreshIconAndContextMenu(page);
407 }); 580 });
408 581
409 setTimeout(function() 582 setTimeout(function()
410 { 583 {
411 var notificationToShow = Notification.getNextToShow(); 584 var notificationToShow = Notification.getNextToShow();
412 if (notificationToShow) 585 if (notificationToShow)
413 showNotification(notificationToShow); 586 showNotification(notificationToShow);
414 }, 3 * 60 * 1000); 587 }, 3 * 60 * 1000);
LEFTRIGHT

Powered by Google App Engine
This is Rietveld