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
dhtmlHistory.initialize();
// add ourselves as a DHTML History listener
dhtmlHistory.addListener(handleHistoryChange);
// 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
historyStorage.put("addressBook",
addressBook);
}
else {
// fetch the cached address book from
// the history storage
window.addressBook =
historyStorage.get("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 =
document.getElementById(newLocation);
// 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 =
historyStorage.get("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 =
document.getElementById("content-title");
var contentValue =
document.getElementById("content-value");
contentTitle.innerHTML =
selectedElement.innerHTML;
contentValue.innerHTML = sectionData;
}
Demo O'Reilly Mail or download the O'Reilly Mail source code.