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

fix($browser): prevent infinite $digest from no trailing slash in IE9 #11675

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/ng/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,26 @@ function Browser(window, document, $log, $sniffer) {
cacheState();
lastHistoryState = cachedState;

/**
* @name $browser#forceReloadLocationUpdate
*
* @description
* This method is a setter.
*
* If the reloadLocation variable is already set, it will be reset to
* the passed-in URL.
*
* NOTE: this api is intended for use only by the $location service in the
* $locationWatch function.
*
* @param {string} url New url
*/
self.forceReloadLocationUpdate = function(url) {
if (reloadLocation) {
reloadLocation = url;
}
};

/**
* @name $browser#url
*
Expand Down
49 changes: 29 additions & 20 deletions src/ng/location.js
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,7 @@ function $LocationProvider() {
$browser.url($location.absUrl(), true);
}

var initializing = true;
var initializing = true, previousOldUrl = null, previousNewUrl = null;

// update $location when $browser url changes
$browser.onUrlChange(function(newUrl, newState) {
Expand Down Expand Up @@ -934,26 +934,35 @@ function $LocationProvider() {
if (initializing || urlOrStateChanged) {
initializing = false;

$rootScope.$evalAsync(function() {
var newUrl = $location.absUrl();
var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
$location.$$state, oldState).defaultPrevented;

// if the location was changed by a `$locationChangeStart` handler then stop
// processing this location change
if ($location.absUrl() !== newUrl) return;

if (defaultPrevented) {
$location.$$parse(oldUrl);
$location.$$state = oldState;
} else {
if (urlOrStateChanged) {
setBrowserUrlWithFallback(newUrl, currentReplace,
oldState === $location.$$state ? null : $location.$$state);
if ((previousOldUrl !== oldUrl) || (previousNewUrl !== newUrl)) {
previousOldUrl = oldUrl, previousNewUrl = newUrl;

$rootScope.$evalAsync(function() {
var newUrl = $location.absUrl();
var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
$location.$$state, oldState).defaultPrevented;

// if the location was changed by a `$locationChangeStart` handler then stop
// processing this location change
if ($location.absUrl() !== newUrl) return;

if (defaultPrevented) {
$location.$$parse(oldUrl);
$location.$$state = oldState;
} else {
if (urlOrStateChanged) {
setBrowserUrlWithFallback(newUrl, currentReplace,
oldState === $location.$$state ? null : $location.$$state);
}
afterLocationChange(oldUrl, oldState);
}
afterLocationChange(oldUrl, oldState);
}
});
});
} else {
$browser.forceReloadLocationUpdate(newUrl);
previousOldUrl = previousNewUrl = false;
}
} else {
previousOldUrl = previousNewUrl = false;
}

$location.$$replace = false;
Expand Down
54 changes: 44 additions & 10 deletions src/ngMock/angular-mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,20 @@ angular.mock = {};
* that there are several helper methods available which can be used in tests.
*/
angular.mock.$BrowserProvider = function() {
this.$get = function() {
return new angular.mock.$Browser();
};
this.$get = ['$sniffer', function($sniffer) {
return new angular.mock.$Browser($sniffer);
}];
};

angular.mock.$Browser = function() {
angular.mock.$Browser = function($sniffer) {
var self = this;

this.isMock = true;
self.$$url = "http://server/";
self.$$lastUrl = self.$$url; // used by url polling fn
self.$$reloadLocation = null;
self.$$sniffer = $sniffer;
self.$$simulateLocationUpdate = false;
self.pollFns = [];

// TODO(vojta): remove this temporary api
Expand All @@ -46,9 +49,11 @@ angular.mock.$Browser = function() {
self.onUrlChange = function(listener) {
self.pollFns.push(
function() {
if (self.$$lastUrl !== self.$$url || self.$$state !== self.$$lastState) {
self.$$lastUrl = self.$$url;
var currUrl = self.$$reloadLocation || self.$$url;
if (self.$$simulateLocationUpdate || self.$$lastUrl !== currUrl || self.$$state !== self.$$lastState) {
self.$$lastUrl = currUrl;
self.$$lastState = self.$$state;
self.$$simulateLocationUpdate = false;
listener(self.$$url, self.$$state);
}
}
Expand Down Expand Up @@ -150,20 +155,43 @@ angular.mock.$Browser.prototype = {
state = null;
}
if (url) {
var sameState = this.$$lastState === state;

if (this.$$lastUrl === url && (!this.$$sniffer.history || sameState)) {
return this;
}

var index = this.$$lastUrl.indexOf('#');
var lastUrlStripped = (index === -1 ? this.$$lastUrl : this.$$lastUrl.substr(0, index));
index = url.indexOf('#');
var urlStripped = (index === -1 ? url : url.substr(0, index));

this.$$lastState = angular.copy(state);

var sameBase = this.$$lastUrl && lastUrlStripped === urlStripped;
if (this.$$sniffer.history && (!sameBase || !sameState)) {
// Native pushState serializes & copies the object; simulate it.
this.$$state = angular.copy(state);
this.$$lastState = this.$$state;
}
if (!sameBase) {
this.$$reloadLocation = url;
}
this.$$url = url;
// Native pushState serializes & copies the object; simulate it.
this.$$state = angular.copy(state);
this.$$lastUrl = url;
this.$$simulateLocationUpdate = true;

return this;
}

return this.$$url;
return this.$$reloadLocation || this.$$url;
},

state: function() {
return this.$$state;
},

cookies: function(name, value) {
cookies: function(name, value) {
if (name) {
if (angular.isUndefined(value)) {
delete this.cookieHash[name];
Expand All @@ -184,6 +212,12 @@ angular.mock.$Browser.prototype = {

notifyWhenNoOutstandingRequests: function(fn) {
fn();
},

forceReloadLocationUpdate: function(url) {
if (this.$$reloadLocation) {
this.$$reloadLocation = url;
}
}
};

Expand Down
Loading