via Ajaxian:

Daniel Kantor has implemented a Back button solution in Streampad and has shared it with us.

One of the main gripes against AJAX webapps is how they break the back button in a typical browser. There have been a few solutions (notably Brad Neuberg’s Really Simple History) but none have got it working in Safari. GMail still does not have a working back button in Safari.

They say the third time is the charm and I have tried to get a Back button thing in Streampad twice before. I do not want to use someone else’s library as they are usually more complex than I need and I did not want to put something in place until I had Safari working. I tried a few different techniques, but when I got it working in Safari, it would break in Firefox or IE.

I finally figured out a way to get this working in Firefox, IE and Safari.

While Daniel struggled with this, he found that the back button support caused a slow down in the entire app performance. He came up with a new solution that didn't suffer from the performance issues:

The general concept is this: You load a page into an iframe that calls parent.goBack() and then changes its own location to a new page (a blank page will do). Because the page jumps to a new location, it now has a history. If you click the back button, it will load the page again (calling parent.goBack()) and then spring forward to the dummy blank page.

JavaScript:
var historyArray = Array(); // create an empty array to hold the history
var historyCounter = -1; // initialize the array pointer to -1

function historyAdd(f){
  if (historyCounter == -1){  // the first time this is called it will change the iframe location
  document.getElementById(’hFrame’).src = “/historySpring.php”;
}

var o = historyArray[historyCounter];
if (f != o){ // don’t put in consecutive duplicates
  historyCounter++
  historyArray[historyCounter] = f; // add function to history
}

function goBack() {
  if (historyCounter> 0){ // don’t want to call it if there is nothing in history array
    historyCounter– // set the pointer back one
    var f = historyArray[historyCounter]; // get the function from the history array
    f = f+”()”;
    eval(f); // call the function
  }
}

drag to resize