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

Delta Between Two Patch Sets: background.js

Issue 11161031: Show notifications on startup (Chrome) (Closed)
Left Patch Set: Addressed issues (except for the animation) Created July 22, 2013, 12:27 p.m.
Right Patch Set: Addressed issues Created July 23, 2013, 12:51 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 | « .hgsubstate ('k') | icons/notification-critical.png » ('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 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
114 function refreshIconAndContextMenu(tab) 114 function refreshIconAndContextMenu(tab)
115 { 115 {
116 // The tab could have been closed by the time this function is called 116 // The tab could have been closed by the time this function is called
117 if(!tab) 117 if(!tab)
118 return; 118 return;
119 119
120 var excluded = isWhitelisted(tab.url); 120 var excluded = isWhitelisted(tab.url);
121 var iconFilename = excluded ? "icons/abp-19-whitelisted.png" : "icons/abp-19.p ng"; 121 var iconFilename = excluded ? "icons/abp-19-whitelisted.png" : "icons/abp-19.p ng";
122 122
123 if (activeNotification) 123 if (activeNotification)
124 setNotificationPageAction(tab, iconFilename); 124 startIconAnimation(tab, iconFilename);
Wladimir Palant 2013/07/22 14:18:36 setNotificationPageAction() won't do anything for
Felix Dahlke 2013/07/22 15:10:22 Yes, it was like that. In patch set 4, all notific
125 else 125 else
126 chrome.pageAction.setIcon({tabId: tab.id, path: iconFilename}); 126 chrome.pageAction.setIcon({tabId: tab.id, path: iconFilename});
127 127
128 // Only show icon for pages we can influence (http: and https:) 128 // Only show icon for pages we can influence (http: and https:)
129 if(/^https?:/.test(tab.url)) 129 if(/^https?:/.test(tab.url))
130 { 130 {
131 chrome.pageAction.setTitle({tabId: tab.id, title: "Adblock Plus"}); 131 chrome.pageAction.setTitle({tabId: tab.id, title: "Adblock Plus"});
132 if ("shouldShowIcon" in localStorage && localStorage["shouldShowIcon"] == "f alse") 132 if ("shouldShowIcon" in localStorage && localStorage["shouldShowIcon"] == "f alse")
133 chrome.pageAction.hide(tab.id); 133 chrome.pageAction.hide(tab.id);
134 else 134 else
135 chrome.pageAction.show(tab.id); 135 chrome.pageAction.show(tab.id);
136 136
137 // Set context menu status according to whether current tab has whitelisted domain 137 // Set context menu status according to whether current tab has whitelisted domain
138 if (excluded) 138 if (excluded)
139 chrome.contextMenus.removeAll(); 139 chrome.contextMenus.removeAll();
140 else 140 else
141 showContextMenu(); 141 showContextMenu();
142 } 142 }
143 }
144
145 function loadImages(imageFiles, callback)
146 {
147 var images = {};
148 var imagesLoaded = 0;
149 imageFiles.forEach(function(imageFile)
150 {
151 var image = new Image();
152 image.src = imageFile;
153 image.addEventListener("load", function()
154 {
155 images[imageFile] = image;
156 if (++imagesLoaded === imageFiles.length)
157 callback(images);
158 });
159 });
160 }
161
162 var iconAnimationTimer = null;
163
164 function stopIconAnimation()
165 {
166 if (!iconAnimationTimer)
167 return;
168
169 clearTimeout(iconAnimationTimer);
170 iconAnimationTimer = null;
171 chrome.tabs.getAllInWindow(null, function(tabs)
172 {
173 tabs.forEach(refreshIconAndContextMenu);
174 activeNotification = null;
Wladimir Palant 2013/07/22 14:18:36 Shouldn't activeNotification be reset before calli
Felix Dahlke 2013/07/22 15:10:22 Yes, I fixed that in patch set 4.
175 });
176 }
177
178 function setNotificationPageAction(tab, iconFileName)
179 {
180 if (activeNotification.severity !== "critical")
181 return;
182
183 stopIconAnimation();
184
185 var notificationIconFile = "icons/notification-critical.png";
186 var iconFiles = [iconFileName, notificationIconFile];
187 loadImages(iconFiles, function(images)
188 {
189 var abpIcon = images[iconFileName];
190 var notificationIcon = images[notificationIconFile];
191 var canvas = document.createElement("canvas");
192 canvas.width = abpIcon.width;
193 canvas.height = abpIcon.height;
194 var context = canvas.getContext("2d");
195 context.clearRect(0, 0, canvas.width, canvas.height);
196 context.drawImage(abpIcon, 0, 0);
197 context.drawImage(notificationIcon, 0, 0);
198 var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
Wladimir Palant 2013/07/22 14:18:36 The code to combine two images with some opacity a
Felix Dahlke 2013/07/22 15:10:22 Not necessary anymore, as of patch set 4.
199 chrome.pageAction.setIcon({tabId: tab.id, imageData: imageData});
200 });
201 } 143 }
202 144
203 /** 145 /**
204 * Old versions stored filter data in the localStorage object, this will import 146 * Old versions stored filter data in the localStorage object, this will import
205 * it into FilterStorage properly. 147 * it into FilterStorage properly.
206 */ 148 */
207 function importOldData() 149 function importOldData()
208 { 150 {
209 function addSubscription(url, title) 151 function addSubscription(url, title)
210 { 152 {
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after
531 chrome.tabs.onUpdated.removeListener(listener); 473 chrome.tabs.onUpdated.removeListener(listener);
532 onLoad(); 474 onLoad();
533 } 475 }
534 }; 476 };
535 chrome.tabs.onUpdated.addListener(listener); 477 chrome.tabs.onUpdated.addListener(listener);
536 } 478 }
537 }); 479 });
538 } 480 }
539 } 481 }
540 482
541 function startInformationNotificationAnimation() 483 var iconAnimationTimer = null;
484 var animatedIconTab = null;
485
486 function stopIconAnimation()
487 {
488 if (!iconAnimationTimer)
489 return;
490
491 clearTimeout(iconAnimationTimer);
492 iconAnimationTimer = null;
493 animatedIconTab = null;
494 }
495
496 function loadImages(imageFiles, callback)
497 {
498 var images = {};
499 var imagesLoaded = 0;
500 imageFiles.forEach(function(imageFile)
501 {
502 var image = new Image();
503 image.src = imageFile;
504 image.addEventListener("load", function()
505 {
506 images[imageFile] = image;
507 if (++imagesLoaded === imageFiles.length)
508 callback(images);
509 });
510 });
511 }
512
513 function startIconAnimation(tab, iconPath)
542 { 514 {
543 stopIconAnimation(); 515 stopIconAnimation();
544 516 animatedIconTab = tab;
545 var abpIconFile = "icons/abp-19.png"; 517
Wladimir Palant 2013/07/22 14:18:36 This still hardcodes the icon and fails to conside
Felix Dahlke 2013/07/22 15:10:22 Has been fixed in patch set 4. But yeah, second co
Wladimir Palant 2013/07/23 07:25:04 No, we can still work with a single global timer -
Felix Dahlke 2013/07/23 10:38:08 Done. I do prefer this, just wasn't able to come u
546 var notificationIconFile = "icons/notification-information.png"; 518 var severitySuffix = activeNotification.severity === "critical"
547 var iconFiles = [abpIconFile, notificationIconFile]; 519 ? "critical" : "information";
520 var notificationIconPath = "icons/notification-" + severitySuffix + ".png";
521 var iconFiles = [iconPath, notificationIconPath];
548 loadImages(iconFiles, function(images) 522 loadImages(iconFiles, function(images)
549 { 523 {
550 var abpIcon = images[abpIconFile]; 524 var icon = images[iconPath];
551 var notificationIcon = images[notificationIconFile]; 525 var notificationIcon = images[notificationIconPath];
526
552 var canvas = document.createElement("canvas"); 527 var canvas = document.createElement("canvas");
553 canvas.width = abpIcon.width; 528 canvas.width = icon.width;
554 canvas.height = abpIcon.height; 529 canvas.height = icon.height;
555 var context = canvas.getContext("2d"); 530 var context = canvas.getContext("2d");
556 531
557 var animationStartTime = Date.now(); 532 var currentFrame = 0;
558 var animationInterval = 1000 / 10; 533 var frameOpacities = [0, 0.2, 0.4, 0.6, 0.8,
534 1, 1, 1, 1, 1,
535 0.8, 0.6, 0.4, 0.2, 0];
536
559 function animationStep() 537 function animationStep()
560 { 538 {
561 var timeElapsed = Date.now() - animationStartTime; 539 var opacity = frameOpacities[currentFrame];
562 var duration = 3000;
563 var animationTime = timeElapsed % duration;
564 var delay = 1000;
565 var fadeInEndTime = duration / 2 - delay / 2;
566 var fadeOutStartTime = fadeInEndTime + delay;
567
568 var opacity;
569 if (animationTime < fadeInEndTime)
570 opacity = animationTime / fadeInEndTime;
571 else if (animationTime > fadeOutStartTime)
572 opacity = 1 - (animationTime - fadeOutStartTime)
573 / (duration - fadeOutStartTime);
Wladimir Palant 2013/07/22 14:18:36 Pretty complicated and IMHO not really necessary c
Felix Dahlke 2013/07/22 15:10:22 It's not really possible to get smooth animations
Felix Dahlke 2013/07/22 15:16:45 But I definitely prefer how you approached the del
Wladimir Palant 2013/07/23 07:25:04 You don't have a smooth animation right now, exact
Felix Dahlke 2013/07/23 10:38:08 Implemented this as you prefer it, since it's not
574
575 context.clearRect(0, 0, canvas.width, canvas.height); 540 context.clearRect(0, 0, canvas.width, canvas.height);
576 context.globalAlpha = 1; 541 context.globalAlpha = 1;
577 context.drawImage(abpIcon, 0, 0); 542 context.drawImage(icon, 0, 0);
578 context.globalAlpha = opacity; 543 context.globalAlpha = opacity;
579 context.drawImage(notificationIcon, 0, 0); 544 context.drawImage(notificationIcon, 0, 0);
580 var imageData = context.getImageData(0, 0, canvas.width, canvas.height); 545 var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
581 546 chrome.pageAction.setIcon({tabId: tab.id, imageData: imageData});
582 chrome.tabs.getSelected(null, function(tab) 547
583 { 548 var interval;
584 chrome.pageAction.setIcon({tabId: tab.id, imageData: imageData}); 549 currentFrame++;
585 iconAnimationTimer = setTimeout(animationStep, animationInterval); 550 if (currentFrame < frameOpacities.length)
586 }); 551 {
552 var duration = 3000;
553 interval = duration / frameOpacities.length;
554 }
555 else
556 {
557 currentFrame = 0;
558 interval = 10000;
559 }
560 iconAnimationTimer = setTimeout(animationStep, interval);
587 } 561 }
588 animationStep(); 562 animationStep();
589 }); 563 });
590 } 564 }
591 565
592 function showInformationNotification() 566 function prepareNotificationIconAndPopup()
593 { 567 {
594 activeNotification.onClicked = function() 568 activeNotification.onClicked = function()
595 { 569 {
570 var tab = animatedIconTab;
596 stopIconAnimation(); 571 stopIconAnimation();
597 activeNotification = null; 572 activeNotification = null;
573 refreshIconAndContextMenu(tab);
598 }; 574 };
599 575
600 startInformationNotificationAnimation(); 576 chrome.windows.getLastFocused({populate: true}, function(window)
601 } 577 {
602 578 chrome.tabs.query({active: true, windowId: window.id}, function(tabs)
603 function showCriticalNotification() 579 {
604 { 580 tabs.forEach(refreshIconAndContextMenu);
605 var notification = webkitNotifications.createHTMLNotification("notification.ht ml"); 581 });
606 notification.show(); 582 });
607 } 583 }
608 584
609 function showNotification(notification) 585 function showNotification(notification)
610 { 586 {
611 activeNotification = notification; 587 activeNotification = notification;
612 588
613 if (notification.severity === "critical") 589 if (activeNotification.severity === "critical")
614 showCriticalNotification(); 590 {
591 var notification = webkitNotifications.createHTMLNotification("notification. html");
592 notification.show();
593 notification.addEventListener("close", prepareNotificationIconAndPopup);
594 }
615 else 595 else
616 showInformationNotification(); 596 prepareNotificationIconAndPopup();
617
618 chrome.tabs.getAllInWindow(null, function(tabs)
619 {
620 tabs.forEach(refreshIconAndContextMenu);
621 });
622 } 597 }
623 598
624 /** 599 /**
625 * This function is a hack - we only know the tabId and document URL for a 600 * This function is a hack - we only know the tabId and document URL for a
626 * message but we need to know the frame ID. Try to find it in webRequest's 601 * message but we need to know the frame ID. Try to find it in webRequest's
627 * frame data. 602 * frame data.
628 */ 603 */
629 function getFrameId(tabId, url) 604 function getFrameId(tabId, url)
630 { 605 {
631 if (tabId in frames) 606 if (tabId in frames)
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
751 }); 726 });
752 727
753 // Update icon if a tab changes location 728 // Update icon if a tab changes location
754 chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) 729 chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab)
755 { 730 {
756 chrome.tabs.sendRequest(tabId, {reqtype: "clickhide-deactivate"}) 731 chrome.tabs.sendRequest(tabId, {reqtype: "clickhide-deactivate"})
757 if(changeInfo.status == "loading") 732 if(changeInfo.status == "loading")
758 refreshIconAndContextMenu(tab); 733 refreshIconAndContextMenu(tab);
759 }); 734 });
760 735
736 // Refresh icon when switching tabs or windows
737 chrome.tabs.onActivated.addListener(function(activeInfo)
738 {
739 refreshIconAndContextMenu(animatedIconTab);
740 chrome.tabs.get(activeInfo.tabId, refreshIconAndContextMenu);
741 });
742 chrome.windows.onFocusChanged.addListener(function(windowId)
743 {
744 refreshIconAndContextMenu(animatedIconTab);
745 chrome.tabs.query({active: true, windowId: windowId}, function(tabs)
746 {
747 tabs.forEach(refreshIconAndContextMenu);
748 });
749 });
750
761 setTimeout(function() 751 setTimeout(function()
762 { 752 {
763 var notificationToShow = Notification.getNextToShow(); 753 var notificationToShow = Notification.getNextToShow();
764 if (notificationToShow) 754 if (notificationToShow)
765 showNotification(notificationToShow); 755 showNotification(notificationToShow);
766 }, 3 * 60 * 1000); 756 }, 3 * 60 * 1000);
LEFTRIGHT

Powered by Google App Engine
This is Rietveld