Permalink
Browse files

address browsers that don't fire popstate on hash assignment Fixes #5414

  • Loading branch information...
1 parent b36f023 commit 6602c21fe45f57aa7b18f10af87933dac06770a0 @johnbender johnbender committed Jan 8, 2013
Showing with 31 additions and 23 deletions.
  1. +0 −1 js/jquery.mobile.navigation.js
  2. +31 −22 js/navigation/navigator.js
@@ -1181,7 +1181,6 @@ define( [
});
$.mobile._handleHashChange = function( url, data ) {
-
//find first page via hash
var to = path.stripHash(url),
//transition is false if it's the first page, undefined otherwise (and may be overridden by default)
@@ -9,6 +9,13 @@ define([ "jquery", "../events/navigate", "./path", "./history" ], function( $ )
$.Navigator = function( history ) {
this.history = history;
+ this.ignoreInitialHashChange = true;
+
+ // This ensures that browsers which don't fire the initial popstate
+ // like opera don't have further hash assignment popstates blocked
+ setTimeout($.proxy(function() {
+ this.ignoreInitialHashChange = false;
+ }, this), 200);
$.mobile.window.bind({
"popstate.history": $.proxy( this.popstate, this ),
@@ -18,8 +25,7 @@ define([ "jquery", "../events/navigate", "./path", "./history" ], function( $ )
$.extend($.Navigator.prototype, {
squash: function( url, data ) {
- var state, href, self = this,
- hash = path.isPath(url) ? path.stripHash(url) : url;
+ var state, href, hash = path.isPath(url) ? path.stripHash(url) : url;
href = path.squash( url );
@@ -42,19 +48,6 @@ define([ "jquery", "../events/navigate", "./path", "./history" ], function( $ )
// is not fired.
window.history.replaceState( state, state.title || document.title, href );
-
- // If popstate is enabled and the browser triggers `popstate` events when the hash
- // is set (this often happens immediately in browsers like Chrome), then the
- // this flag will be set to false already. If it's a browser that does not trigger
- // a `popstate` on hash assignement or `replaceState` then we need to unlock the
- // At the time of this writing this happens with Opera 12
- // NOTE I hate the fact that we have to do this but it captures all the possible
- // issues with browsers that won't trigger a popstate in either case
- // ie, hash assignment/replaceState
- setTimeout(function() {
- self.ignoreNextHashChange = false;
- }, 100);
-
return state;
},
@@ -85,7 +78,7 @@ define([ "jquery", "../events/navigate", "./path", "./history" ], function( $ )
// TODO reconsider name
go: function( url, data, noEvents ) {
- var state, href, hash, popstateEvent;
+ var state, href, hash, popstateEvent,
isPopStateEvent = $.event.special.navigate.isPushStateEnabled();
// Get the url as it would look squashed on to the current resolution url
@@ -115,15 +108,21 @@ define([ "jquery", "../events/navigate", "./path", "./history" ], function( $ )
// the current url.
window.location.hash = hash;
+ // If popstate is enabled and the browser triggers `popstate` events when the hash
+ // is set (this often happens immediately in browsers like Chrome), then the
+ // this flag will be set to false already. If it's a browser that does not trigger
+ // a `popstate` on hash assignement or `replaceState` then we need avoid the branch
+ // that swallows the event created by the popstate generated by the hash assignment
+ // At the time of this writing this happens with Opera 12 and some version of IE
+ this.ignoreNextHashChange = false;
+
state = $.extend({
url: href,
hash: hash,
title: document.title
}, data);
if( isPopStateEvent ) {
-
-
popstateEvent = new $.Event( "popstate" );
popstateEvent.originalEvent = {
type: "popstate",
@@ -178,6 +177,17 @@ define([ "jquery", "../events/navigate", "./path", "./history" ], function( $ )
return;
}
+ // If there is no state, and the history stack length is one were
+ // probably getting the page load popstate fired by browsers like chrome
+ // avoid it and set the one time flag to false
+ if( !event.originalEvent.state
+ && this.history.stack.length == 1
+ && this.ignoreInitialHashChange ) {
+ this.ignoreInitialHashChange = false;
+
+ return;
+ }
+
// account for direct manipulation of the hash. That is, we will receive a popstate
// when the hash is changed by assignment, and it won't have a state associated. We
// then need to squash the hash. See below for handling of hash assignment that
@@ -186,10 +196,9 @@ define([ "jquery", "../events/navigate", "./path", "./history" ], function( $ )
hash = path.parseLocation().hash;
active = this.history.getActive();
- // Avoid adding a history entry in two cases
- // 1) on the initial hashchange
- // 2) when the current history entry hash is identical to the
- // current location hash
+ // We want to avoid adding a history entry in for the initial
+ // hash change, but we also want to permit hash assignment to work
+ // when there is only
if( this.history.stack.length !== 1 || hash !== active.hash ) {
state = $.navigate.navigator.squash( hash );
// TODO it might be better to only add to the history stack

0 comments on commit 6602c21

Please sign in to comment.