Infrequently Noted

Alex Russell on browsers, standards, and the process of progress.

back, and stuff

So I'm going to try to avoid the obligitory "wasn't SxSW fun!?" post and just breifly mention that Ping has a new blog on usable security.

I can't say how incredibly happy I am to see this kind of work being opened up to a more general audience.

dojo browserio profile package and article

After months of work, I'm happy to announce the first releaes of a Dojo package. This package contains ONLY what is necessaray to support our XMLHTTP wrapper and it's generic bind() API.

The package is available at:

http://dojotoolkit.org/dojo_browserio.tar.gz


An article that is being released as part of the package is also available separately here.

Jennifer blogs!

Jennifer has a new blog! w00t!

sooooooo geeky

I'm somewhere just south of Burlingame as I write this, on my way to work just as fast as CalTrain will take me. Now, it's not unusual for me to be working or blogging or hacking on projects on the train, but it IS unusual for me to have network access at the same time. Thanks to bluetooth, a small hack for my new Treo and an all-you-can-eat data plan from Sprint, I think it's going to be less unusual.

When Sprint first rolled out their CDMA 1xRTT service ("vision" in sprintspeek), I bought a Samsung A620 phone and accompanying data cable to take full advantage of the then-new service. My mobile life was pretty good given that I tunnel everything over a personal VPN connection to avoid Sprint's lame http proxy. Then I moved to California and, somehow, mysteriously, my 1xRTT just stopped working. Not only could I not make a handset call to "#777" and receive a modem connection string, I couldn't even get the darn thing to work over the cable.

Grumble.

Eventually, I got used to being disconnected on the train, and it is one of my most productive times of the day, but that doesn't mean that I don't want my mobile computing nirvana back. So I took the plunge on a Treo650. Sprint (and, it seems, Cingular) have dissabled the DUN profile in the bluetooth configuration menus of their Treo650s, but some enterprising person provided a hack to re-enable the feature. The DUN profile allows you to use your Treo as a modem for your laptop over bluetooth, and when combined with the 1xRTT data service, a connection that doesn't use my phone minutes or require another ISP. The upshot is that now, in addition to being able to sync my treo wirelessly, I can use it as a data connection wirelessly too. It's SOOOO geeky, and yet it gives me that warm fuzzy "I can check code in from anywhere" feeling.

Horray for technology, even if it does arrive 5-10 years later than we expected it would.

in defense of the "back" button

The back button is one of those things that until recently I've considered an unfortunate casualty of the move from web pages to DHTML/CADEX applications. location.replace() and the history-less behavior of XMLHTTP have elicited foot-shuffling, eye-averting mumbling from people building responsive UIs when asked "what about the back button?". That the back button nukes all of a user's progress through an application has been a small point of collective shame. Wouldn't it be great if there were some way to cause the back-button to fire off some sort of callback within the UI instead of obliterating it?

Lo-and-behold, we have a solution! ()

Before I get into the nitty gritty of how this all works, let me provide a demonstration of the way you'd invoke this capability in Dojo. A normal call to get some data in Dojo often looks like:

dojo.io.bind({
url: "sampleData.txt",
load: function(type, data, evt){ alert(data); },
error: function(type, errObj){ alert(errObj.message); }
});


dojo.io.bind() takes an anonymous object consisting of properties required for making an asynchronous request as well as functions that are useful for reporting back success or failure thereof. In normal operation within a browser, this call won't ever add anything to the history, so when the user hits the back button, away we go to wherever the current application was linked from. Here's the same request, but with a callback registered that will be called when the user hits "back", instead of the previous "nuking" behavior:

dojo.io.bind({
url: "sampleData.txt",
load: function(type, data, evt){ alert(data); },
error: function(type, errObj){ alert(errObj.message); },
backButton: function(){ alert('the back button was intercepted, the document should not unload'); }
});


How it works:

After discussing the problem with Aaron, I thought I'd try a quick, naive implementation that just allowed me to intercept the back button. Who cares if actually does anything for the purposes of a prototype, right? Boy was I in for a ride.

Unbeknownst to me, browsers seem to keep two sets of history list: one that's the visible set of top-level pages visited, and another set that includes any transitions between iframes. The first set is exposed via drop-down lists from the back button and the like. The second set, while not exposed to the user, is actually what one cycles through when moving back and forth with forward and backward buttons. But not if the iframe that's doing the navigating was created after the page calls onload. This "property" alone took hours to debug, but once Aaron sent me a minimal static HTML page that added an entry to the forward-back buttons by changing an iframe, I had one of those slap-your-forehead moments and it all made sense.

Turns out that there's NO way to create an iframe after onload that will affect the forward-back history as far as I can tell. Unlike a lot of other dynamically created iframe bugs (and lordy, are there a lot of 'em), this seems to be true across IE and Firefox. As a result, Dojo now does a document.write() to create an invisible iframe when the required bootstrap files are being loaded, since they are the only files that are guaranteed to be pulled in with a <script> tag.

Once that is done, we continually load the same file in this iframe (blank.html) but provide it with an ever-changing query string (keyed on millisecond time). This file calls back up to the parent environment whenever it is loaded in the iframe, and so we can determine when a new document has been loaded and based on whether or not we requested a new document, whether or not this was due to a press of the back button. Aaron has suggested that I post a stand-alone package of this code, but I don't know that breaking it out from Dojo is really that useful. If you want this feature in a stand alone package, comment here or send me mail.

Despite this advancement in the state of usability, my current code doesn't correctly handle subsequent forward button requests or the bookmarking of particular states in an application (think "checkpointing"). Aaron and I have discussed possible solutions, but until I have working code I'm reluctant to post descriptions of how it might be done. The good news for everyone is that these problems are looking more and more solveable for the great majority of browsers. The back button no longer need be a tactial nuke that gets dropped into our apps.

We can finally make peace with our inner usability demons.

The technique presented here only works on IE and Mozilla/Firefox as of this writing. I'm still looking for ways to cajole Safari into a similar behavior, and Opera is untested to date.