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:
function saveData( item ){ if ( navigator.onLine ) { saveToServer( item ); } else { toSave.push( item ); } } function loadData( item ){ if ( navigator.onLine ) { return loadFromServer( item ); } else { var result = loadFromQueue( item ); if ( !result ) { displayError(); toLoad.push( item ); } return result; } } setInterval(function(){ if ( navigator.onLine ) { var item = predictNextItemToBeLoaded(); loadData( item ); } }, 5000); window.ononline = function(){ toSave.forEach( saveData ); toLoad.forEach( loadData ); }; window.onload = function(){ document.getElementById("myform").onsubmit = function(){ saveData( this ); return false; }; };
As you can see from this code, there are two very important aspects at play:
- You need to know when the service comes back online, so that you can re-synchronize with the server.
- 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.
<!doctype html> <html> <head> <script> function updateOnlineStatus(msg) { var status = document.getElementById("status"); var condition = navigator.onLine ? "ONLINE" : "OFFLINE"; status.setAttribute("class", condition); var state = document.getElementById("state"); state.innerHTML = condition; var log = document.getElementById("log"); log.appendChild(document.createTextNode("Event: " + msg + "; status=" + condition + "\n")); } function loaded() { updateOnlineStatus("load"); document.body.addEventListener("offline", function () { updateOnlineStatus("offline") }, false); document.body.addEventListener("online", function () { updateOnlineStatus("online") }, false); } </script> <style>...</style> </head> <body onload="loaded()"> <div id="status"><p id="state"></p></div> <div id="log"></div> </body> </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.
funTomas (February 16, 2007 at 3:30 am)
Yep, I’m looking forwar to see more web apps like scrybe, for example.
Andrew (February 16, 2007 at 9:06 am)
Very cool!
Robert O'Callahan (February 17, 2007 at 3:40 am)
Automatic switching to offline mode is supposed to work, on Windows and Linux anyway. There seems to be some sort of regression at the moment.
John Resig (February 17, 2007 at 1:11 pm)
@Robert: Ah, that would explain it, I tested this in OSX. Alright, I’ll have to do some testing elsewhere, then.
Brennan Stehling (February 17, 2007 at 1:36 pm)
John, I am interested in building an offline application but I would like to know more about the requirements. One application I am working on uses AJAX/JSON to get data which is then held in Javascript objects. If this was done in offline mode I suppose I would not send the AJAX request but then how would I populate the objects? Should I still do the requests and expect the offline features to simulate the returned JSON messages? Currently I am doing AJAX/JSON Posts to get the data. Are those going to fail when a Get request would work?
Már (February 17, 2007 at 6:11 pm)
Nice!
Joe Grossberg (February 18, 2007 at 9:27 pm)
“Now, you might be asking yourself (as I did), when can a page load and NOT have a status of “online”?”
What if you were to browse a page on your hard drive (directly through file://foo and not via localhost or 127.0.0.1)?
Would that be online or offline?
Julien Couvreur (April 11, 2007 at 7:53 pm)
I thought that you would be interested in a prototype wiki which supports offline, TiwyWiki (“Take It With You”): http://blog.monstuff.com/archives/000272.html
It demonstrates all the basics for building an offline ajax applications, from caching, local storage, offline events and synchronization.
joey (June 1, 2007 at 3:41 pm)
screw you
joey (June 1, 2007 at 3:41 pm)
fuck you all
美國産å (September 20, 2007 at 4:28 am)
There seems to be some sort of regression at the moment.