Blograby

Preserving History

The HTML5 specification introduces an API to manage the browser history. 2 In Creating an Accessible Updatable Region, on page 104, we built a prototype for AwesomeCo’s new home page that switched out the main content when we clicked one of the navigation tabs. One drawback with the approach we used is that there’s no support for the browser’s Back button. We can fix that with some hacks, but we will eventually be able to solve it for good with the History API.

We can detect support for this API like this:

function s u p p o r t s H i s t o r y O {
return ! ! ( w i n d o w . h i s t o r y && w i n d o w . h i s t o r y . p u s h S t a t e ) ;}

We use this method whenever we need to work with the History objects.

Storing the Current State

When a visitor brings up a new web page, the browser adds that page to its history. When a user brings up a new tab, we need to add the new tab to the history ourselves, like this:

Une l $( “nav ul “) . cl i c k(function(event) {
t a r g e t = $ ( e v e n t . t a r g e t ) ;
i f ( t a r g e t . i s ( ” a ” ) ) {
e v e n t . p r e v e n t D e f a u l t ( ) ;
5 if ( $ ( t a r g e t . a t t r ( ” h r e f ” ) ) .hasCl ass ( ” h i d d e n ” ) ){
i f ( s u p p o r t s H i s t o r y ( ) ) {
I- var tab = $ ( t a r g e t ) . a t t r ( ” h r e f ” ) ;
I- var s t a t e O b j e c t = { t a b : t a b } ;
! • window.history.pushState(stateObject, t a b ) ;
};
$( ” .visible”) . removed ass ( ” v i si b 7 e ” ) . addCl as s( “hidden”) . h i d e ( ) ;
$ ( t a r g e t . a t t r ( “href”)) . removed ass (“hidden”) . addClass( “visible”) . show() ;
is };
};
} ) ;
} ) ;

We snag the ID of the element that’s visible, and then we add a history state to the browser. The first parameter of the pushstateO method is an object that we’ll be able to interact with later. We’ll use this to store the ID of the tab we want to display when our user navigates back to this point. For example, when the user clicks the Services tab, we’ll store #services in the state object.

The second parameter is a title that we can use to identify the state in our history. It has nothing to do with the title element of the page; it’s just a way to identify the entry in the browser’s history. We’ll use the ID of the tab again.

Retrieving the Previous State

Although this adds a history state, we still have to write the code to handle the history state change. When the user clicks the Back button, the window.onpopstateO event gets fired. We use this hook to display the tab we stored in the state object.

i f ( s u p p o r t s H i s t o r y O ) {
window.onpopstate = function(event) {
i f ( e v e n t . s t a t e ) {
var tab = ( e v e n t . s t a t e [ ” t a b ” ] ) ;
$(“. visible”)
. removed ass{“visible”)
.addClass(“hidden”)
. h i d e O ;
$ ( t a b )
. r e m o v e d a s s ( ” h i d d e n ” )
. a d d C l a s s ( ” v i s i b 7 e ” )
. show() ;
}
};

We fetch the name of the tab and then use jQuery to locate the element to hide by its ID. The code that hides and shows the tabs is repeated here from the original code. We should refactor this to remove the duplication.

Defaulting

When we first bring up our page, our history state is going to be null, so we’ll need to set it ourselves. We can do that right above where we defined our window.onpopstateO method.

i f ( s u p p o r t s H i s t o r y O ) {
w i n d o w . h i s t o r y . p u s h S t a t e C { t a b : “#we7come”}, ‘^welcome’);
window.onpopstate = function(event) {
i f ( e v e n t . s t a t e ) {
var tab = ( e v e n t . s t a t e [ ” t a b ” ] ) ;
$(“. visible”)
. removed ass(“visible”)
.addClass(“hidden”)
. h i d e O ;
$ ( t a b )
. r e m o v e d a s s ( ” h i d d e n ” )
. a d d d a s s ( ” v i s i b 7 e ” )
. show() ;
}
};
};

Now, when we bring up the page, we can cycle through our tabs using the browser history.

Falling Back

This works in Firefox 4 and Safari 4, as well as in Chrome 5, but it doesn’t work in Internet Explorer. Solutions like the jQuery Address plug-in4 provide the same functionality, but we won’t go into implementing that as a fallback solution because it’s less of a fallback and
more of a complete replacement with a lot of additional features. Keep an eye on browser support for history manipulation, though, because you’ll be able to easily provide much more user-friendly applications when you can use this API in every browser.

 

Exit mobile version