| Index: background.js | 
| =================================================================== | 
| --- a/background.js | 
| +++ b/background.js | 
| @@ -33,6 +33,7 @@ | 
| var Prefs = require("prefs").Prefs; | 
| var Synchronizer = require("synchronizer").Synchronizer; | 
| var Utils = require("utils").Utils; | 
| +var Notification = require("notification").Notification; | 
|  | 
| // Some types cannot be distinguished | 
| RegExpFilter.typeMap.OBJECT_SUBREQUEST = RegExpFilter.typeMap.OBJECT; | 
| @@ -133,6 +134,9 @@ | 
| else | 
| showContextMenu(); | 
| } | 
| + | 
| +  if (activeNotification) | 
| +    setNotificationPageAction(tab); | 
| } | 
|  | 
| /** | 
| @@ -473,6 +477,152 @@ | 
| } | 
| } | 
|  | 
| +var activeNotification; | 
| + | 
| +function loadImages(imageFiles, callback) | 
| +{ | 
| +  var images = {}; | 
| +  imageFiles.forEach(function(imageFile) | 
| +  { | 
| +    var image = new Image(); | 
| +    image.src = imageFile; | 
| +    image.addEventListener("load", function() | 
| +    { | 
| +      images[imageFile] = image; | 
| +      if (Object.keys(images).length === imageFiles.length) | 
| +        callback(images); | 
| +    }); | 
| +  }); | 
| +} | 
| + | 
| +function startInformationNotificationAnimation() | 
| +{ | 
| +  var abpIconFile = "icons/abp-19.png"; | 
| +  var notificationIconFile = "icons/notification-information.png"; | 
| +  var iconFiles = [abpIconFile, notificationIconFile]; | 
| +  loadImages(iconFiles, function(images) | 
| +  { | 
| +    var abpIcon = images[abpIconFile]; | 
| +    var notificationIcon = images[notificationIconFile]; | 
| +    var canvas = document.createElement("canvas"); | 
| +    canvas.width = abpIcon.width; | 
| +    canvas.height = abpIcon.height; | 
| +    var context = canvas.getContext("2d"); | 
| + | 
| +    var animationStartTime = Date.now(); | 
| +    var animationInterval = 1000 / 60; | 
| +    function animationStep() | 
| +    { | 
| +      var timeElapsed = Date.now() - animationStartTime; | 
| +      var duration = 3000; | 
| +      var animationTime = timeElapsed % duration; | 
| +      var delay = 1000; | 
| +      var fadeInEndTime = duration / 2 - delay / 2; | 
| +      var fadeOutStartTime = fadeInEndTime + delay; | 
| + | 
| +      var opacity; | 
| +      if (animationTime < fadeInEndTime) | 
| +        opacity = animationTime / fadeInEndTime; | 
| +      else if (animationTime > fadeOutStartTime) | 
| +        opacity = 1 - (animationTime - fadeOutStartTime) | 
| +          / (duration - fadeOutStartTime); | 
| + | 
| +      context.clearRect(0, 0, canvas.width, canvas.height); | 
| +      context.globalAlpha = 1; | 
| +      context.drawImage(abpIcon, 0, 0); | 
| +      context.globalAlpha = opacity; | 
| +      context.drawImage(notificationIcon, 0, 0); | 
| +      var imageData = context.getImageData(0, 0, canvas.width, canvas.height); | 
| + | 
| +      chrome.tabs.getSelected(null, function(tab) | 
| +      { | 
| +        chrome.pageAction.setIcon({tabId: tab.id, imageData: imageData}); | 
| +        activeNotification.animationTimer = | 
| +          setTimeout(animationStep, animationInterval); | 
| +      }); | 
| +    } | 
| +    animationStep(); | 
| +  }); | 
| +} | 
| + | 
| +function showInformationNotification() | 
| +{ | 
| +  activeNotification.onClicked = function() | 
| +  { | 
| +    clearTimeout(activeNotification.animationTimer); | 
| +    chrome.tabs.getAllInWindow(null, function(tabs) | 
| +    { | 
| +      tabs.forEach(refreshIconAndContextMenu); | 
| +      activeNotification = null; | 
| +    }); | 
| +  }; | 
| + | 
| +  startInformationNotificationAnimation(); | 
| +} | 
| + | 
| +function showCriticalNotification() | 
| +{ | 
| +  var notification = webkitNotifications.createHTMLNotification("notification.html"); | 
| +  notification.show(); | 
| +} | 
| + | 
| +function setNotificationPageAction(tab) | 
| +{ | 
| +  if (activeNotification.severity !== "critical") | 
| +    return; | 
| + | 
| +  var abpIconFile = "icons/abp-19.png"; | 
| +  var notificationIconFile = "icons/notification-critical.png"; | 
| +  var iconFiles = [abpIconFile, notificationIconFile]; | 
| +  loadImages(iconFiles, function(images) | 
| +  { | 
| +    var abpIcon = images[abpIconFile]; | 
| +    var notificationIcon = images[notificationIconFile]; | 
| +    var canvas = document.createElement("canvas"); | 
| +    canvas.width = abpIcon.width; | 
| +    canvas.height = abpIcon.height; | 
| +    var context = canvas.getContext("2d"); | 
| +    context.clearRect(0, 0, canvas.width, canvas.height); | 
| +    context.drawImage(abpIcon, 0, 0); | 
| +    context.drawImage(notificationIcon, 0, 0); | 
| +    var imageData = context.getImageData(0, 0, canvas.width, canvas.height); | 
| +    chrome.pageAction.setIcon({tabId: tab.id, imageData: imageData}); | 
| +  }); | 
| +} | 
| + | 
| +function showNotification(notification) | 
| +{ | 
| +  activeNotification = notification; | 
| + | 
| +  if (notification.severity === "critical") | 
| +    showCriticalNotification(); | 
| +  else | 
| +    showInformationNotification(); | 
| + | 
| +  chrome.tabs.getAllInWindow(null, function(tabs) | 
| +  { | 
| +    tabs.forEach(setNotificationPageAction); | 
| +  }); | 
| +} | 
| + | 
| +function getLocalizedTexts(notification) | 
| +{ | 
| +  return Notification.getLocalizedTexts(notification); | 
| +} | 
| + | 
| +function getDocLinks(notification) | 
| +{ | 
| +  if (!notification.links) | 
| +    return []; | 
| + | 
| +  var docLinks = []; | 
| +  notification.links.forEach(function(link) | 
| +  { | 
| +    docLinks.push(Utils.getDocLink(link)); | 
| +  }); | 
| +  return docLinks; | 
| +} | 
| + | 
| /** | 
| * This function is a hack - we only know the tabId and document URL for a | 
| * message but we need to know the frame ID. Try to find it in webRequest's | 
| @@ -609,3 +759,10 @@ | 
| if(changeInfo.status == "loading") | 
| refreshIconAndContextMenu(tab); | 
| }); | 
| + | 
| +setTimeout(function() | 
| +{ | 
| +  var notificationToShow = Notification.getNextToShow(); | 
| +  if (notificationToShow) | 
| +    showNotification(notificationToShow); | 
| +}, 3 * 60 * 1000); | 
|  |