jquery-mobile/js/jquery.mobile.navigation.pushstate.js

116 lines
No EOL
3.5 KiB
JavaScript

/*
* jQuery Mobile Framework : history.pushState support, layered on top of hashchange
* Copyright (c) jQuery Project
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*/
( function( $, window ) {
// For now, let's Monkeypatch this onto the end of $.mobile._registerInternalEvents
// Scope self to pushStateHandler so we can reference it sanely within the
// methods handed off as event handlers
var pushStateHandler = {},
self = pushStateHandler,
$win = $( window ),
url = $.mobile.path.parseUrl( location.href );
$.extend( pushStateHandler, {
// TODO move to a path helper, this is rather common functionality
initialFilePath: (function() {
return url.pathname + url.search;
})(),
initialHref: url.hrefNoHash,
// Flag for tracking if a Hashchange naturally occurs after each popstate + replace
hashchangeFired: false,
state: function() {
return {
hash: location.hash || "#" + self.initialFilePath,
title: document.title,
// persist across refresh
initialHref: self.initialHref
};
},
resetUIKeys: function( url ) {
var dialog = $.mobile.dialogHashKey,
subkey = "&" + $.mobile.subPageUrlKey,
dialogIndex = url.indexOf( dialog );
if( dialogIndex > -1 ) {
url = url.slice( 0, dialogIndex ) + "#" + url.slice( dialogIndex );
} else if( url.indexOf( subkey ) > -1 ) {
url = url.split( subkey ).join( "#" + subkey );
}
return url;
},
// on hash change we want to clean up the url
// NOTE this takes place *after* the vanilla navigation hash change
// handling has taken place and set the state of the DOM
onHashChange: function( e ) {
var href, state;
self.hashchangeFired = true;
// only replaceState when the hash doesn't represent an embeded page
if( $.mobile.path.isPath(location.hash) ) {
// propulate the hash when its not available
state = self.state();
// make the hash abolute with the current href
href = $.mobile.path.makeUrlAbsolute( state.hash.replace("#", ""), location.href );
href = self.resetUIKeys( href );
// replace the current url with the new href and store the state
history.replaceState( state, document.title, href );
}
},
// on popstate (ie back or forward) we need to replace the hash that was there previously
// cleaned up by the additional hash handling
onPopState: function( e ) {
var poppedState = e.originalEvent.state, holdnexthashchange = false;
// if there's no state its not a popstate we care about, ie chrome's initial popstate
// or forward popstate
if( poppedState ) {
// disable any hashchange triggered by the browser
$.mobile.urlHistory.ignoreNextHashChange = true;
// defer our manual hashchange until after the browser fired
// version has come and gone
setTimeout(function() {
// make sure that the manual hash handling takes place
$.mobile.urlHistory.ignoreNextHashChange = false;
// change the page based on the hash
$.mobile._handleHashChange( poppedState.hash );
}, 100);
}
},
init: function() {
$win.bind( "hashchange", self.onHashChange );
// Handle popstate events the occur through history changes
$win.bind( "popstate", self.onPopState );
// if there's no hash, we need to replacestate for returning to home
if ( location.hash === "" ) {
history.replaceState( self.state(), document.title, location.href );
}
}
});
$( function() {
if( $.mobile.pushStateEnabled && $.support.pushState ){
pushStateHandler.init();
}
});
})( jQuery, this );