@@ -123,11 +123,14 @@ function Browser(window, document, $log, $sniffer) {
123
123
// URL API
124
124
//////////////////////////////////////////////////////////////
125
125
126
- var lastBrowserUrl = location . href ,
127
- lastHistoryState = history . state ,
126
+ var cachedState , lastHistoryState ,
127
+ lastBrowserUrl = location . href ,
128
128
baseElement = document . find ( 'base' ) ,
129
129
reloadLocation = null ;
130
130
131
+ cacheState ( ) ;
132
+ lastHistoryState = cachedState ;
133
+
131
134
/**
132
135
* @name $browser#url
133
136
*
@@ -165,7 +168,7 @@ function Browser(window, document, $log, $sniffer) {
165
168
// Don't change anything if previous and current URLs and states match. This also prevents
166
169
// IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
167
170
// See https://github.com/angular/angular.js/commit/ffb2701
168
- if ( lastBrowserUrl === url && ( ! $sniffer . history || history . state === state ) ) {
171
+ if ( lastBrowserUrl === url && ( ! $sniffer . history || cachedState === state ) ) {
169
172
return ;
170
173
}
171
174
var sameBase = lastBrowserUrl && stripHash ( lastBrowserUrl ) === stripHash ( url ) ;
@@ -174,9 +177,8 @@ function Browser(window, document, $log, $sniffer) {
174
177
// due to a bug in IE10/IE11 which leads
175
178
// to not firing a `hashchange` nor `popstate` event
176
179
// in some cases (see #9143).
177
- if ( $sniffer . history && ( ! sameBase || history . state !== state ) ) {
180
+ if ( $sniffer . history && ( ! sameBase || cachedState !== state ) ) {
178
181
history [ replace ? 'replaceState' : 'pushState' ] ( state , '' , url ) ;
179
- lastHistoryState = history . state ;
180
182
} else {
181
183
if ( ! sameBase ) {
182
184
reloadLocation = url ;
@@ -187,6 +189,8 @@ function Browser(window, document, $log, $sniffer) {
187
189
location . href = url ;
188
190
}
189
191
}
192
+ lastHistoryState = cachedState ;
193
+ cachedState = state ;
190
194
return self ;
191
195
// getter
192
196
} else {
@@ -208,20 +212,40 @@ function Browser(window, document, $log, $sniffer) {
208
212
* @returns {object } state
209
213
*/
210
214
self . state = function ( ) {
211
- return isUndefined ( history . state ) ? null : history . state ;
215
+ return cachedState ;
212
216
} ;
213
217
214
218
var urlChangeListeners = [ ] ,
215
219
urlChangeInit = false ;
216
220
221
+ function cacheStateAndFireUrlChange ( ) {
222
+ cacheState ( ) ;
223
+ fireUrlChange ( ) ;
224
+ }
225
+
226
+ // This variable should be used *only* inside the cacheState function.
227
+ var lastCachedState = null ;
228
+ function cacheState ( ) {
229
+ // This should be the only place in $browser where `history.state` is read.
230
+ cachedState = window . history . state ;
231
+ cachedState = isUndefined ( cachedState ) ? null : cachedState ;
232
+
233
+ // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
234
+ if ( equals ( cachedState , lastCachedState ) ) {
235
+ cachedState = lastCachedState ;
236
+ }
237
+ lastCachedState = cachedState ;
238
+ }
239
+
217
240
function fireUrlChange ( ) {
218
- if ( lastBrowserUrl === self . url ( ) && lastHistoryState === history . state ) {
241
+ if ( lastBrowserUrl === self . url ( ) && lastHistoryState === cachedState ) {
219
242
return ;
220
243
}
221
244
222
245
lastBrowserUrl = self . url ( ) ;
246
+ lastHistoryState = cachedState ;
223
247
forEach ( urlChangeListeners , function ( listener ) {
224
- listener ( self . url ( ) , history . state ) ;
248
+ listener ( self . url ( ) , cachedState ) ;
225
249
} ) ;
226
250
}
227
251
@@ -254,9 +278,9 @@ function Browser(window, document, $log, $sniffer) {
254
278
// changed by push/replaceState
255
279
256
280
// html5 history api - popstate event
257
- if ( $sniffer . history ) jqLite ( window ) . on ( 'popstate' , fireUrlChange ) ;
281
+ if ( $sniffer . history ) jqLite ( window ) . on ( 'popstate' , cacheStateAndFireUrlChange ) ;
258
282
// hashchange event
259
- jqLite ( window ) . on ( 'hashchange' , fireUrlChange ) ;
283
+ jqLite ( window ) . on ( 'hashchange' , cacheStateAndFireUrlChange ) ;
260
284
261
285
urlChangeInit = true ;
262
286
}
0 commit comments