fix timing issue where the pushstate plugin expected popstate generated hashchanges to happen before a given timeout

This commit is contained in:
John Bender 2012-01-10 10:47:33 -08:00 committed by scottjehl
parent cb84e13148
commit eb9e113911

View file

@ -21,9 +21,6 @@ define( [ "jquery.mobile.navigation" ], function() {
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,
@ -48,6 +45,11 @@ define( [ "jquery.mobile.navigation" ], function() {
return url;
},
hashValueAfterReset: function( url ) {
var resetUrl = self.resetUIKeys( url );
return $.mobile.path.parseUrl( resetUrl ).hash;
},
// TODO sort out a single barrier to hashchange functionality
nextHashChangePrevented: function( value ) {
$.mobile.urlHistory.ignoreNextHashChange = value;
@ -62,13 +64,15 @@ define( [ "jquery.mobile.navigation" ], function() {
if( self.onHashChangeDisabled ){
return;
}
var href, state,
hash = location.hash,
isPath = $.mobile.path.isPath( hash ),
resolutionUrl = isPath ? location.href : $.mobile.getDocumentUrl();
hash = isPath ? hash.replace( "#", "" ) : hash;
// propulate the hash when its not available
state = self.state();
@ -95,23 +99,42 @@ define( [ "jquery.mobile.navigation" ], function() {
// 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;
var poppedState = e.originalEvent.state,
timeout, fromHash, toHash, hashChanged;
// if there's no state its not a popstate we care about, ie chrome's initial popstate
// or forward popstate
// if there's no state its not a popstate we care about, eg chrome's initial popstate
if( poppedState ) {
// disable any hashchange triggered by the browser
self.nextHashChangePrevented( true );
// the active url in the history stack will still be from the previous state
// so we can use it to verify if a hashchange will be fired from the popstate
fromHash = self.hashValueAfterReset( $.mobile.urlHistory.getActive().url );
// 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
self.nextHashChangePrevented( false );
// the hash stored in the state popped off the stack will be our currenturl or
// the url to which we wish to navigate
toHash = self.hashValueAfterReset( poppedState.hash.replace("#", "") );
// change the page based on the hash
$.mobile._handleHashChange( poppedState.hash );
}, 100);
// if the hashes of the urls are different we must assume that the browser
// will fire a hashchange
hashChanged = fromHash !== toHash;
// unlock hash handling once the hashchange caused be the popstate has fired
if( hashChanged ) {
$win.one( "hashchange.pushstate", function() {
self.nextHashChangePrevented( false );
});
}
// enable hash handling for the the _handleHashChange call
self.nextHashChangePrevented( false );
// change the page based on the hash
$.mobile._handleHashChange( poppedState.hash );
// only prevent another hash change handling if a hash change will be fired
// by the browser
if( hashChanged ) {
// disable hash handling until one of the above timers fires
self.nextHashChangePrevented( true );
}
}
},