From 6a56461135d45bdce16732f93d0394603156d2d0 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Mon, 21 Mar 2016 10:43:49 +0000 Subject: [PATCH 1/2] chore(.gitignore): ignore Visual Studio Code settings --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index dcfa68efd8e1..d209a68a412c 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ libpeerconnection.log npm-debug.log /tmp/ /scripts/bower/bower-* +.vscode \ No newline at end of file From 5ee1f00b8e4b093ea63f8b0db8b8d70e80e3f560 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Wed, 9 Mar 2016 10:16:19 +0000 Subject: [PATCH 2/2] feat($location): default hashPrefix to '!' The $location service is designed to support hash prefixed URLs for cases where the browser does not support HTML5 push-state navigation. The Google Ajax Crawling Scheme expects that local paths within a SPA start with a hash-bang (e.g. `somedomain.com/base/path/#!/client/side/path`). The `$locationProvide` allows the application developer to configure the hashPrefix, and it is normal to set this to a bang '!', but the default has always been the empty string ''. This has caused some confusion where a user is not aware of this feature and wonders why adding a hash value to the location (e.g. `$location.hash('xxx')`) results in a double hash: `##xxx`. This commit changes the default value of the prefix to '!', which is more natural and expected. See https://developers.google.com/webmasters/ajax-crawling/docs/getting-started Closes #13812 BREAKING CHANGE The hash-prefix for `$location` hash-bang URLs has changed from the empty string "" to the bang "!". If your application does not use HTML5 mode or is being run on browsers that do not support HTML5 mode, and you have not specified your own hash-prefix then client side URLs will now contain a "!" prefix. For example, rather than `mydomain.com/#/a/b/c` will become `mydomain/#!/a/b/c`. If you actually wanted to have no hash-prefix then you should configure this by adding a configuration block to you application: ``` appModule.config(['$locationProvider', function($locationProvider) { $locationProvider.hashPrefix(""); }]); ``` --- docs/content/guide/$location.ngdoc | 4 +- src/ng/location.js | 3 +- test/ng/browserSpecs.js | 14 +-- test/ng/locationSpec.js | 154 ++++++++++++++++------------- test/ngRoute/routeSpec.js | 2 +- 5 files changed, 100 insertions(+), 77 deletions(-) diff --git a/docs/content/guide/$location.ngdoc b/docs/content/guide/$location.ngdoc index d2d1074df64f..9d8481b34e51 100644 --- a/docs/content/guide/$location.ngdoc +++ b/docs/content/guide/$location.ngdoc @@ -99,11 +99,11 @@ To configure the `$location` service, retrieve the - **hashPrefix(prefix)**: {string}
prefix used for Hashbang URLs (used in Hashbang mode or in legacy browser in Html5 mode)
- default: `""` + default: `"!"` ### Example configuration ```js -$locationProvider.html5Mode(true).hashPrefix('!'); +$locationProvider.html5Mode(true).hashPrefix('*'); ``` ## Getter and setter methods diff --git a/src/ng/location.js b/src/ng/location.js index 3c91549b53b4..655f8784f414 100644 --- a/src/ng/location.js +++ b/src/ng/location.js @@ -701,7 +701,7 @@ function locationGetterSetter(property, preprocess) { * Use the `$locationProvider` to configure how the application deep linking paths are stored. */ function $LocationProvider() { - var hashPrefix = '', + var hashPrefix = '!', html5Mode = { enabled: false, requireBase: true, @@ -712,6 +712,7 @@ function $LocationProvider() { * @ngdoc method * @name $locationProvider#hashPrefix * @description + * The default value for the prefix is `'!'`. * @param {string=} prefix Prefix for hash part (containing path and search) * @returns {*} current value if used as getter or itself (chaining) if used as setter */ diff --git a/test/ng/browserSpecs.js b/test/ng/browserSpecs.js index 35f45cce6fdf..6630a6383b59 100755 --- a/test/ng/browserSpecs.js +++ b/test/ng/browserSpecs.js @@ -755,9 +755,9 @@ describe('browser', function() { $rootScope.$apply(function() { $location.path('/initialPath'); }); - expect(fakeWindow.location.href).toBe('http://server/#/initialPath'); + expect(fakeWindow.location.href).toBe('http://server/#!/initialPath'); - fakeWindow.location.href = 'http://server/#/someTestHash'; + fakeWindow.location.href = 'http://server/#!/someTestHash'; $rootScope.$digest(); @@ -774,9 +774,9 @@ describe('browser', function() { $rootScope.$apply(function() { $location.path('/initialPath'); }); - expect(fakeWindow.location.href).toBe('http://server/#/initialPath'); + expect(fakeWindow.location.href).toBe('http://server/#!/initialPath'); - fakeWindow.location.href = 'http://server/#/someTestHash'; + fakeWindow.location.href = 'http://server/#!/someTestHash'; $rootScope.$digest(); @@ -793,9 +793,9 @@ describe('browser', function() { $rootScope.$apply(function() { $location.path('/initialPath'); }); - expect(fakeWindow.location.href).toBe('http://server/#/initialPath'); + expect(fakeWindow.location.href).toBe('http://server/#!/initialPath'); - fakeWindow.location.href = 'http://server/#/someTestHash'; + fakeWindow.location.href = 'http://server/#!/someTestHash'; $rootScope.$digest(); @@ -846,7 +846,7 @@ describe('browser', function() { $rootScope.$digest(); // from $location for rewriting the initial url into a hash url - expect(browser.url).toHaveBeenCalledWith('http://server/#/some/deep/path', true); + expect(browser.url).toHaveBeenCalledWith('http://server/#!/some/deep/path', true); expect(changeUrlCount).toBe(1); }); diff --git a/test/ng/locationSpec.js b/test/ng/locationSpec.js index 07efc1bbe776..6048ac7fc4cb 100644 --- a/test/ng/locationSpec.js +++ b/test/ng/locationSpec.js @@ -13,6 +13,28 @@ describe('$location', function() { }); + describe('defaults', function() { + it('should have hashPrefix of "!"', function() { + initService({}); + inject( + initBrowser({ url: 'http://host.com/base/index.html', basePath: '/base/index.html' }), + function($location) { + $location.path('/a/b/c'); + expect($location.absUrl()).toEqual('http://host.com/base/index.html#!/a/b/c'); + }); + }); + + it('should not be html5 mode', function() { + initService({}); + inject( + initBrowser({ url: 'http://host.com/base/index.html', basePath: '/base/index.html' }), + function($location) { + $location.path('/a/b/c'); + expect($location.absUrl()).toContain('#!'); + }); + }); + }); + describe('File Protocol', function() { /* global urlParsingNode: true */ var urlParsingNodePlaceholder; @@ -676,10 +698,10 @@ describe('$location', function() { $location.path('/').replace(); } }); - expect($browser.url()).toEqual('http://server/base/#/home'); + expect($browser.url()).toEqual('http://server/base/#!/home'); $rootScope.$digest(); expect(handlerCalled).toEqual(true); - expect($browser.url()).toEqual('http://server/base/#/'); + expect($browser.url()).toEqual('http://server/base/#!/'); } ); }); @@ -716,7 +738,7 @@ describe('$location', function() { $rootScope.$digest(); - expect($browser.url()).toEqual('http://server/app/#/Home'); + expect($browser.url()).toEqual('http://server/app/#!/Home'); expect($location.path()).toEqual('/Home'); expect($browserUrl).toHaveBeenCalledTimes(1); }); @@ -732,10 +754,10 @@ describe('$location', function() { $rootScope.$digest(); - expect($browser.url()).toEqual('http://server/app/#/'); + expect($browser.url()).toEqual('http://server/app/#!/'); expect($location.path()).toEqual('/'); expect($browserUrl).toHaveBeenCalledTimes(1); - expect($browserUrl.calls.argsFor(0)).toEqual(['http://server/app/#/', false, null]); + expect($browserUrl.calls.argsFor(0)).toEqual(['http://server/app/#!/', false, null]); }); }); @@ -748,10 +770,10 @@ describe('$location', function() { updatePathOnLocationChangeSuccessTo('/Home'); $rootScope.$digest(); - expect($browser.url()).toEqual('http://server/app/#/Home'); + expect($browser.url()).toEqual('http://server/app/#!/Home'); expect($location.path()).toEqual('/Home'); expect($browserUrl).toHaveBeenCalledTimes(1); - expect($browserUrl.calls.argsFor(0)).toEqual(['http://server/app/#/Home', false, null]); + expect($browserUrl.calls.argsFor(0)).toEqual(['http://server/app/#!/Home', false, null]); }); }); @@ -764,7 +786,7 @@ describe('$location', function() { updatePathOnLocationChangeSuccessTo('/'); $rootScope.$digest(); - expect($browser.url()).toEqual('http://server/app/#/'); + expect($browser.url()).toEqual('http://server/app/#!/'); expect($location.path()).toEqual('/'); expect($browserUrl).toHaveBeenCalledTimes(1); }); @@ -1822,17 +1844,17 @@ describe('$location', function() { // we need to do this otherwise we can't simulate events $document.find('body').append($rootElement); - var element = $compile('v1v2')($rootScope); + var element = $compile('v1v2')($rootScope); $rootElement.append(element); var av1 = $rootElement.find('a').eq(0); var av2 = $rootElement.find('a').eq(1); browserTrigger(av1, 'click'); - expect($browser.url()).toEqual(base + '#/view1'); + expect($browser.url()).toEqual(base + '#!/view1'); browserTrigger(av2, 'click'); - expect($browser.url()).toEqual(base + '#/view2'); + expect($browser.url()).toEqual(base + '#!/view2'); $rootElement.remove(); }); @@ -1844,27 +1866,27 @@ describe('$location', function() { var base; module(function($locationProvider) { return function($browser) { - window.location.hash = '!someHash'; + window.location.hash = '!!someHash'; $browser.url(base = window.location.href); base = base.split('#')[0]; - $locationProvider.hashPrefix('!'); + $locationProvider.hashPrefix('!!'); }; }); inject(function($rootScope, $compile, $browser, $rootElement, $document, $location) { // we need to do this otherwise we can't simulate events $document.find('body').append($rootElement); - var element = $compile('v1v2')($rootScope); + var element = $compile('v1v2')($rootScope); $rootElement.append(element); var av1 = $rootElement.find('a').eq(0); var av2 = $rootElement.find('a').eq(1); browserTrigger(av1, 'click'); - expect($browser.url()).toEqual(base + '#!/view1'); + expect($browser.url()).toEqual(base + '#!!/view1'); browserTrigger(av2, 'click'); - expect($browser.url()).toEqual(base + '#!/view2'); + expect($browser.url()).toEqual(base + '#!!/view2'); }); }); @@ -1992,11 +2014,11 @@ describe('$location', function() { $rootScope.$apply(); expect($log.info.logs.shift()). - toEqual(['before', 'http://server/#/somePath', 'http://server/', 'http://server/']); + toEqual(['before', 'http://server/#!/somePath', 'http://server/', 'http://server/']); expect($log.info.logs.shift()). - toEqual(['after', 'http://server/#/somePath', 'http://server/', 'http://server/#/somePath']); + toEqual(['after', 'http://server/#!/somePath', 'http://server/', 'http://server/#!/somePath']); expect($location.url()).toEqual('/somePath'); - expect($browser.url()).toEqual('http://server/#/somePath'); + expect($browser.url()).toEqual('http://server/#!/somePath'); })); @@ -2021,7 +2043,7 @@ describe('$location', function() { $rootScope.$apply(); expect($log.info.logs.shift()). - toEqual(['before', 'http://server/#/somePath', 'http://server/', 'http://server/']); + toEqual(['before', 'http://server/#!/somePath', 'http://server/', 'http://server/']); expect($log.info.logs[1]).toBeUndefined(); expect($location.url()).toEqual(''); expect($browser.url()).toEqual('http://server/'); @@ -2031,7 +2053,7 @@ describe('$location', function() { inject(function($location, $browser, $rootScope, $log) { $rootScope.$on('$locationChangeStart', function(event, newUrl, oldUrl) { $log.info('before', newUrl, oldUrl, $browser.url()); - if (newUrl === 'http://server/#/somePath') { + if (newUrl === 'http://server/#!/somePath') { $location.url('/redirectPath'); } }); @@ -2043,15 +2065,15 @@ describe('$location', function() { $rootScope.$apply(); expect($log.info.logs.shift()). - toEqual(['before', 'http://server/#/somePath', 'http://server/', 'http://server/']); + toEqual(['before', 'http://server/#!/somePath', 'http://server/', 'http://server/']); expect($log.info.logs.shift()). - toEqual(['before', 'http://server/#/redirectPath', 'http://server/', 'http://server/']); + toEqual(['before', 'http://server/#!/redirectPath', 'http://server/', 'http://server/']); expect($log.info.logs.shift()). - toEqual(['after', 'http://server/#/redirectPath', 'http://server/', - 'http://server/#/redirectPath']); + toEqual(['after', 'http://server/#!/redirectPath', 'http://server/', + 'http://server/#!/redirectPath']); expect($location.url()).toEqual('/redirectPath'); - expect($browser.url()).toEqual('http://server/#/redirectPath'); + expect($browser.url()).toEqual('http://server/#!/redirectPath'); }) ); @@ -2059,7 +2081,7 @@ describe('$location', function() { inject(function($location, $browser, $rootScope, $log) { $rootScope.$on('$locationChangeStart', function(event, newUrl, oldUrl) { $log.info('before', newUrl, oldUrl, $browser.url()); - if (newUrl === 'http://server/#/somePath') { + if (newUrl === 'http://server/#!/somePath') { event.preventDefault(); $location.url('/redirectPath'); } @@ -2072,15 +2094,15 @@ describe('$location', function() { $rootScope.$apply(); expect($log.info.logs.shift()). - toEqual(['before', 'http://server/#/somePath', 'http://server/', 'http://server/']); + toEqual(['before', 'http://server/#!/somePath', 'http://server/', 'http://server/']); expect($log.info.logs.shift()). - toEqual(['before', 'http://server/#/redirectPath', 'http://server/', 'http://server/']); + toEqual(['before', 'http://server/#!/redirectPath', 'http://server/', 'http://server/']); expect($log.info.logs.shift()). - toEqual(['after', 'http://server/#/redirectPath', 'http://server/', - 'http://server/#/redirectPath']); + toEqual(['after', 'http://server/#!/redirectPath', 'http://server/', + 'http://server/#!/redirectPath']); expect($location.url()).toEqual('/redirectPath'); - expect($browser.url()).toEqual('http://server/#/redirectPath'); + expect($browser.url()).toEqual('http://server/#!/redirectPath'); }) ); @@ -2088,9 +2110,9 @@ describe('$location', function() { inject(function($location, $browser, $rootScope, $log) { $rootScope.$on('$locationChangeStart', function(event, newUrl, oldUrl) { $log.info('before', newUrl, oldUrl, $browser.url()); - if (newUrl === 'http://server/#/somePath') { + if (newUrl === 'http://server/#!/somePath') { $location.url('/redirectPath'); - } else if (newUrl === 'http://server/#/redirectPath') { + } else if (newUrl === 'http://server/#!/redirectPath') { $location.url('/redirectPath2'); } }); @@ -2102,17 +2124,17 @@ describe('$location', function() { $rootScope.$apply(); expect($log.info.logs.shift()). - toEqual(['before', 'http://server/#/somePath', 'http://server/', 'http://server/']); + toEqual(['before', 'http://server/#!/somePath', 'http://server/', 'http://server/']); expect($log.info.logs.shift()). - toEqual(['before', 'http://server/#/redirectPath', 'http://server/', 'http://server/']); + toEqual(['before', 'http://server/#!/redirectPath', 'http://server/', 'http://server/']); expect($log.info.logs.shift()). - toEqual(['before', 'http://server/#/redirectPath2', 'http://server/', 'http://server/']); + toEqual(['before', 'http://server/#!/redirectPath2', 'http://server/', 'http://server/']); expect($log.info.logs.shift()). - toEqual(['after', 'http://server/#/redirectPath2', 'http://server/', - 'http://server/#/redirectPath2']); + toEqual(['after', 'http://server/#!/redirectPath2', 'http://server/', + 'http://server/#!/redirectPath2']); expect($location.url()).toEqual('/redirectPath2'); - expect($browser.url()).toEqual('http://server/#/redirectPath2'); + expect($browser.url()).toEqual('http://server/#!/redirectPath2'); }) ); @@ -2131,13 +2153,13 @@ describe('$location', function() { }); - $browser.url('http://server/#/somePath'); + $browser.url('http://server/#!/somePath'); $browser.poll(); expect($log.info.logs.shift()). - toEqual(['start', 'http://server/#/somePath', 'http://server/']); + toEqual(['start', 'http://server/#!/somePath', 'http://server/']); expect($log.info.logs.shift()). - toEqual(['after', 'http://server/#/somePath', 'http://server/']); + toEqual(['after', 'http://server/#!/somePath', 'http://server/']); }) ); @@ -2146,7 +2168,7 @@ describe('$location', function() { $location.url('/somepath'); $rootScope.$apply(); - expect($browser.url()).toEqual('http://server/#/somepath'); + expect($browser.url()).toEqual('http://server/#!/somepath'); expect($location.url()).toEqual('/somepath'); $rootScope.$on('$locationChangeStart', function(event, newUrl, oldUrl) { @@ -2160,9 +2182,9 @@ describe('$location', function() { $browser.poll(); expect($log.info.logs.shift()). - toEqual(['start', 'http://server/', 'http://server/#/somepath']); + toEqual(['start', 'http://server/', 'http://server/#!/somepath']); expect($log.info.logs.shift()). - toEqual(['after', 'http://server/', 'http://server/#/somepath']); + toEqual(['after', 'http://server/', 'http://server/#!/somepath']); }) ); @@ -2170,7 +2192,7 @@ describe('$location', function() { inject(function($location, $browser, $rootScope, $log) { $rootScope.$on('$locationChangeStart', function(event, newUrl, oldUrl) { $log.info('before', newUrl, oldUrl, $browser.url()); - if (newUrl === 'http://server/#/somePath') { + if (newUrl === 'http://server/#!/somePath') { $location.url('/redirectPath'); } }); @@ -2178,21 +2200,21 @@ describe('$location', function() { $log.info('after', newUrl, oldUrl, $browser.url()); }); - $browser.url('http://server/#/somePath'); + $browser.url('http://server/#!/somePath'); $browser.poll(); expect($log.info.logs.shift()). - toEqual(['before', 'http://server/#/somePath', 'http://server/', - 'http://server/#/somePath']); + toEqual(['before', 'http://server/#!/somePath', 'http://server/', + 'http://server/#!/somePath']); expect($log.info.logs.shift()). - toEqual(['before', 'http://server/#/redirectPath', 'http://server/#/somePath', - 'http://server/#/somePath']); + toEqual(['before', 'http://server/#!/redirectPath', 'http://server/#!/somePath', + 'http://server/#!/somePath']); expect($log.info.logs.shift()). - toEqual(['after', 'http://server/#/redirectPath', 'http://server/#/somePath', - 'http://server/#/redirectPath']); + toEqual(['after', 'http://server/#!/redirectPath', 'http://server/#!/somePath', + 'http://server/#!/redirectPath']); expect($location.url()).toEqual('/redirectPath'); - expect($browser.url()).toEqual('http://server/#/redirectPath'); + expect($browser.url()).toEqual('http://server/#!/redirectPath'); }) ); @@ -2200,7 +2222,7 @@ describe('$location', function() { inject(function($location, $browser, $rootScope, $log) { $rootScope.$on('$locationChangeStart', function(event, newUrl, oldUrl) { $log.info('before', newUrl, oldUrl, $browser.url()); - if (newUrl === 'http://server/#/somePath') { + if (newUrl === 'http://server/#!/somePath') { event.preventDefault(); $location.url('/redirectPath'); } @@ -2209,28 +2231,28 @@ describe('$location', function() { $log.info('after', newUrl, oldUrl, $browser.url()); }); - $browser.url('http://server/#/somePath'); + $browser.url('http://server/#!/somePath'); $browser.poll(); expect($log.info.logs.shift()). - toEqual(['before', 'http://server/#/somePath', 'http://server/', - 'http://server/#/somePath']); + toEqual(['before', 'http://server/#!/somePath', 'http://server/', + 'http://server/#!/somePath']); expect($log.info.logs.shift()). - toEqual(['before', 'http://server/#/redirectPath', 'http://server/#/somePath', - 'http://server/#/somePath']); + toEqual(['before', 'http://server/#!/redirectPath', 'http://server/#!/somePath', + 'http://server/#!/somePath']); expect($log.info.logs.shift()). - toEqual(['after', 'http://server/#/redirectPath', 'http://server/#/somePath', - 'http://server/#/redirectPath']); + toEqual(['after', 'http://server/#!/redirectPath', 'http://server/#!/somePath', + 'http://server/#!/redirectPath']); expect($location.url()).toEqual('/redirectPath'); - expect($browser.url()).toEqual('http://server/#/redirectPath'); + expect($browser.url()).toEqual('http://server/#!/redirectPath'); }) ); it('should listen on click events on href and prevent browser default in hashbang mode', function() { module(function() { return function($rootElement, $compile, $rootScope) { - $rootElement.html('link'); + $rootElement.html('link'); $compile($rootElement)($rootScope); jqLite(document.body).append($rootElement); }; @@ -2310,7 +2332,7 @@ describe('$location', function() { }); // change through $browser - $browser.url(base + '#/myNewPath'); + $browser.url(base + '#!/myNewPath'); $browser.poll(); expect(log).toEqual(['/myNewPath', '/', '/myNewPath']); diff --git a/test/ngRoute/routeSpec.js b/test/ngRoute/routeSpec.js index 9efc0b070d04..dc247a4788ea 100644 --- a/test/ngRoute/routeSpec.js +++ b/test/ngRoute/routeSpec.js @@ -1073,7 +1073,7 @@ describe('$route', function() { expect($location.path()).toEqual('/bar/id3'); expect($browserUrl.calls.mostRecent().args) - .toEqual(['http://server/#/bar/id3?extra=eId', true, null]); + .toEqual(['http://server/#!/bar/id3?extra=eId', true, null]); }); }); });