Permalink
Browse files

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

  • Loading branch information...
johnbender committed Jan 8, 2013
1 parent b36f023 commit 6602c21fe45f57aa7b18f10af87933dac06770a0
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)
View
@@ -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.