Monday, February 27, 2012

Building Chrome Extensions From Scratch - Part 2

This is Part 2 of the series - Building Chrome Extensions From Scratch. In this part, we will continue from where we left off in the previous part.

As a quick recap, in Part 1, we covered

  1. The extension descriptor file - manifest.json
  2. How to define a default icon for a chrome extension that appears in the browser's toolbar.
  3. How to install a chrome extension from a local hard drive.

Our extension, whom we named Mr0, just had a name and a face. We used the manifest.json file to define the icon to be used as the default icon in the browser toolbar. But you may remember that there is one important component that I talked about in the previous post but did not discuss - the extension's background page.



A Brief Introduction

If the manifest.json file is the heart of the extension, then the background page can be aptly called the brain of the extension. Its like a Don that sits in the background and monitors its minions. The reason behind why I did not discuss it in the previous post was that in spite of its critical role in an extension, it is not mandatory for an extension to have a background page. Extensions are pretty simple beings. They don't need to think a lot in order to live. Hence, before we go ahead and talk more about the extension background page, lets see another aspect of the extension UI - the popup that appears when you click on an extension.



The Popup Page

Most of the extensions display a popup when you click on their icon in the browser toolbar. Taking our analogy a step further, we can safely assume that the popup that appears when you click on the extension icon is a the body of the extension. Unsurprisingly, the popup is nothing but another ordinary html page. And just like other html pages, you can write the usual CSS, markup and javascript. For instance, if you need to use jQuery, all you need to do is to keep the jquery.js file in your extension folder, and inside your popup, you can reference this file relatively.

In order to make use of a popup page, i.e. as a page that appears when the user clicks on the extension icon in the broswer toolbar, you need to specify the name of this html page in the manifest.json file. I am going to create a very simple html file called popup.html that says hello world. Below you can see the manifest file.

{
  "name": "Mr0",
  "version": "1.0",
  "browser_action": {
    "default_icon": "images/icon19.jpg",
 "default_popup": "popup.html"
 }
}

The manifest.json file has not changed much. The only new addition is to the the browser_action property list. We added a property called the default_popup and specified the page that we wanted to load when the user clicks on the extension icon.

Below is the code for our popup page. As you can see, I made use of the jquery library in the same old fashioned way.

 
  
 
 
  Hello World
 


Save these changes. Once you are done, click on the browser icon and you will see a neat little popup near the extension that says hello world. In case the popup does not appear, it may be because the browser did not pick up the changes. You can try clicking again once you have reloaded the extension from the extensions menu.



A Faulty Click Counter

Aint that just sweet! And wasnt it astonishingly simple? But we all know that webpages can never become truly cool unless we introduce a bit of javascript into the them. Lets just say that we want to create some sort of a counter. One that tells us the number of times that you have clicked on the button inside an extension.

Here's what you'd write (at first)
 
  
  
 
 
  
  


Now if you click on the browser icon, the popup will show you a button that which upon clicking, increments the value of the counter. Now, click somewhere else on the screen to let the popup disappear and then click on the icon again. Now you see the same popup, but notice that the counter starts counting from 0 again. But didn't we increment the coutner when we clicked on the button previously?

Yes, of course we did. However, as it turns out, whenever you click on an extension icon, the popup window gets reloaded. Which means that the counter is initialized to 0 each time we click on the browser icon because we are declaring the variable counter on pageload.

So what do we do in order to maintain a click counter? We need to find a way to maintain state over multiple clicks on the extension icon. We need to store our variables in a place which has a longer lifetime as compared to the popup page. Does it remind you about the http session? Well, if you guessed that we are going to store the counter value in a http session, you are quite wrong. Thats because we dont have any server! But then thats where background pages come to the rescue.



Extension Background Pages

An extension background page, as I briefly discussed earlier, is like a Don who sits in the background and can monitor its minions. Its more like an browser scope page i.e. that it is alive in the background for as long as the extension is acive in the browser. However you should create background pages for extensions only when needed because since a background page is after all nothing but a page, it adds to the memory footprint of the browser.

Coming back to creating our extension, in order to maintain the state of the counter when the user exits the popup window, you will need to store the current state of the variable inside the background page. This is where the chrome extension API's come into play. When you are inside the pages that are a part of the chrome extension, you have access to a set of javascript functions that allow you to do a lot of cool stuff. One of them is the ability to communicate between different pages of the same extension. In our case, we need a channel of communication between the popup page and the background page.

Here's what I want to do. When the user clicks on the extension icon
Check if the background page has a predefined value for the counter. If yes, save as the value of the counter in the popup page. Each time the user increments the counter, save its value in the background page.



Extension Message Passing

In order to send and receive messages in an asynchronous manner between pages and scripts and between background pages and other scripts, chrome has a predefined set of functions.

Send a message to a tab

chrome.tabs.sendRequest(tab.id, requestJSON, function(response) {
    //console.log(response);
  });

Send a message to a background page

chrome.extension.sendRequest(requestJSON, function(response) {
 //console.log(response');
});

Receive a message from either a tab or a background page

chrome.extension.onRequest.addListener(
  function(request, sender, sendResponse) {
    //console.log(sender.tab ?"from a content script:" + sender.tab.url :"from the extension");
    //console.log(request.sender?'Request from : ' + request.sender:'unknown');
    //sendResponse(responseJSON);
  });


As you see, there are three functions. The first one is used to send a request from any extension script(we will talk more about this soon) such as the on one the popup page to another extension script on the tab.
The second one lets any extension script send a request to the background page, which is actually the main page for the extension.
The next function is nothing but a listener for a request. The syntax is same whether the request comes from a script in a tab or from an extension.

As you can clearly see in the comments written inside each of these functions, you can send a response to the caller via the sendRespose function parameter and pass any information that might have been requested by the caller.

In our example, we are going make use of these functions to store the value of the variable in the background page and then retrieve the stored value whenever the user clicks on the browser icon of the extension before we increment it locally.



A Correct Click Counter

Before we begin writing the code, we first need to create a background page and keep it in the extension folder. And then we need to specify that page to be used as the background page in the manifest.json file.
I created a page called background.html and placed it in the chrome_ext folder. Here's how my manifest.json file looks now.

manifest.json
{
  "name": "Mr0",
  "version": "1.0",
  "background_page": "background.html",
  "browser_action": {
    "default_icon": "images/icon19.jpg",
 "default_popup": "popup.html"
 }
}


Then I modified the javascript code in the popup.html to look like this.

popup.html
$(function(){
 
 chrome.extension.sendRequest({action:'getCounter'}, function(response) {
  var counter = response.counterValue?response.counterValue:0;
  
  $('button.count').bind('click',function(){
   $('.counter-status').html(counter++);
   
   chrome.extension.sendRequest({action:'setCounter', counterValue:counter}, function(response) {
    console.log('response');
   });
   
  });
 
 });
 
});


Then in the background.html page, the following code will do the job for you.


background.html



Notice that I have placed the script of the background page inside the script tag. That's because, as I said earlier, the background page is also like a normal html page apart from the fact that it lives as long as the extension is alive and active in the browser.

Now, all you need to do is to reload your browser and when you click on the icon and click the counter, and repeat the same, the counter value will continue from the point where you previously left off.



In the next part of the series, we will take things a step further and try to make an extension that does more than just count clicks. Stay Tuned!

Happy Programming :)
Signing Off

Ryan

No comments: