Monday, January 26, 2015

Your Browser is Lying to You

There's a little trick I do on my comic to make sharing easier. Since the content changes three times per week, if you send someone the link to "amphibian.com" and they don't click on it until 2 days later there's a good chance they'll see a different comic than you did. That's why as soon as you navigate to amphibian.com I re-write the URL to include the id of the latest comic. Then when you copy the contents of your browser's location bar into the "share" field on Facebook, everyone will see the same thing you did - even if they don't click on it for a year.

And speaking of Facebook, you may have noticed this trick there as well. When you click on a picture, it will show up larger and cover most of your news feed. If you take note of the URL in your browser, it will change to a direct link to that picture. Copy that URL and use it later, or give it to a friend, and it will take you right to that picture.

You are looking at www.facebook.com...
...but click on that picture and the URL changes!

But technically speaking, your browser never left the page it was on before you clicked on the image. Just like amphibian.com doesn't redirect you to a new URL when you first visit the site or even when you navigate around using the "Previous" and "Next" links - the URL bar can lie to you!

Doing this yourself is fairly simple. Look at this code:

var newPath = "whatnot";
if (history.replaceState) {
    history.replaceState({
        nowShowing: newPath,
        yourData: "whatever you need",
        storeIt: "in this object"
    }, "page title not really used", newPath);
} else {
    // you are using an old Internet Explorer
}

The history.replaceState function is what makes the magic happen. You should check to see if it exists (I still hate you, IE 9) before calling it, but I haven't found a good fallback option or polyfill. There are some that try, but in my opinion they aren't worth the hassle. Anyway, let's unpack this a little. The replaceState function takes 3 parameters. The first is an object. Any object you want. More on this later. The second parameter is the page title for the new URL. Nothing is really done with this, but it may be used someday according to the browser documentation. Just put some text in here and forget about it. The third parameter is the new path. In my example it's "whatnot" - so if you were to execute this on www.example.com, the URL would change to www.example.com/whatnot.

Alright, so what's up with that generic, whatever-you-want, first parameter object? It comes into play when the browser's back button gets used after you've changed the URL. To have consistent behavior, you need to handle what happens when the user wants to return to where they were before you changed the URL. For example, I change the URL to www.example.com/whatnot, based on something on which the user clicked. Then I change it to www.example.com/something when they click on something else. Then they hit the back button. The browser takes them back to www.example.com/whatnot - but they didn't really never left the page. I have to know how to re-create what I had on the screen when I made up the /whatnot path in the first place.

To handle situations like this, bind a function to the "popstate" event on the window object. This function will be called whenever the back button is used. In it, you can access that object you made when you replaced the URL. Just put enough information in there to recreate the user experience you created the first time you changed the URL. Here's an example which uses jQuery for the even binding:

$(window).bind("popstate", function(event) {
    var s = event.originalEvent.state;
    if (s && s.nowShowing) {
        console.log("welcome back to " + s.nowShowing);
    }
});

Your object that you passed in to replaceState is now available via the event.originalEvent.state object. So when /whatnot becomes the URL again, you'll know as long as you put some identifying information in that object. In my example, the field nowShowing contained the path.

These tricks are often useful when developing something like a single-page web application and you want to gracefully handle the back button, but clearly they have other applications as well. Just another browser/JavaScript feature to think about when you are looking for creative solutions to web-based problems.

Amphibian.com comic for 26 January 2015