From 1324db46ef9691ab0ea8403d23b06ec79b72b6dc Mon Sep 17 00:00:00 2001 From: Tobias Bosch Date: Tue, 26 Aug 2014 15:23:47 -0700 Subject: [PATCH 1/2] fix($browser): detect changes to the browser url that happened in sync Closes #6976. --- src/ng/browser.js | 7 +++++++ src/ng/rootScope.js | 2 ++ src/ngMock/angular-mocks.js | 2 ++ test/ng/locationSpec.js | 22 ++++++++++++++++++++++ 4 files changed, 33 insertions(+) diff --git a/src/ng/browser.js b/src/ng/browser.js index 3ca4a7c0a86c..7cc38e807a9c 100644 --- a/src/ng/browser.js +++ b/src/ng/browser.js @@ -234,6 +234,13 @@ function Browser(window, document, $log, $sniffer) { return callback; }; + /** + * Checks whether the url has changed outside of Angular. + * Needs to be exported to be able to check for changes that have been done in sync, + * as hashchange/popstate events fire in async. + */ + self.$$checkUrlChangedOutsideAngular = fireUrlChange; + ////////////////////////////////////////////////////////////// // Misc API ////////////////////////////////////////////////////////////// diff --git a/src/ng/rootScope.js b/src/ng/rootScope.js index 9938240a60e6..c4dc88a8209b 100644 --- a/src/ng/rootScope.js +++ b/src/ng/rootScope.js @@ -687,6 +687,8 @@ function $RootScopeProvider(){ logIdx, logMsg, asyncTask; beginPhase('$digest'); + // Check for changes to browser url that happened in sync with the call to $digest + $browser.$$checkUrlChangedOutsideAngular(); lastDirtyWatch = null; diff --git a/src/ngMock/angular-mocks.js b/src/ngMock/angular-mocks.js index ba9790539ff8..93aa5f8f463a 100644 --- a/src/ngMock/angular-mocks.js +++ b/src/ngMock/angular-mocks.js @@ -56,6 +56,8 @@ angular.mock.$Browser = function() { return listener; }; + self.$$checkUrlChangedOutsideAngular = angular.noop; + self.cookieHash = {}; self.lastCookieHash = {}; self.deferredFns = []; diff --git a/test/ng/locationSpec.js b/test/ng/locationSpec.js index ff36ce42a888..5436483d7ef6 100644 --- a/test/ng/locationSpec.js +++ b/test/ng/locationSpec.js @@ -769,6 +769,28 @@ describe('$location', function() { }); + it('should update location when location changed outside of Angular', function() { + module(function($windowProvider, $locationProvider, $browserProvider) { + $locationProvider.html5Mode(true); + $browserProvider.$get = function($document, $window, $log, $sniffer) { + var b = new Browser($window, $document, $log, $sniffer); + b.pollFns = []; + return b; + }; + }); + inject(function($rootScope, $browser, $location, $sniffer){ + if ($sniffer.history) { + window.history.replaceState(null, '', '/hello'); + // Verify that infinite digest reported in #6976 no longer occurs + expect(function() { + $rootScope.$digest(); + }).not.toThrow(); + expect($location.path()).toBe('/hello'); + } + }); + }); + + it('should rewrite when hashbang url given', function() { initService(true, '!', true); inject( From 2ff0f52ca7d2eae632997f6407c48c4e8a86123c Mon Sep 17 00:00:00 2001 From: Jeff Cross Date: Tue, 26 Aug 2014 17:24:08 -0700 Subject: [PATCH 2/2] SQUASH: add test for hash changes, fix IE 9 reload --- test/ng/locationSpec.js | 46 ++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/test/ng/locationSpec.js b/test/ng/locationSpec.js index 5436483d7ef6..a0d816df3550 100644 --- a/test/ng/locationSpec.js +++ b/test/ng/locationSpec.js @@ -769,25 +769,57 @@ describe('$location', function() { }); - it('should update location when location changed outside of Angular', function() { + it('should update url when location changed outside of Angular by changing hash', function() { + var fakeWindow = { + addEventListener: angular.noop, + location: { + replace: angular.noop, + href: '/hello' + }, + history: { + } + }; + module(function($windowProvider, $locationProvider, $browserProvider) { $locationProvider.html5Mode(true); - $browserProvider.$get = function($document, $window, $log, $sniffer) { - var b = new Browser($window, $document, $log, $sniffer); + $browserProvider.$get = function($document, $log, $sniffer) { + var b = new Browser(fakeWindow, $document, $log, $sniffer); b.pollFns = []; return b; }; }); - inject(function($rootScope, $browser, $location, $sniffer){ - if ($sniffer.history) { + + inject(function($rootScope, $location) { + fakeWindow.location.href = '/hello#goodbye'; + expect(function() { + $rootScope.$digest(); + }).not.toThrow(); + expect($location.hash()).toBe('goodbye'); + expect($location.url()).toBe('/hello#goodbye'); + }); + }); + + + it('should update url when location changed outside of Angular with replaceState', function() { + if (window.history.replaceState) { + module(function($windowProvider, $locationProvider, $browserProvider) { + $locationProvider.html5Mode(true); + $browserProvider.$get = function($document, $window, $log, $sniffer) { + var b = new Browser($window, $document, $log, $sniffer); + b.pollFns = []; + return b; + }; + }); + + inject(function($rootScope, $browser, $location, $sniffer){ window.history.replaceState(null, '', '/hello'); // Verify that infinite digest reported in #6976 no longer occurs expect(function() { $rootScope.$digest(); }).not.toThrow(); expect($location.path()).toBe('/hello'); - } - }); + }); + } });