Skip to content

Commit 3993257

Browse files
author
Gabriel Schulhof
committed
Navigation: Tag replaceState() and internal history state with unique id
Closes jquery-archivegh-7613 Fixes jquery-archivegh-7602
1 parent 9951e54 commit 3993257

File tree

4 files changed

+59
-7
lines changed

4 files changed

+59
-7
lines changed

js/navigation/history.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,29 @@ define([ "jquery", "./../ns", "./path" ], function( jQuery ) {
7474
return index;
7575
},
7676

77-
closest: function( url ) {
78-
var closest, a = this.activeIndex;
77+
_findById: function( id ) {
78+
var stackIndex,
79+
stackLength = this.stack.length;
7980

80-
// First, take the slice of the history stack before the current index and search
81+
for ( stackIndex = 0 ; stackIndex < stackLength ; stackIndex++ ) {
82+
if ( this.stack[ stackIndex ].id === id ) {
83+
break;
84+
}
85+
}
86+
87+
return ( stackIndex < stackLength ? stackIndex : undefined );
88+
},
89+
90+
closest: function( url, id ) {
91+
var closest = ( id === undefined ? undefined : this._findById( id ) ),
92+
a = this.activeIndex;
93+
94+
// First, we check whether we've found an entry by id. If so, we're done.
95+
if ( closest !== undefined ) {
96+
return closest;
97+
}
98+
99+
// Failing that take the slice of the history stack before the current index and search
81100
// for a url match. If one is found, we'll avoid avoid looking through forward history
82101
// NOTE the preference for backward history movement is driven by the fact that
83102
// most mobile browsers only have a dedicated back button, and users rarely use
@@ -100,7 +119,7 @@ define([ "jquery", "./../ns", "./path" ], function( jQuery ) {
100119
},
101120

102121
direct: function( opts ) {
103-
var newActiveIndex = this.closest( opts.url ), a = this.activeIndex;
122+
var newActiveIndex = this.closest( opts.url, opts.id ), a = this.activeIndex;
104123

105124
// save new page index, null check to prevent falsey 0 result
106125
// record the previous index for reference

js/navigation/navigator.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ define(["jquery",
2424
};
2525

2626
$.extend($.mobile.Navigator.prototype, {
27+
historyEntryId: 0,
2728
squash: function( url, data ) {
2829
var state, href, hash = path.isPath(url) ? path.stripHash(url) : url;
2930

@@ -32,6 +33,7 @@ define(["jquery",
3233
// make sure to provide this information when it isn't explicitly set in the
3334
// data object that was passed to the squash method
3435
state = $.extend({
36+
id: ++this.historyEntryId,
3537
hash: hash,
3638
url: href
3739
}, data);
@@ -129,7 +131,7 @@ define(["jquery",
129131
state: null
130132
};
131133

132-
this.squash( url, state );
134+
state.id = ( this.squash( url, state ) || {} ).id;
133135

134136
// Trigger a new faux popstate event to replace the one that we
135137
// caught that was triggered by the hash setting above.
@@ -220,6 +222,7 @@ define(["jquery",
220222
// If all else fails this is a popstate that comes from the back or forward buttons
221223
// make sure to set the state of our history stack properly, and record the directionality
222224
this.history.direct({
225+
id: ( event.originalEvent.state || {} ).id,
223226
url: (event.originalEvent.state || {}).url || hash,
224227

225228
// When the url is either forward or backward in history include the entry

tests/integration/navigation/method/method_core.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,36 @@ $.testHelper.setPushState();
117117
]);
118118
});
119119

120+
asyncTest( "Entries with identical URLs are distinguishable when pushState is enabled",
121+
function() {
122+
$.testHelper.eventSequence( "navigate", [
123+
function() {
124+
$.mobile.navigate( "#foo" );
125+
},
126+
function() {
127+
$.mobile.navigate( "#bar" );
128+
},
129+
function() {
130+
$.mobile.navigate( "#foo" );
131+
},
132+
function() {
133+
deepEqual( $.mobile.navigate.history.activeIndex, $.support.pushState ? 2 : 0,
134+
"After sequence start -> #foo -> #bar -> #foo activeIndex is correct" );
135+
window.history.back();
136+
},
137+
function() {
138+
deepEqual( $.mobile.navigate.history.activeIndex, 1,
139+
"After going back once in the sequence the activeIndex is correct" );
140+
window.history.forward();
141+
},
142+
function() {
143+
deepEqual( $.mobile.navigate.history.activeIndex, $.support.pushState ? 2 : 0,
144+
"After returning to the last sequnce entry the activeIndex is correct" );
145+
start();
146+
}
147+
]);
148+
});
149+
120150
asyncTest( "setting the hash with a url not in history should always create a new history entry", function() {
121151
$.testHelper.eventTarget = $( window );
122152

tests/integration/navigation/navigation_core.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ $.testHelper.delayStart();
6161
function(){
6262
ok( $.mobile.activePage[0] === $( "#active-state-page1" )[ 0 ], "successful navigation to internal page." );
6363

64-
$.testHelper.openPage("#/tests/integration/navigation/external.html");
64+
$.testHelper.openPage( "#" + $.mobile.path.parseLocation().directory + "external.html" );
6565
},
6666

6767
function() {
68-
ok( $.mobile.activePage.attr("id"), "external-test", "successful navigation to external page." );
68+
deepEqual( $.mobile.activePage.attr("id"), "external-test", "successful navigation to external page." );
6969
window.history.back();
7070
},
7171

0 commit comments

Comments
 (0)