@@ -42,18 +42,14 @@ define([
4242 // NOTE we currently _leave_ the appended hash in the hash in the interest
4343 // of seeing what happens and if we can support that before the hash is
4444 // pushed down
45-
46- // set the hash to be squashed by replace state or picked up by
47- // the navigation special event
48- history . ignoreNextHashChange = true ;
49-
5045 // IMPORTANT in the case where popstate is supported the event will be triggered
5146 // directly, stopping further execution - ie, interupting the flow of this
5247 // method call to fire bindings at this expression. Below the navigate method
5348 // there is a binding to catch this event and stop its propagation.
5449 //
5550 // We then trigger a new popstate event on the window with a null state
5651 // so that the navigate events can conclude their work properly
52+ history . ignoreNextHashChange = true ;
5753 window . location . hash = url ;
5854
5955 if ( $ . support . pushState ) {
@@ -75,7 +71,8 @@ define([
7571 // is not fired.
7672 window . history . replaceState ( state , document . title , href ) ;
7773
78- // Trigger a new faux popstate event to
74+ // Trigger a new faux popstate event to replace the one that we
75+ // caught that was triggered by the hash setting above.
7976 $ ( window ) . trigger ( popstateEvent ) ;
8077 }
8178
@@ -93,6 +90,12 @@ define([
9390 // TODO grab the original event here and use it for the synthetic event in the
9491 // second half of the navigate execution that will follow this binding
9592 $ ( window ) . bind ( "popstate" , function ( event ) {
93+ // Partly to support our test suite which manually alters the support
94+ // value to test hashchange. Partly to prevent all around weirdness
95+ if ( ! $ . support . pushState ) {
96+ return ;
97+ }
98+
9699 if ( history . ignoreNextHashChange ) {
97100 history . ignoreNextHashChange = false ;
98101 event . stopImmediatePropagation ( ) ;
@@ -121,9 +124,10 @@ define([
121124
122125
123126 history . direct ( {
124- currentUrl : path . parseLocation ( ) . hash ,
125- either : function ( historyEntry ) {
127+ url : path . parseLocation ( ) . hash ,
128+ either : function ( historyEntry , direction ) {
126129 event . hashchangeState = historyEntry ;
130+ event . hashchangeState . direction = direction ;
127131 }
128132 } ) ;
129133 } ) ;
@@ -170,27 +174,43 @@ define([
170174 this . stack = this . stack . slice ( 0 , this . activeIndex + 1 ) ;
171175 } ,
172176
173- direct : function ( opts ) {
174- var back , forward , newActiveIndex , prev = this . getActive ( ) , a = this . activeIndex ;
175-
176- // check if url is in history and if it's ahead or behind current page
177- $ . each ( this . stack , function ( i , historyEntry ) {
178- //if the url is in the stack, it's a forward or a back
179- if ( decodeURIComponent ( opts . currentUrl ) === decodeURIComponent ( historyEntry . url ) ) {
180- //define back and forward by whether url is older or newer than current page
181- back = i < this . activeIndex ;
182- forward = ! back ;
183- newActiveIndex = i ;
177+ find : function ( url , stack ) {
178+ var entry , i , length = this . stack . length , newActiveIndex ;
179+
180+ for ( i = 0 ; i < length ; i ++ ) {
181+ entry = this . stack [ i ] ;
182+
183+ if ( decodeURIComponent ( url ) === decodeURIComponent ( entry . url ) ) {
184+ return i ;
184185 }
185- } ) ;
186+ }
187+
188+ return undefined ;
189+ } ,
190+
191+ direct : function ( opts ) {
192+ var back , forward , entry , newActiveIndex , prev = this . getActive ( ) , a = this . activeIndex ;
193+
194+ // First, take the slice of the history stack before the current index and search
195+ // for a url match. If one is found, we'll avoid avoid looking through forward history
196+ // NOTE the preference for backward history movement is driven by the fact that
197+ // most mobile browsers only have a dedicated back button, and users rarely use
198+ // the forward button in desktop browser anyhow
199+ newActiveIndex = this . find ( opts . url , this . stack . slice ( 0 , a - 1 ) . reverse ( ) ) ;
200+
201+ // If nothing was found in backward history check forward
202+ if ( newActiveIndex === undefined ) {
203+ newActiveIndex = this . find ( opts . url , this . stack . slice ( a + 1 ) ) ;
204+ }
186205
187206 // save new page index, null check to prevent falsey 0 result
188207 this . activeIndex = newActiveIndex !== undefined ? newActiveIndex : this . activeIndex ;
189208
190- if ( back ) {
191- ( opts . either || opts . isBack ) ( this . getActive ( ) ) ;
192- } else if ( forward ) {
193- ( opts . either || opts . isForward ) ( this . getActive ( ) ) ;
209+ // invoke callbacks where appropriate
210+ if ( newActiveIndex < a ) {
211+ ( opts . either || opts . isBack ) ( this . getActive ( ) , 'back' ) ;
212+ } else if ( newActiveIndex > a ) {
213+ ( opts . either || opts . isForward ) ( this . getActive ( ) , 'forward' ) ;
194214 }
195215 } ,
196216
0 commit comments