@@ -9,6 +9,13 @@ define([ "jquery", "../events/navigate", "./path", "./history" ], function( $ )
99
1010 $ . Navigator = function ( history ) {
1111 this . history = history ;
12+ this . ignoreInitialHashChange = true ;
13+
14+ // This ensures that browsers which don't fire the initial popstate
15+ // like opera don't have further hash assignment popstates blocked
16+ setTimeout ( $ . proxy ( function ( ) {
17+ this . ignoreInitialHashChange = false ;
18+ } , this ) , 200 ) ;
1219
1320 $ . mobile . window . bind ( {
1421 "popstate.history" : $ . proxy ( this . popstate , this ) ,
@@ -18,8 +25,7 @@ define([ "jquery", "../events/navigate", "./path", "./history" ], function( $ )
1825
1926 $ . extend ( $ . Navigator . prototype , {
2027 squash : function ( url , data ) {
21- var state , href , self = this ,
22- hash = path . isPath ( url ) ? path . stripHash ( url ) : url ;
28+ var state , href , hash = path . isPath ( url ) ? path . stripHash ( url ) : url ;
2329
2430 href = path . squash ( url ) ;
2531
@@ -42,19 +48,6 @@ define([ "jquery", "../events/navigate", "./path", "./history" ], function( $ )
4248 // is not fired.
4349 window . history . replaceState ( state , state . title || document . title , href ) ;
4450
45-
46- // If popstate is enabled and the browser triggers `popstate` events when the hash
47- // is set (this often happens immediately in browsers like Chrome), then the
48- // this flag will be set to false already. If it's a browser that does not trigger
49- // a `popstate` on hash assignement or `replaceState` then we need to unlock the
50- // At the time of this writing this happens with Opera 12
51- // NOTE I hate the fact that we have to do this but it captures all the possible
52- // issues with browsers that won't trigger a popstate in either case
53- // ie, hash assignment/replaceState
54- setTimeout ( function ( ) {
55- self . ignoreNextHashChange = false ;
56- } , 100 ) ;
57-
5851 return state ;
5952 } ,
6053
@@ -85,7 +78,7 @@ define([ "jquery", "../events/navigate", "./path", "./history" ], function( $ )
8578
8679 // TODO reconsider name
8780 go : function ( url , data , noEvents ) {
88- var state , href , hash , popstateEvent ;
81+ var state , href , hash , popstateEvent ,
8982 isPopStateEvent = $ . event . special . navigate . isPushStateEnabled ( ) ;
9083
9184 // 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( $ )
115108 // the current url.
116109 window . location . hash = hash ;
117110
111+ // If popstate is enabled and the browser triggers `popstate` events when the hash
112+ // is set (this often happens immediately in browsers like Chrome), then the
113+ // this flag will be set to false already. If it's a browser that does not trigger
114+ // a `popstate` on hash assignement or `replaceState` then we need avoid the branch
115+ // that swallows the event created by the popstate generated by the hash assignment
116+ // At the time of this writing this happens with Opera 12 and some version of IE
117+ this . ignoreNextHashChange = false ;
118+
118119 state = $ . extend ( {
119120 url : href ,
120121 hash : hash ,
121122 title : document . title
122123 } , data ) ;
123124
124125 if ( isPopStateEvent ) {
125-
126-
127126 popstateEvent = new $ . Event ( "popstate" ) ;
128127 popstateEvent . originalEvent = {
129128 type : "popstate" ,
@@ -178,6 +177,17 @@ define([ "jquery", "../events/navigate", "./path", "./history" ], function( $ )
178177 return ;
179178 }
180179
180+ // If there is no state, and the history stack length is one were
181+ // probably getting the page load popstate fired by browsers like chrome
182+ // avoid it and set the one time flag to false
183+ if ( ! event . originalEvent . state
184+ && this . history . stack . length == 1
185+ && this . ignoreInitialHashChange ) {
186+ this . ignoreInitialHashChange = false ;
187+
188+ return ;
189+ }
190+
181191 // account for direct manipulation of the hash. That is, we will receive a popstate
182192 // when the hash is changed by assignment, and it won't have a state associated. We
183193 // 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( $ )
186196 hash = path . parseLocation ( ) . hash ;
187197 active = this . history . getActive ( ) ;
188198
189- // Avoid adding a history entry in two cases
190- // 1) on the initial hashchange
191- // 2) when the current history entry hash is identical to the
192- // current location hash
199+ // We want to avoid adding a history entry in for the initial
200+ // hash change, but we also want to permit hash assignment to work
201+ // when there is only
193202 if ( this . history . stack . length !== 1 || hash !== active . hash ) {
194203 state = $ . navigate . navigator . squash ( hash ) ;
195204 // TODO it might be better to only add to the history stack
0 commit comments