"Thou shalt not spam" or what are web notifications

Web notifications are one of the newer features added into modern browsers. They are intended as alerts for the user outside of the web page context. The idea is for them to be browsers and system independent, for example, when using a mobile browser notification could go into the home screen of the device. On the desktop usually they show up on the right-corner of the screen, at least on most desktop environments. They can be very annoying thing and you should think if thoroughly before you decide this is the right way to inform the users. There are some restrictions that avoid the creation of popup but I still have a bad feeling whenever I see one of these. One example of these notifications are the gmail/gtalk updates that show up on new messages (they are useful and annoying at the same time). This is done via the Notification API and we will do a simple example of its usage.

The implementation

First we can start with a simple wrapper for the Notification API that will have a fallback for the WebKit temporary implementation. We will define a simpleNotification object that will be the wrapper and it will contain a function called show that accepts data parameter. This data parameter is also a wrapper object that contains all the required info for a simple notification. For example :

var data = {
    icon: "http://upload.wikimedia.org/wikipedia/commons/7/7e/Jacob_de_Gheyn_-_Wapenhandelinge_4.jpg",
    title: "The Art of War - The Use of Spies ",
    body: "text",
    timeout : 7000,
    errorCallback: function(){
      $("#fallback").text(this.body);
    }
  };

Where the errorCallback is executed if non of our implementations are supported by the browser, as for the others, they should be self descriptive.

var simpleNotification = (function () {
   var my = {};
    my.show = function (data) {
     if (window.webkitNotifications) {
       //check if there is a support for webkitNotifications
       if (window.webkitNotifications.checkPermission() == 0) {
         var notification = webkitNotifications.createNotification(data.icon, data.title, data.body);
         notification.show();
         //set timeout to hide it
         setTimeout(function(){
             notification.cancel();
          }, data.timeout);
       } else {
         webkitNotifications.requestPermission(function () {
           //call the same function again
           my.show(data);
         });
       }
     }else if (window.Notification) {
   //Currently a fallback, but this should be the real implementation on all browsers
       if ("granted" === Notification.permissionLevel()) {
         var notification = new Notification(data.title, data);
         notification.show();
       } else if ("default" === Notification.permissionLevel() ) {
         Notification.requestPermission(function () {
           //call the same function again
           my.show(data);
         });
       }
     }else{
       //Notifications not supported,going with fallback
      data.errorCallback();
     }
   };
 return my;
}());

The standard based implementation is the one that uses window.Notification. An interface defined by W3C

  [Constructor(DOMString title, optional NotificationOptions options)]
  interface Notification : EventTarget {
    static readonly attribute NotificationPermission permission;
    static void requestPermission(optional NotificationPermissionCallback callback);

    attribute EventHandler onclick;
    attribute EventHandler onshow;
    attribute EventHandler onerror;
    attribute EventHandler onclose;

    readonly attribute NotificationDirection dir;
    readonly attribute DOMString lang;
    readonly attribute DOMString body;
    readonly attribute DOMString tag;
    readonly attribute DOMString icon;

    void close();
  };

Since our data object already contains similar values it can be passed directly in the instantiation of the Notification object. For example :

var notification = new Notification(data.title, data);

On the other hand window.webkitNotifications is the non-standard Chrome implementation. For a more detailed usage of the webkit version please see decadecity blogpost.

In order for us to be able to trigger the notification it is important in the html snippet to have some element that can be user triggered. We have some simple html containing a button

 <body>
   <button id="show">Show quote</button>
   <div id="fallback"> my fallback notification</div>
 </body>

This is needed in order to have request for the permission and to avoid “spam” notification. In our case this is the onClick function on the button. More specifically the jQuery click event. The call now is very simple, we just create the data object using some defaults and load some random data.

$(document).ready(function() {
    $("#show").click(function () {
      var data = {
        icon: "http://upload.wikimedia.org/wikipedia/commons/7/7e/Jacob_de_Gheyn_-_Wapenhandelinge_4.jpg",
        title: "The Art of War - The Use of Spies ",
        body: "text",
        timeout : 7000,
        errorCallback: function() {
          $("#fallback").text(this.body);
        }
      };
      var randomSampleId = Math.floor(Math.random()*sampleData.quotes.length)+1;
      var sample = sampleData.quotes[randomSampleId];
      for (var key in sample) {
        data.title += key;
        data.body = sample[key];
       }

      simpleNotification.show(data);
    });
});

The sample data used is a JSON containing quotes from “Sun Tzu -The Art of War” which is also available for for free on project gutenberg (win for public domain). The data is structured in the following format :

var sampleData = {
    quotes: [
     {
       "1": "Sun Tzu said: Raising a host of a hundred thousand men and marching them great distances entails heavy loss on the people and a drain on the resources of the State.The daily expenditure will amount to a thousand ounce of silver. There will be commotion at home and abroad, and men will drop down exhausted on the highways, As many as seven hundred thousand lies will be impededin their labor."
     },
     {
       "2": "Hostile armies may face each other for years, striving for the victory which is decided in a single day.This being so, to remain in ignorance of the enemy's condition simply because one grudges the outlay of a hundred ounces of silver in honors and emoluments, is the height of inhumanity."
     }
    ]
 };

One more thing to note is that Web Notifications were not supported by IE when this article was written.

You can play around with the jsfiddle to see it in action.

Related links

No comments: