ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

AJAX: How to Handle Bookmarks and Back Buttons
Pages: 1, 2, 3, 4, 5, 6

Example 2: O'Reilly Mail

Our second example is a simple, fake AJAX email application named O'Reilly Mail, similar to Gmail. O'Reilly Mail illustrates how to control the browser's history using the dhtmlHistory class, and how to cache history data using the historyStorage object.

The O'Reilly Mail user interface has two pieces. On the left side of the page is a menu with different email folders and options, such as Inbox, Drafts, etc. When a user selects a menu item, such as the Inbox, we update the right side of the page with this menu item's contents. In a real application, we would remotely fetch and display the selected mailbox's contents; in O'Reilly Mail, however, we simply display the option that was selected.

O'Reilly Mail uses the Really Simple History framework to add menu changes to the browser's history and update the location bar, allowing users to bookmark the application and to jump to previous menu changes using the browser's back and forward buttons.

We add one special menu option, Address Book, to illustrate how historyStorage might be used. The address book is a JavaScript array of contact names and email addresses; in a real application we would fetch this from a remote server. In O'Reilly Mail, however, we create this array locally, add a few names and email addresses, and then store it into the historyStorage object. If the user leaves the web page and then returns, the O'Reilly Mail application retrieves the address book from the cache, rather than having to contact the remote server again.

The address book is stored and retrieved in our initialize() method:

/** Our function that initializes when the page
    is finished loading. */
function initialize() {
   // initialize the DHTML History framework
   // add ourselves as a DHTML History listener

   // if we haven't retrieved the address book
   // yet, grab it and then cache it into our
   // history storage
   if (window.addressBook == undefined) {
      // Store the address book as a global
      // object.
      // In a real application we would remotely
      // fetch this from a server in the
      // background.
      window.addressBook =
         ["Brad Neuberg 'bkn3@columbia.edu'",
          "John Doe 'johndoe@example.com'",
          "Deanna Neuberg 'mom@mom.com'"];
      // cache the address book so it exists
      // even if the user leaves the page and
      // then returns with the back button
   else {
      // fetch the cached address book from
      // the history storage
      window.addressBook = 

The code to handle history changes is also straightforward. In the source below, handleHistoryChange is called when the user presses either the back or forward button. We take the newLocation and use it to update our user interface to the correct state, using a utility method O'Reilly Mail defines named displayLocation.

/** Handles history change events. */
function handleHistoryChange(newLocation, 
                             historyData) {
   // if there is no location then display
   // the default, which is the inbox
   if (newLocation == "") {
      newLocation = "section:inbox";
   // extract the section to display from
   // the location change; newLocation will
   // begin with the word "section:" 
   newLocation = 
         newLocation.replace(/section\:/, "");
   // update the browser to respond to this
   // DHTML history change
   displayLocation(newLocation, historyData);

/** Displays the given location in the 
    right-hand side content area. */
function displayLocation(newLocation,
                         sectionData) {
   // get the menu element that was selected
   var selectedElement = 
   // clear out the old selected menu item
   var menu = document.getElementById("menu");
   for (var i = 0; i < menu.childNodes.length;
                                          i++) {
      var currentElement = menu.childNodes[i];
      // see if this is a DOM Element node
      if (currentElement.nodeType == 1) {
         // clear any class name
         currentElement.className = "";
   // cause the new selected menu item to
   // appear differently in the UI
   selectedElement.className = "selected";
   // display the new section in the right-hand
   // side of the screen; determine what 
   // our sectionData is
   // display the address book differently by
   // using our local address data we cached
   // earlier
   if (newLocation == "addressbook") {
      // format and display the address book
      sectionData = "<p>Your addressbook:</p>";
      sectionData += "<ul>";
      // fetch the address book from the cache
      // if we don't have it yet
      if (window.addressBook == undefined) {
         window.addressBook = 
      // format the address book for display
      for (var i = 0; 
               i < window.addressBook.length;
                     i++) {
         sectionData += "<li>"
                        + window.addressBook[i]
                        + "</li>";                  
      sectionData += "</ul>";
   // If there is no sectionData, then 
   // remotely retrieve it; in this example
   // we use fake data for everything but the
   // address book
   if (sectionData == null) {
      // in a real application we would remotely
      // fetch this section's content
      sectionData = "<p>This is section: " 
         + selectedElement.innerHTML + "</p>";  
   // update the content's title and main text
   var contentTitle = 
   var contentValue =
   contentTitle.innerHTML = 
   contentValue.innerHTML = sectionData;

Demo O'Reilly Mail or download the O'Reilly Mail source code.

Pages: 1, 2, 3, 4, 5, 6

Next Pagearrow