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

Commit 0793a03

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 0793a03

File tree

2 files changed

+221
-72
lines changed

2 files changed

+221
-72
lines changed

src/ng/browser.js

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,14 @@ function Browser(window, document, $log, $sniffer) {
123123
// URL API
124124
//////////////////////////////////////////////////////////////
125125

126-
var lastBrowserUrl = location.href,
127-
lastHistoryState = history.state,
126+
var cachedState, lastHistoryState,
127+
lastBrowserUrl = location.href,
128128
baseElement = document.find('base'),
129129
reloadLocation = null;
130130

131+
cacheState();
132+
lastHistoryState = cachedState;
133+
131134
/**
132135
* @name $browser#url
133136
*
@@ -165,7 +168,7 @@ function Browser(window, document, $log, $sniffer) {
165168
// Don't change anything if previous and current URLs and states match. This also prevents
166169
// IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
167170
// 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)) {
169172
return;
170173
}
171174
var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
@@ -174,9 +177,8 @@ function Browser(window, document, $log, $sniffer) {
174177
// due to a bug in IE10/IE11 which leads
175178
// to not firing a `hashchange` nor `popstate` event
176179
// in some cases (see #9143).
177-
if ($sniffer.history && (!sameBase || history.state !== state)) {
180+
if ($sniffer.history && (!sameBase || cachedState !== state)) {
178181
history[replace ? 'replaceState' : 'pushState'](state, '', url);
179-
lastHistoryState = history.state;
180182
} else {
181183
if (!sameBase) {
182184
reloadLocation = url;
@@ -187,6 +189,8 @@ function Browser(window, document, $log, $sniffer) {
187189
location.href = url;
188190
}
189191
}
192+
lastHistoryState = cachedState;
193+
cachedState = state;
190194
return self;
191195
// getter
192196
} else {
@@ -208,20 +212,40 @@ function Browser(window, document, $log, $sniffer) {
208212
* @returns {object} state
209213
*/
210214
self.state = function() {
211-
return isUndefined(history.state) ? null : history.state;
215+
return cachedState;
212216
};
213217

214218
var urlChangeListeners = [],
215219
urlChangeInit = false;
216220

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+
217240
function fireUrlChange() {
218-
if (lastBrowserUrl === self.url() && lastHistoryState === history.state) {
241+
if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
219242
return;
220243
}
221244

222245
lastBrowserUrl = self.url();
246+
lastHistoryState = cachedState;
223247
forEach(urlChangeListeners, function(listener) {
224-
listener(self.url(), history.state);
248+
listener(self.url(), cachedState);
225249
});
226250
}
227251

@@ -254,9 +278,9 @@ function Browser(window, document, $log, $sniffer) {
254278
// changed by push/replaceState
255279

256280
// html5 history api - popstate event
257-
if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange);
281+
if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
258282
// hashchange event
259-
jqLite(window).on('hashchange', fireUrlChange);
283+
jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
260284

261285
urlChangeInit = true;
262286
}

0 commit comments

Comments
 (0)