It seems that nobody cares much for web2py, ajax and browser back buttons :) Nevertheless, I made some progress and thought I'd post some findings here If anyone searches the group with a similar goal.
Let me describe the problem once again. Imagine a scenario: 1) visitor is on Google, searches for a web2py powered site, finds it, follows the link 2) site loads 3) visitor sees an internal link which loads a web2py component (ajax call) with new content, follows the link, component loads 4) visitor reads the content, wants to go back, uses the browser back button... 5) KABOOM, user is back on Google instead on the first page of the site which is pretty bad as far as user experience goes. Anyway, our site has a number of components that can work as regular pages (.load and .html do the same thing) so what I really need is a way for a component to tell the browser it has loaded. To solve this, i need to manipulate the browser history manually. Sadly, current state of things is pretty messy on the browser side. After looking at what's available, I found several solutions but none of them perfect. I decided to give up on Internet Explorer 8 and 9 completely. Sorry folks, you're on your own. IE 10 *should* work as it comes out... yes, I believe in Santa. :) So, the first thing I tried was using the native browser's history API [1], which all modern HTML5 browsers have (yes, forget IE9). It looks fine on paper, but the implementation has some problems. Chromium / Chrome behaves differently than Firefox/Opera/Safari in one crucial point (fires initial onpopstate, I even managed to crash Chromium) [2], so I had to abandon using this API directly. If it wasn't for this Chromium issue, it would be the perfect solution. Then I tried using the history.js [3]. This project has a long history of successfully coping with ajax/browser history issues, so I was optimistic. But sadly, history.js's master branch (version 1.7.1) also works in a way that pushState and replaceState will immediately trigger onpopstate, which is not what I wanted [4]. Luckily, the devel branch (1.8.0-dev) got an additional State.internal [5] with this commit [6], so I can tell if onpopstate is triggered by the browser's buttons or not. Ok, long story is coming to an end. It's time for some code. This is what I'm currently at: - set the history entry in the component's controller: response.js = "History.pushState({isMyPageName:1},'','"+URL('some','thing',extension=False)+"')" -at the end of layout.html: <script> (function(window,undefined){ var History = window.History; if ( !History.enabled ) { return false; } History.Adapter.bind(window,'statechange',function(){ var State = History.getState(); if (( State.data.isMyPageName == 1 ) && ( State.internal == false )) { //alert("data: " + JSON.stringify(State.data) + " title: " + State.title + " url: " + State.url + " internal: " + State.internal); window.location = State.url; } }); })(window); </script> Ok, that's about it... The solution is flaky at times and I still need to manipulate document.title, haven't gotten to that yet. But it works, web2py components can silently change the browser url as they load. And no &#&%/ URL hashes and hashbangs... [1] https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history [2] https://github.com/balupton/history.js/wiki/The-State-of-the-HTML5-History-API [3] https://github.com/balupton/history.js [4] https://github.com/balupton/history.js/issues/47 [5] https://github.com/balupton/history.js/tree/dev [6] https://github.com/balupton/history.js/commit/c79c17f9801373f5218f144088c387f1935f3462