Sunday, February 21, 2010

New Firefox Extension: Fullscreen Tasks in Gmail

I know that when you have a lot of things to do, using Tasks in the cramped space within Gmail or Calendar may seem frustrating. There is actually a great workaround, which is to use the fullscreen version of the Tasks iGoogle gadget available at https://mail.google.com/tasks/canvas. Unfortunately, few people seem to know about it even though it was posted on the Gmail blog back in October.

My new extension simply adds a link in the sidebar that makes it possible to bring up the fullscreen version of Tasks in an iframe without leaving Gmail:



You can download the extension from http://bolinfest.com/chickenscratch/fullscreen-tasks-in-gmail.xpi. For some reason, you need to install it by first downloading it and then using the File -> Open File... menu in Firefox to open it up and install it. The traditional method of installing, which is just going to the URL in Firefox, does not seem to work for some reason: I get some nonsense about it not being a valid install package.

Because I thought this was going to be a short script, I originally tried to write it in Greasemonkey because I feel like it is easier to get users to install Greasemonkey scripts than separate extensions these days. Initially I tried using the Gmail Greasemonkey API, but unfortunately it is super-busted: many of the methods in the API do not work right now.

Then I considered looking under the hood of Gmail and trying to use XPaths, but those were nightmarish and would be likely to break, so I decided that I really needed some of the primitives in Chickenfoot to grab the appropriate DOM elements. For example, to display Tasks, I need to hide the threadlist and insert my iframe. In Chickenfoot, I came up with a fairly good heuristic:
  var n1 = find('first select all').element;
var n2 = find('second select all').element;
if (!n1 || !n2) {
return false;
}
ancestor = goog.dom.findCommonAncestor(n1, n2);
dom = goog.dom.getDomHelper(ancestor);

This essentially finds the DOM element for each of the "Select: All" controls that appear above and below the threadlist, and uses their common ancestor as the node to hide to make room for my Tasks iframe.

If you are interested, the code for the Chickenfoot script is also available. In creating the extension, I ended up fixing some bugs in Chickenfoot, but also added some new features, so when Chickenfoot 1.0.8 is released, it will be possible to run my script as-is. One new feature is that Closure Lite will be available as a library in Chickenfoot, so with the include('closure-lite.js') call in Chickenfoot, lots of goog goodness will be readily available, which made the development of this script go so much faster.

For a script that should be so easy to write, it may be surprising that it is over 100 lines long. Much of this is because I tried to include a number of features that should make the extension easier to use:
  • Keyboard shortcut that works when either the threadlist or the Tasks iframe have focus.
  • Tooltip to make the keyboard shortcut more discoverable.
  • Logic to ensure that the style of the "Full Tasks" link matches that of your Gmail theme.
  • Focus is given back to the threadlist when exiting fullscreen Tasks.
  • The Tasks iframe is resized when the browser window is resized.
  • Timing logic to account for the fact that many things in Gmail are loaded asynchronously.
I bring this up not just to toot my own horn, but to comment on something that I recently read about in Coders at Work that Kushal recently touched upon on his blog as well, which is the idea of the "empathy gene". (Some bloggers misattribute the phrase to Josh Bloch because he brings it up in his interview in Coders at Work, but Bloch actually attributes the phrase to Kevin Bourrillion during the interview.)

I think it's particularly relevant in this example because most userscripts that I have looked at are pretty hacky pieces of code. This is partially because most userscripts are viewed as hacks in the first place, though there is nothing about writing userscripts that forces them to be that way. For example, with my new extension, there are a million ways I could have chosen to jam a Tasks iframe into Gmail, most of which would have taken many fewer lines of code. But to make something reliable, thoughtful, and usable took a lot more code than that. I like to think that this is my empathy gene at work.

An even better example of non-hacky Greasemonkey scripts are those written by Mihai. Mihai clearly has the empathy gene, which is one of the reasons why Google Reader is such a great product. (Though even an empathetic guy like Mihai has been known to ruin Christmas every once in awhile -- oops!)

Finally, although I enjoyed creating this extension and am glad that I also made improvements to Chickenfoot in the process, I would be even happier if this feature (or something like it) were made available in Gmail (I'm looking at you, Mountain View!). Though if Tasks were able to "graduate" into the navigation bar in the top of the page that is available across all apps, that would solve most of my problems. It may be time to update iGoogleBar to do exactly that!