Today I discovered how to do something that’s been bugging me for months. Literally, we launched the MotoGP site with slightly less featured deep linking than anyone would have liked. But, as no solution was forthcoming, we had to deal with it.

What was the problem, you ask? Well. When you navigate to different parts of the (Flash) site, I update your browser’s location bar. I’m also updating your browser’s history. This means that we’re not constantly reloading the same enormous Flash file, that your browser back/forward buttons work, and that you can copy/paste/bookmark/whatever the URL from the address bar to return to that exact spot in the future.

I was using the ubiquitous “location.hash” property to get this behavior. And it worked wonderfully. Except in Firefox, where it refused to update. And in Opera, where it was occasionally even worse.

A new project coming down the pipe also wanted the deep links, so I’ve been sneaking time between bugfixes to figure out how to make things work in Firefox. Finally, this morning I stumbled upon the right incantation to feed into Google, and I found my answer.

The correct method is not to set the location directly, but to call its replace() function.

Thus:

location.hash = "something";

becomes

location.replace( "#something" );

And this works for most cases. Enter the more complicated scenareo that I’d built for myself with MotoGP. The site works by loading two separate files into a pair of frames, one visible, the other hidden. When you go to a new state in the main view, it sends a signal to the bottom frame and causes the browser history to change and keep up. When you use your browser arrows to navigate, the bottom frame reloads and sends a state update to the main view – which in turn realizes that it’s being told to go somewhere.

Well, if we just change location from the bottom frame, it’ll only update the bottom frame’s internal location value. Not terribly helpful.

We need to update top.document’s location. Except there’s a problem here as well.

top.document.location.replace( "#something" );

doesn’t work. It has all kinds of unpleasant behavior. Namely, it throws away the frame setup and loads a copy of the bottom frame into the browser window. Likewise:

top.document.location.replace( top.document.location+"#something" );

doesn’t work either. It keeps appending more anchor tags to the string and never stops, giving you urls with “#something#somethingelse#andsomethingelse” appended to them. Not the desired effect.

Hence, you must either parse the url string to remove any previous anchor tag, or just build it yourself by:

// build it yourself
var address = top.document.location.protocol + "//" +
              top.document.location.host +
              top.document.location.pathname;
// or just parse it out
var index = top.document.location.indexOf("#");
if( index != -1 )
    address = top.document.location.substr( 0, index );
else
    address = top.document.location;

I’m not sure which method is faster or more reliable, I’ve not done any really extensive testing, but I’m just using the composition method for now.

Leave a Reply