Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 7b228dd

Browse files
committed
fix($browser): account for IE deserializing history.state on each read
IE 10-11+ deserialize history.state on every read, causing simple comparisons against history.state always return false. Account for that caching `history.state` on every hashchange or popstate event. Also, prevent firing onUrlChange callbacks twice if both popstate and hashchange event were fired. Closes #9587 Refs #9545
1 parent 874cac8 commit 7b228dd

File tree

2 files changed

+217
-71
lines changed

2 files changed

+217
-71
lines changed

src/ng/browser.js

+30-9
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ function Browser(window, document, $log, $sniffer) {
124124
//////////////////////////////////////////////////////////////
125125

126126
var lastBrowserUrl = location.href,
127-
lastHistoryState = history.state,
127+
cachedState = history.state,
128+
lastHistoryState = cachedState,
128129
baseElement = document.find('base'),
129130
reloadLocation = null;
130131

@@ -165,7 +166,7 @@ function Browser(window, document, $log, $sniffer) {
165166
// Don't change anything if previous and current URLs and states match. This also prevents
166167
// IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
167168
// See https://github.com/angular/angular.js/commit/ffb2701
168-
if (lastBrowserUrl === url && (!$sniffer.history || history.state === state)) {
169+
if (lastBrowserUrl === url && (!$sniffer.history || cachedState === state)) {
169170
return;
170171
}
171172
var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
@@ -174,9 +175,10 @@ function Browser(window, document, $log, $sniffer) {
174175
// due to a bug in IE10/IE11 which leads
175176
// to not firing a `hashchange` nor `popstate` event
176177
// in some cases (see #9143).
177-
if ($sniffer.history && (!sameBase || history.state !== state)) {
178+
if ($sniffer.history && (!sameBase || cachedState !== state)) {
178179
history[replace ? 'replaceState' : 'pushState'](state, '', url);
179-
lastHistoryState = history.state;
180+
lastHistoryState = cachedState;
181+
cachedState = state;
180182
} else {
181183
if (!sameBase) {
182184
reloadLocation = url;
@@ -208,20 +210,39 @@ function Browser(window, document, $log, $sniffer) {
208210
* @returns {object} state
209211
*/
210212
self.state = function() {
211-
return isUndefined(history.state) ? null : history.state;
213+
return cachedState;
212214
};
213215

214216
var urlChangeListeners = [],
215217
urlChangeInit = false;
216218

219+
function cacheStateAndFireUrlChange() {
220+
cacheState();
221+
fireUrlChange();
222+
}
223+
224+
// This variable should be used *only* inside the cacheState function.
225+
var lastCachedState;
226+
function cacheState() {
227+
cachedState = window.history.state;
228+
cachedState = isUndefined(cachedState) ? null : cachedState;
229+
230+
// Prevent callbacks fo fire twice if both hashchange & popstate were fired.
231+
if (equals(cachedState, lastCachedState)) {
232+
cachedState = lastCachedState;
233+
}
234+
lastCachedState = cachedState;
235+
}
236+
217237
function fireUrlChange() {
218-
if (lastBrowserUrl === self.url() && lastHistoryState === history.state) {
238+
if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
219239
return;
220240
}
221241

222242
lastBrowserUrl = self.url();
243+
lastHistoryState = cachedState;
223244
forEach(urlChangeListeners, function(listener) {
224-
listener(self.url(), history.state);
245+
listener(self.url(), cachedState);
225246
});
226247
}
227248

@@ -254,9 +275,9 @@ function Browser(window, document, $log, $sniffer) {
254275
// changed by push/replaceState
255276

256277
// html5 history api - popstate event
257-
if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange);
278+
if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
258279
// hashchange event
259-
jqLite(window).on('hashchange', fireUrlChange);
280+
jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
260281

261282
urlChangeInit = true;
262283
}

0 commit comments

Comments
 (0)