Offline Events


Another feature that’s coming along, into Firefox 3, from the WHATWG Web Applications 1.0 spec is that of Online/Offline events. This feature serves as the second piece to the “Offline Web Application” puzzle (The first being DOM Storage), that’s really coming into place in Firefox 3.

What is the purpose of offline events?

Effectively, in order to build a good offline application, you need to know when you’re actually offline. Incidentally, you also need to know when your application has returned to an ‘online’ status again.

Generally speaking, the flow for an offline-capable web application would look something like this, written completely in pseudo-code:

  1. function saveData( item ){
  2.     if ( navigator.onLine ) {
  3.         saveToServer( item );
  4.     } else {
  5.         toSave.push( item );
  6.     }
  7. }
  8.  
  9. function loadData( item ){
  10.     if ( navigator.onLine ) {
  11.         return loadFromServer( item );
  12.     } else {
  13.         var result = loadFromQueue( item );
  14.         if ( !result ) {
  15.             displayError();
  16.             toLoad.push( item );
  17.         }
  18.         return result;
  19.     }
  20. }
  21.  
  22. setInterval(function(){
  23.     if ( navigator.onLine ) {
  24.         var item = predictNextItemToBeLoaded();
  25.         loadData( item );
  26.     }
  27. }, 5000);
  28.  
  29. window.ononline = function(){
  30.     toSave.forEach( saveData );
  31.     toLoad.forEach( loadData );
  32. };
  33.  
  34. window.onload = function(){
  35.     document.getElementById("myform").onsubmit = function(){
  36.         saveData( this );
  37.         return false;
  38.     };
  39. };

As you can see from this code, there are two very important aspects at play:

  1. You need to know when the service comes back online, so that you can re-synchronize with the server.
  2. You need to know when your service is offline, so that you can be sure to queue your requests for a later time.

It is this process that offline events helps to trivialize. So let’s take at the API that we’re given by the specification:

navigator.onLine

This is a single property that maintains a true/false value (true for online, false for offline). Currently, this property is updated (in Firefox) whenever you switch into “Offline Mode” (more details at the end of this post).

Additionally, this property should update whenever a browser is no longer capable of connecting to the network. According to the specification:

The navigator.onLine attribute must return false if the user agent will not contact the network when the user follows links or when a script requests a remote page (or knows that such an attempt would fail)…

As of this time, Firefox only appears to update this property when switching to/from the browser’s Offline mode.

One point that I found to be curious, about this property, was it’s naming. It appears as if someone originally felt that “online” was spelled “on-line” (and since you can’t have dashes in JavaScript property names, converted it to its camelcase equivalent, “onLine”). Unsurprisingly, this naming convention is a bit of legacy.

Interestingly, this property already exists in Firefox and Internet Explorer (the specification based itself off of these prior implementations), so you can begin using them today.

“online” and “offline” events

These two events are the truly-new aspects of offline events. They are fired against the document body of any page that switches inbetween online and offline mode. Additionally, the event bubbles up from document.body, to document, ending at window. Both of the events are non-cancellable (you can’t prevent the user from coming online, or going offline).

As a side note, Mozilla has had these built in to its XPCOM layer for some time now, specifically the network:offline-status-changed event.

A Simple Test

In the ticket that describes the implementation of these events in Firefox, there’s a simple test case that you can run to verify that the events are working.

Considering that you probably don’t want to go through the trouble of building your own copy of “Minefield”, let’s take a quick look at what happens in this test’s code.

  1. <!doctype html>
  2. <html>
  3. <head>
  4.   <script>
  5.     function updateOnlineStatus(msg) {
  6.       var status = document.getElementById("status");
  7.       var condition = navigator.onLine ? "ONLINE" : "OFFLINE";
  8.       status.setAttribute("class", condition);
  9.       var state = document.getElementById("state");
  10.       state.innerHTML = condition;
  11.       var log = document.getElementById("log");
  12.       log.appendChild(document.createTextNode("Event: " + msg + "; status=" + condition + "\n"));
  13.     }
  14.     function loaded() {
  15.       updateOnlineStatus("load");
  16.       document.body.addEventListener("offline", function () {
  17.         updateOnlineStatus("offline")
  18.       }, false);
  19.       document.body.addEventListener("online", function () {
  20.         updateOnlineStatus("online")
  21.       }, false);
  22.     }
  23.   </script>
  24.   <style>...</style>
  25. </head>
  26. <body onload="loaded()">
  27.   <div id="status"><p id="state"></p></div>
  28.   <div id="log"></div>
  29. </body>
  30. </html>

There are four important lines to take note of: 7, 16, 19, and 26. We’ll be looking at them in depth here.

You’ll notice, that if you tried to run the test in your browser (even if you didn’t have the bleeding-edge build), that it worked! You probably saw a result just like this:

Why is this the case? As I mentioned before, Firefox already has support for the navigator.onLine event, the only thing that’s been added was the addition of events to notify you when the property changes. Incidentally, you can still bind an onload=”” event and check for a browser’s online/offline status there.

Now, you might be asking yourself (as I did), when can a page load and NOT have a status of “online”? Upon reading through some of the information available, it appears as if this can occur when a page is loaded directly from the browser’s cache, while you’re in an offline mode. These are the steps that Mark Finkle took to reproduce this:

  • Load a web page from a bookmark.
  • Put the browser into offline mode.
  • Close the browser.
  • Open the browser. (Incidentally, you’re back in online mode.)
  • Re-enable offline mode.
  • Click the bookmark again, and you’ll be visiting the “offline” copy of that page.

Let’s take a look, now, at the browser’s “Work offline” mode, and what that offers to us web application developers.

Enable Offline Mode

In a nutshell: Offline mode is a means, through which, a user can tell the browser to be much greedier, and possibly more proactive, about the caching that it performs. Effectively, a browser will try to use the browser’s cache as much as possible.

In order to move into offline mode, you can toggle the menu option like so:

This triggers the “offline” event – giving your web application the ability to react, and behave, accordingly.

Disable Offline Mode

Additionally, when it comes time for the user to move back into “online” mode, another event is fired (which can be handled and interpreted).

Summary and Comments

This is a really handy feature, and certainly a great tool for making offline web application simpler. I’m looking forward to its widespread adoption.

My biggest gripe with the feature, right now, is more in its implementation (rather than its concept). There’s a huge amount of ambiguity concerning what “Working Offline” means. It’s not really clear what is supposed to happen when that menu option is triggered – nor, what exactly, is supposed to trigger the online/offline events.

I see a huge amount of potential in Firefox 3′s offline capabilities, however they really need to be clarified – and made useful to the user. Hooking “offline” mode purely to network connectivity would be a great start. (Forcing the user to toggle some sort of offline mode is cumbersome – especially considering that most of the time that I go offline, it’s not of my own free will.)

In short: I think Firefox 3 is off to a great start, in supporting offline web applications, but we still have a ways to go in order to make the whole process (both for users and for developers) as smooth as possible.

Posted: February 16th, 2007


If you particularly enjoy my work, I appreciate donations given with Gittip.

11 Comments (Show Comments)



Comments are closed.
Comments are automatically turned off two weeks after the original post. If you have a question concerning the content of this post, please feel free to contact me.


Secrets of the JavaScript Ninja

Secrets of the JS Ninja

Secret techniques of top JavaScript programmers. Published by Manning.

Ukiyo-e Database and Search

Ukiyo-e.org

Japanese woodblock print database and search engine.


John Resig Twitter Updates

@jeresig

Infrequent, short, updates and links.