Showing posts with label ajax. Show all posts
Showing posts with label ajax. Show all posts

Sunday, March 25, 2007

History reloaded

My last post was about Really Simple History and how to get it to work in IE7. I forgot to mention the problems you easily get then using dhtmlHistory.js and IE if you serve your pages from a script language. This is because for dynamic history to work, IE must preserve the content of a form between page reloads. This can only happend if the web server returns a status code 304 (Not modified) on the page access.

In my case I used PHP as the server side script language to build my pages and had problems getting F5 to reload the page and stay on the current page. After a page reload, dhtmlHistory.js considered it a first load and the home page was shown again.

The solution I found after a while was to check if any of the pages had been modified and return the 304 status code from PHP. I also use an ETag header to make the checking for modifications simple.

The index.php file creates the HTML by listing all page_*.php files in a directory. For this I use the glob PHP function. After that I check for the file that was modified last, this is because this time will be used as modification date for the generated page. Then serving the generated page an ETag header will also be generated. This ETag will be constructed by using the md5 PHP function on the modification time.

On hitting F5 the web browser will send this ETag back in a header (if-none-match) to check for modified content. In PHP this header will be called $_SERVER["HTTP_IF_NONE_MATCH"] and the code checks if the current modification time is the same, if so a 304 status is returned.

Here is the code from index.php:


$pages = glob("page_*.php");

$mtime = filemtime("index.php");
foreach($pages as $page_file) {
$m = filemtime($page_file);
if ($m > $mtime) {
$mtime = $m;
}
}


$etag=(isset($_SERVER['HTTP_IF_NONE_MATCH']))? $_SERVER['HTTP_IF_NONE_MATCH']:"";

$etime = $mtime + 3600; // How long can a cache server save this content without asking again? (1 hour)

if ($etag == md5($mtime)) {
header('HTTP/1.0 304 Not Modified');
die;
}

header("Last-Modified: " . gmdate('D, d M Y H:i:s', $mtime) . ' GMT');
header("Expires: ". gmdate('D, d M Y H:i:s', $etime) . ' GMT');
header("ETag: " . md5($mtime));

Thursday, March 22, 2007

History restored

I currently work on a Web2.0 project for a customer where we use AJAX extensively. We download all of the HTML code and JavaScript from index.html and every part of the application after that are implemented using DHTML and AJAX requests to the server.

To give the user the standard Web experience we are using a JavaScript library called Really Simply History. By using this library we can control that will happen if the user presses the back button in the browser.

The library worked great until IE7 started to appear. Suddenly we got strange "white-outs" of the pages. Then clicking a button or a link all HTML of the page was removed and only two buttons of the UI was left.

After some digging using Google I found a post in Spanish describing that went wrong and a fix. The problem seems to be that dhtmlHistory.js breaks the DOM in some way. I implemented the fix suggested by jorgemaestre and it worked, the whiteouts was removed.

But instead I got other problems. Pressing F5 for a page reload did not work as expected, after hitting F5 the site reloaded but I was taken back to the home page. This means the history function did not work. I did some debugging and discovered that for dhtmlHistory.js to work, the form field values needed to be preserved. I also found another post on the Internet about IE not saving the values of a form if it's created after the page has loaded.

The solution is to let the dhtmlHistory.js create it's form during normal page loading but as the last part of the page, after all other content. To implement the fix:

1) Open the dhtmlHistory.js and remove the last rows saying:


/** Initialize all of our objects now. */
window.historyStorage.init();
window.dhtmlHistory.create();


2) To your main index.html or whatever that's using dhtmlHistory.js add as the last part before </body>


</script>
/** Initialize all of our objects now. */
window.historyStorage.init();
window.dhtmlHistory.create();
</script>