Creating Browser Actions
Next let's create a browser action. Unlike our Hacker News extension, which affects only that website, browser actions affect all or most websites. For this example, we're going to create a lightweight note-taking extension. We'll be requesting two permissions:
- The tabs permission allows us to inject content scripts (JavaScript and CSS files that operate inside a browser tab) to do our work.
- The notifications permission allows us to use Chrome's notification system.
Because it's visible on the browser bar, we should add an icon and some title text to represent our action. The last parameter in this snippet, popup.html, denotes the page that will appear when someone clicks the icon.
"permissions" : [ "tabs", "notifications" ], "browser_action" : { "default_icon" : "icon.png", "default_title" : "Take a Note", "default_popup" : "popup.html" },
The code below shows that the content script will apply to all sites:
"background" : { "scripts" : ["background.js"] }
Creating the Pop-Up Page
The HTML code for our pop-up page is relatively simple. We have a label, a text area, and several buttons, as shown in the following snippet. (A JavaScript file is also associated; we'll discuss that in a moment.)
<!DOCTYPE html> <html> <head> <script src="popup.js"></script> </head> <body> <label for="note">Note about site: <span id="sitename"></span></label> <textarea name="note" rows="5" cols="80"></textarea> <button id="save">Save</button> <button id="delete">Delete</button> </body> </html>
Adding the JavaScript Logic
Most of the logic for our extension lives in popup.js, so let's go over it chunk by chunk. Our outermost function below instructs the function to be executed only after the Document Object Model (DOM) has loaded:
document.addEventListener("DOMContentLoaded", function() { //... code });
The next inner function is exposed by the chrome.tabs permission. It grabs the currently selected tab so that we can retrieve the URL that's currently displayed:
chrome.tabs.getSelected(null, function(tab) { //... code });
Once we have the tab's URL, we populate the sitename field in our pop-up page and check localStorage for an associated entry. localStorage is a simple key-value store that allows us to store data that will persist between sessions. You might notice that the call to localStorage references the background page. The reason is that while the pop-up page is created and purged on demand, the background page and its data persist for the life of the extension, until the browser cache is purged.
document.querySelector('#sitename').innerHTML = tab.url; window.siteurl = tab.url; // Load current note, if any; notes are stored on background page var text = chrome.extension.getBackgroundPage().localStorage[window.siteurl]; if (text != undefined) document.querySelector('[name=note]').value = text; });
Finally, we need to wire up the actions for our Save and Delete buttons. When one of the buttons is clicked, we save or delete the data, execute a call to surface a notification, and then close the pop-up.
There are two things to note here:
- Saving the value to localStorage doesn't require a call to the background page, unlike retrieving from localStorage, which does require a call. For better readability and error avoidance, you probably should call chrome.extension.getBackgroundPage() in both cases, but it's not required.
- The other notable thing is that we call to the background page for the notification.
// Save button document.querySelector("#save").addEventListener("click", function() { var text = document.querySelector('[name=note]').value; localStorage[window.siteurl] = text; // Fire off notification chrome.extension.getBackgroundPage().notify("Note saved."); window.close(); }); // Delete button document.querySelector("#delete").addEventListener("click", function() { var text = document.querySelector('[name=note]').value; chrome.extension.getBackgroundPage().localStorage.removeItem(window.siteurl); // Fire off notification chrome.extension.getBackgroundPage().notify("Note deleted."); window.close(); });
The reason we need to call the background page to create the notification is that we want it to disappear after a certain interval. If we create the notification in the pop-up page (or its JavaScript file) instead of the background page, as shown in the snippet below, we would destroy the timer before it gets a chance to finish.
function notify(msg) { var notification = webkitNotifications.createNotification( "", "Note Status.", msg ); notification.show(); window.setTimeout(function() {notification.cancel();}, 5000); }
We've created a simple desktop notification by specifying an optional image, title, and message text. Though not shown here, another variant can show an HTML page as the content of the notification. Here's the signature for that variant:
webkitNotifications.createHTMLNotification("url of page")
You can check out the final version of the source code here.