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!

Tuesday, January 26, 2010

I'm a Semi-Published Author! (Closure: The Definitive Guide)

Today, I am officially a semi-published author in that the half of the book I am working on is available (for pay) online as part of O'Reilly's Rough Cuts program! The title is Closure: The Definitive Guide, and as you may have guessed, the aim is to create an (invaluable!) manual for the Closure Tools suite. When I am finished, the book will cover the Library, Templates, the Compiler, the Testing Framework, and the Inspector, though the six chapters that are available today are only on the Library. However, if you purchase the book through Rough Cuts, you will get the updates to the book as I publish them there, so it is more like buying a subscription than a book.

I am extremely excited about the Rough Cuts program because it allows me to get information out to you, the web developer, much faster than I could if I forced you to wait for the print version. It also gives you the opportunity to provide me with feedback to help ensure that the Guide contains the information that you need.

For those of you who have purchased a book via Rough Cuts before, you may be surprised to see how "rough" my book is compared to the other offerings. This is a fairly new program at O'Reilly, so the first books to go through Rough Cuts were not made available until a nearly complete draft of the book was done. By comparison, my book is half done and has gone through neither copy edit nor technical review. So when providing feedback, please bear in mind the staff at O'Reilly will ultimately help with things like the misuse of parallel structure, but I need your help in determining when something merits a code sample or more explanation.

The material that is currently available is:
  • Preface
  • Chapter 1: Introduction to Closure
  • Chapter 2: Annotations for Closure JavaScript
  • Chapter 3: Closure Primitives
  • Chapter 4: Common Utilities
  • Chapter 5: Classes and Inheritance
  • Chapter 6: Event Management
  • Appendix A: Inheritance Patterns in JavaScript
  • Appendix B: Frequently Misunderstood JavaScript Concepts
Although there is nothing that requires me to write the chapters in order, I was encouraged to start out that way in order to have something that would be well-connected for Rough Cuts readers. This meant that I had to draft the introduction earlier than I would have liked, but I am actually quite happy with what is there right now. Among other things, it contains a complete "Hello World" example that shows how to use all of the tools together, which is something I have yet to see on any blogs or even as part of Google's own documentation.

Currently, I am taking a break from writing more on the Library and am skipping a few chapters ahead to start focusing on the Compiler. As an active member of the Closure Google Groups, it is pretty clear to me that developers need more help in that area, so I hope to make that information available soon.

I also hope to improve Closure in the process of writing this book. When I run into things that I feel are hard to explain, sometimes I end up filing bugs or feature requests against Closure with proposed changes. It is so much easier to write a few paragraphs to report a bug than it is to draft several pages to explain away a quirk!

With 150 pages of content, I suspect I have given you enough to chew on while I put together more information on the Compiler. Please take a look and let me know what you think.

Update: Changed the book link from http://techbus.safaribooksonline.com/9781449381882 to http://my.safaribooksonline.com/9781449381882 where it is actually possible to purchase the book! There is a button that says "Purchase Options" on the upper-right.

Saturday, January 2, 2010

google.com uses AJAX to update search results in place?

My Gmail account appears to be in an experiment where searches from google.com update in place. That is, a search for bolinfest takes me to:

http://www.google.com/#hl=en&source=hp&q=bolinfest&aq=f&aqi=g10&oq=&fp=cbc2f75bf9d43a8f

Rather than the classic:

http://www.google.com/search?hl=en&source=hp&q=bolinfest&aq=f&oq=&aqi=g-p1g2

Apparently this was first reported in January 2009. There was immediately an outcry because the fragment (with includes the keywords used in the Google search) was not included in the referrer, so sites who analyze their traffic using that information were at a loss.

In my version of the experiment, this is no longer an issue because the search results use a URL redirector (which I do not believe is a new practice). Although the first search result is for www.bolinfest.com/, and when I hover over the link in Firefox, the status bar says http://www.bolinfest.com/, the actual destination of the link is:

http://www.google.com/url?sa=t&source=web&ct=res&cd=1&ved=0CAoQFjAA&url=http%3A%2F%2Fwww.bolinfest.com%2F&rct=j&q=bolinfest&ei=kYU_S8nZAdC0lAeJ0fmVBw&usg=AFQjCNEgHH2q8kppSggtQt45aSSazDTynA&sig2=G54nS0q_UtfEChH7icC_NA

When I follow the link and run javascript:alert(document.referrer) in the address bar, I see the same thing:

http://www.google.com/url?sa=t&source=web&ct=res&cd=1&ved=0CAoQFjAA&url=http%3A%2F%2Fwww.bolinfest.com%2F&rct=j&q=bolinfest&ei=kYU_S8nZAdC0lAeJ0fmVBw&usg=AFQjCNEgHH2q8kppSggtQt45aSSazDTynA&sig2=G54nS0q_UtfEChH7icC_NA

Note that this URL contains the query in the URL parameter q=bolinfest, which should appease those who are concerned with keyword tracking.

What is interesting is that the AJAX request to load the search results appears to be an ordinary GET request to:

http://www.google.com/search?hl=en&q=bolinfest&aq=&aqi=g2&oq=bolinfest&fp=cbc2f75bf9d43a8f

The content of that URL is an HTML page with 21 <script> tags in the <head> and an empty <body> tag.

Also, copying and pasting http://www.google.com/#hl=en&source=hp&q=bolinfest&aq=f&aqi=g10&oq=&fp=cbc2f75bf9d43a8f into the address bar of a new tab works as expected (though I do get a JavaScript error when I paste the URL into a new tab that I do not get when doing the initial search from google.com).

It's hard to say what this really means, if anything. Presumably, Google's objective is to make search results load faster without pissing off advertisers. As I'm not in the SEO racket, I'm not terribly interested in the latter, but I am curious whether Google is on to a new technique for loading web content faster!

Monday, December 21, 2009

Closure Lite - Just in time for Christmas!

When I was an undergrad at MIT, the end of the fall semester meant I had about 5 weeks of freedom to hack on stuff before the start of the spring semester. At MIT, instead of starting classes back up in January, they have what is called the Independent Activities Period (IAP). Although IAP is optional, many students return for it (except the Hawaiians I knew, who generally decided to stay home in their tropical paradise during one of the coldest months in Boston) because there are so many great opportunities: you can get scuba certified, do research, or my personal favorite -- engage in programming competitions!

For you holiday hackers who haven't found the time to play around with Closure yet, I've tried to make it a little easier to get started by creating Closure Lite. Closure Lite is a single JavaScript file that you can include on a web page to start using a subset of the Closure Library. This is similar to the approach used by other popular JavaScript libraries such as jQuery. But as the Closure Lite documentation explains, although Closure Lite is a good way to start learning the Library, it is recommended to learn and use the Closure Compiler on your production JavaScript.

I hope that both Closure and Closure Lite are useful to MIT students who are competing in 6.470 this IAP!

Wednesday, December 9, 2009

Check out Speed Tracer (it's not just for GWT applications!)

Last night, Google hosted a Campfire One event introducing Google Web Toolkit (GWT) 2.0. The Campfire event is divided into six segments that are all available on YouTube.



If you do not feel like watching the entire presentation (it's a little over an hour), I recommend watching Parts 3 and 5. In Part 3, Bruce Johnson discusses GWT's JavaScript compiler (which is different from the Closure Compiler) and GWT 2.0's new code splitting feature. From the presentation, it sounds like the GWT compiler has added some of the optimizations that the Closure Compiler has had for some time. (I've heard of instances of the Closure Compiler reducing compiled code from GWT by 20%, so clearly there was room for improvement.) Historically, the GWT and Closure compilers were separate codebases because one was open-sourced and the other was not, but since that is no longer the case, perhaps we will see some convergence in the future. I wouldn't hold my breath, though.

But what was more impressive was the ease with which GWT was able to introduce code-splitting. That is, dividing up a large JavaScript file into smaller files, the majority of which get loaded asynchronously by the application as the features that depend on them are accessed. The Closure Compiler has support for such a feature, but it is undocumented and requires a bit of work by the developer, even if he knows what he is doing. The code-splitting feature in GWT 2.0 (introduced about 10 minutes into Part 3) is much more elegant and straightforward. I hope that the Closure Tools suite evolves to make this just as simple.

Then in Part 5, Kelly Norton introduces Speed Tracer, which is a Chrome extension that gives an unprecedented amount of insight into what Chrome is doing when it runs a web application. It is more similar to dynaTrace than it is to Firebug. Page Tracer is informative and so snappy that you might not believe the UI is written in HTML5 -- try it out!

However, my one gripe with the Campfire presentation is that you might come away from it believing that Speed Tracer works only with GWT applications, but that is not the case at all! Although its documentation lives under GWT on code.google.com and Speed Tracer was written using GWT, it can be downloaded and used completely independently from GWT. This morning, I installed it to explore the performance of some webapps I used to work on (which were written using Closure), such as Google Tasks. (I found some areas for improvement which I forwarded to the team.) I strongly recommend evaluating your own web applications using Speed Tracer as you may be surprised at what you discover.

Also, if you're like me, you may not notice the links to additional Speed Tracer documentation because they appear below the fold on the landing page. Under the Tools heading in the left-hand-nav, there are links to Hints, the Data Dump Format, and the Logging API.

If you stop and think about it, this level of tool support is essential for the Chrome OS initiative to succeed. If the browser is going to substitute for the desktop as a platform, then it must be fast (which is where Chrome comes in), it needs to have a kickass API (which is where HTML5 comes in), and it needs to have best-of-breed developer tools (which is where GWT, Closure, and Speed Tracer come in) so it is possible to build web applications that can compete with (and ideally exceed) desktop applications. When Chrome OS was originally announced, I was a naysayer, but now that more of the pieces are starting to come together, I'm getting a bit more optimistic.

Monday, November 23, 2009

Practical Chickenfoot Presentation

Today I gave a guest lecture on Chickenfoot to Monzy's course on mashups at NYU's Tisch School of the Arts. The presentation is available online as a Google Doc. Unlike previous talks on Chickenfoot, this one focused on practical examples of how to use it rather than the research behind it. This was a nice change because I actually got to sit down with a classroom full of first-time users of Chickenfoot as they went through the exercises. Thanks to Monzy and his students at ITP for having me!

Wednesday, November 18, 2009

Example of using Closure Compiler to attain an 85% improvement over YUI Compressor when minifying Closure Library code

For those of you who do not care about caveats or grains of salt: here is my test showing Closure Compiler beating YUI Compressor by 85% when compiling a simple JavaScript file that uses a widget from the Closure Library.

I chose the title of this blog post very carefully: I do not claim that the Closure Compiler will always minify 85% better than YUI Compressor, and I wanted to make it clear that the dramatic results are specific to Closure Library code which is written in a style that was designed to be minified by the Closure Compiler. Although both tools can be used independently, they were meant to be used together.

That is not to say that other libraries cannot get dramatic minification benefits from the Compiler -- they can! But doing so requires following the style guidelines explained in the Advanced Compilation and Externs article on the Google Code web site.

And even if you think my test is unfair, or that I rigged it to butcher the YUI Compressor, I hope you can at least benefit from these two code samples that came out of creating these tests: