#summary Case study: Gmail View Watcher #labels Featured This example script demonstrates how to load and reference the `gmonkey` bindings exposed by the [GmailGreasemonkey10API Gmail Greasemonkey API]. It will add a navigation box to the left-hand pane in Gmail that updates with the name of the current view. = Code = You can install this script here: [http://gmail-greasemonkey.googlecode.com/svn/trunk/scripts/gmail-view-watcher.user.js gmail-view-watcher.user.js] (requires [https://addons.mozilla.org/en-US/firefox/addon/748 Greasemonkey]) {{{ // Copyright (c) 2007, Google Inc. // Released under the BSD license: // http://www.opensource.org/licenses/bsd-license.php // // ==UserScript== // @name Gmail View Watcher // @namespace http://mail.google.com/ // @description Adds a nav box to Gmail which monitors the current view. // @include http://mail.google.com/* // @include https://mail.google.com/* // ==/UserScript== window.addEventListener('load', function() { if (unsafeWindow.gmonkey) { unsafeWindow.gmonkey.load('1.0', function(gmail) { function setViewType() { var str = ''; switch (gmail.getActiveViewType()) { case 'tl': str = 'Threadlist'; break; case 'cv': str = 'Conversation'; break; case 'co': str = 'Compose'; break; case 'ct': str = 'Contacts'; break; case 's': str = 'Settings'; break; default: str = 'Unknown'; } module.setContent(str); } var module = gmail.addNavModule('View Monitor'); gmail.registerViewChangeCallback(setViewType); setViewType(); }); } }, true); }}} = Code walkthrough = First, we need some Greasemonkey metadata to define where this script will run. We want to run on `mail.google.com/*` on both HTTP and HTTPS. This will catch normal Gmail accounts, as well as domain-specific Gmail accounts (i.e. [https://www.google.com/a/ Google Apps For Your Domain]). To learn more about Greasemonkey metadata, see [http://diveintogreasemonkey.org/helloworld/metadata.html Dive Into Greasemonkey: Describing your user script with metadata]. {{{ // ==UserScript== // @name Gmail View Watcher // @namespace http://mail.google.com/ // @description Adds a nav box to Gmail which monitors the current view. // @include http://mail.google.com/* // @include https://mail.google.com/* // ==/UserScript== }}} The first thing you must always do before using the [GmailGreasemonkey10API Gmail Greasemonkey API] is to load the API. For performance reasons, it is not loaded for all users; your user script must explicitly request it. {{{ window.addEventListener('load', function() { if (unsafeWindow.gmonkey) { unsafeWindow.gmonkey.load('1.0', function(gmail) { // Use local reference to *gmail* object }); } }, true); }}} Our inline function is called when the API is successfully loaded. Within the callback function, the `gmail` object is a reference to a [GmailGreasemonkey10API GmailAPI object]. Now we can get down to business. {{{ function setViewType() { var str = ''; switch (gmail.getActiveViewType()) { case 'tl': str = 'Threadlist'; break; case 'cv': str = 'Conversation'; break; case 'co': str = 'Compose'; break; case 'ct': str = 'Contacts'; break; case 's': str = 'Settings'; break; default: str = 'Unknown'; } module.setContent(str); } }}} Within our callback function, we define another function called `setViewType`. The `setViewType` function calls the Gmail-specific method `getActiveViewType` to determine where in the Gmail interface the user is at the moment. The switch statement contains an exhaustive list of all possible values for the active view type, and it simply uses these values to set a simple human-readable string that describes the active view. This code is a little confusing until you look at what comes next -- this "inner" function actually references a variable named `module` that is defined in the outer callback function. Let's see what that is: {{{ var module = gmail.addNavModule('View Monitor'); }}} Aha! The `module` object is actually returned from another Gmail-specific method, `addNavModule`. The `gmail.addNavModule` method creates a new navigation box in the left-hand pane of Gmail. This new navigation box works just like the built-in Labels box or Google Talk box (if you are using Gmail + chat in a supported browser). Each navigation box has a title, a colored border, and a collapso/expando toggle button. Inside the navigation box you can display arbitrary HTML content. In this case, we are only setting the title, which is passed as the first argument to the `gmail.addNavModule` method. OK, so we have a titled navigation box, but it doesn't change its content based on the current view. In fact, it doesn't ever display anything inside the box at all. Thus the next step is to register our `setViewType` function as a callback that gets called whenever the active view changes. {{{ gmail.registerViewChangeCallback(setViewType); }}} Now the `setViewType` callback function will be called whenever the user changes from one view to another: from the Inbox to a conversation, or from a conversation back to the Inbox, or to composing a new message, and so forth. Whenever that happens, the `setViewType` is called without arguments, but that's OK. Because of Javascript's scoping rules, we can still access the `gmail` object (which was originally passed as a parameter to the callback function from `gmonkey.load`) and the `module` object (which was defined as a local variable in the function that contains the `setViewType` function. So we have all the context we need to access the Gmail Greasemonkey API and our custom navigation box. There's just one thing missing: when Gmail first loads, our navigation box will be empty until the user changes to a different view. We need to manually call our `setViewType` function once on startup, so it displays the current view type immediately. {{{ setViewType(); }}} And that's all she wrote! = Screenshots = Our custom navigation box is displayed at the bottom of the left-hand pane in Gmail. It is titled "View Monitor". In the Gmail Inbox, the current view type is `"tl"`, which our `setViewType` function displays as `Threadlist`. Yes, I really have 35,486 spam messages. http://gmail-greasemonkey.googlecode.com/svn/trunk/screenshots/gmailviewwatcher-inbox.jpg If you click "Compose Mail", Gmail displays the message composition form. Because we called `gmail.registerViewChangeCallback` with our `setViewType` function, our "View Monitor" navigation box automatically changes its display to `Compose` (view type `"co"`). http://gmail-greasemonkey.googlecode.com/svn/trunk/screenshots/gmailviewwatcher-compose.jpg If you click "Contacts", Gmail displays your contact list, and our navigation box automatically changes to `Contacts` (view type `"ct"`). http://gmail-greasemonkey.googlecode.com/svn/trunk/screenshots/gmailviewwatcher-contacts.jpg = Further reading = * [GmailGreasemonkey10API Gmail Greasemonkey API] * [http://diveintogreasemonkey.org/helloworld/metadata.html Dive Into Greasemonkey: Describing your user script with metadata]