mirror of
https://github.com/Hopiu/jquery-mobile.git
synced 2026-03-16 22:10:25 +00:00
162 lines
5.4 KiB
JavaScript
162 lines
5.4 KiB
JavaScript
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
|
|
//>>description: history.pushState support, layered on top of hashchange.
|
|
//>>label: Pushstate Support
|
|
|
|
define( [ "jquery", "jquery.mobile.navigation" ], function( $ ) {
|
|
//>>excludeEnd("jqmBuildExclude");
|
|
( 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,
|
|
|
|
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;
|
|
},
|
|
|
|
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;
|
|
self.onHashChangeDisabled = value;
|
|
},
|
|
|
|
// 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 ) {
|
|
// disable this hash change
|
|
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();
|
|
|
|
// make the hash abolute with the current href
|
|
href = $.mobile.path.makeUrlAbsolute( hash, resolutionUrl );
|
|
|
|
if ( isPath ) {
|
|
href = self.resetUIKeys( href );
|
|
}
|
|
|
|
// replace the current url with the new href and store the state
|
|
// Note that in some cases we might be replacing an url with the
|
|
// same url. We do this anyways because we need to make sure that
|
|
// all of our history entries have a state object associated with
|
|
// them. This allows us to work around the case where window.history.back()
|
|
// is called to transition from an external page to an embedded page.
|
|
// In that particular case, a hashchange event is *NOT* generated by the browser.
|
|
// Ensuring each history entry has a state object means that onPopState()
|
|
// will always trigger our hashchange callback even when a hashchange event
|
|
// is not fired.
|
|
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,
|
|
timeout, fromHash, toHash, hashChanged;
|
|
|
|
// if there's no state its not a popstate we care about, eg chrome's initial popstate
|
|
if( poppedState ) {
|
|
// 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 );
|
|
|
|
// 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("#", "") );
|
|
|
|
// 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 );
|
|
}
|
|
}
|
|
},
|
|
|
|
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 );
|
|
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
|
|
});
|
|
//>>excludeEnd("jqmBuildExclude");
|