diff --git a/js/jquery.mobile.navigation.js b/js/jquery.mobile.navigation.js index 2b9e029a..afcb6d1f 100755 --- a/js/jquery.mobile.navigation.js +++ b/js/jquery.mobile.navigation.js @@ -1351,7 +1351,12 @@ //if to is defined, load it if ( to ) { - to = ( typeof to === "string" && !path.isPath( to ) ) ? ( '#' + to ) : to; + // At this point, 'to' can be one of 3 things, a cached page element from + // a history stack entry, an id, or site-relative/absolute URL. If 'to' is + // an id, we need to resolve it against the documentBase, not the location.href, + // since the hashchange could've been the result of a forward/backward navigation + // that crosses from an external page/dialog to an internal page/dialog. + to = ( typeof to === "string" && !path.isPath( to ) ) ? ( path.makeUrlAbsolute( '#' + to, documentBase ) ) : to; $.mobile.changePage( to, changePageOptions ); } else { //there's no hash, go to the first page in the dom diff --git a/js/jquery.mobile.navigation.pushstate.js b/js/jquery.mobile.navigation.pushstate.js index 03f3c1ff..0eb99bd6 100644 --- a/js/jquery.mobile.navigation.pushstate.js +++ b/js/jquery.mobile.navigation.pushstate.js @@ -52,24 +52,34 @@ // 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; + var href, state, + hash = location.hash, + isPath = $.mobile.path.isPath( hash ); + hash = isPath ? hash.replace( "#", "" ) : hash; 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(); - // 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 ); + // make the hash abolute with the current href + href = $.mobile.path.makeUrlAbsolute( hash, location.href ); + if ( isPath ) { href = self.resetUIKeys( href ); - - // replace the current url with the new href and store the state - history.replaceState( state, document.title, 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 diff --git a/tests/unit/navigation/navigation_core.js b/tests/unit/navigation/navigation_core.js index 2c5a87cf..37406ebb 100644 --- a/tests/unit/navigation/navigation_core.js +++ b/tests/unit/navigation/navigation_core.js @@ -43,6 +43,36 @@ } }); + asyncTest( "window.history.back() from external to internal page", function(){ + + $.testHelper.pageSequence([ + + // open our test page + function(){ + $.testHelper.openPage("#active-state-page1"); + }, + + function(){ + ok( $.mobile.activePage[0] === $( "#active-state-page1" )[ 0 ], "successful navigation to internal page." ); + + //location.hash = siteDirectory + "external.html"; + $.mobile.changePage("external.html"); + }, + + function(){ + ok( $.mobile.activePage[0] !== $( "#active-state-page1" )[ 0 ], "successful navigation to external page." ); + + window.history.back(); + }, + + function(){ + ok( $.mobile.activePage[0] === $( "#active-state-page1" )[ 0 ], "successful navigation back to internal page." ); + + start(); + } + ]); + }); + asyncTest( "external page is removed from the DOM after pagehide", function(){ $.testHelper.pageSequence([ navigateTestRoot,