diff --git a/src/ng/location.js b/src/ng/location.js index 8ec16ddff1ac..4ae5de578eb3 100644 --- a/src/ng/location.js +++ b/src/ng/location.js @@ -31,10 +31,11 @@ function parseAbsoluteUrl(absoluteUrl, locationObj) { } -function parseAppUrl(relativeUrl, locationObj) { +function parseAppUrl(relativeUrl, locationObj, fixHashFragmentLinks) { var prefixed = (relativeUrl.charAt(0) !== '/'); + var hashPrefix = (fixHashFragmentLinks && relativeUrl.charAt(0) !== '#') ? '#' : ''; if (prefixed) { - relativeUrl = '/' + relativeUrl; + relativeUrl = '/' + hashPrefix + relativeUrl; } var match = urlResolve(relativeUrl); locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ? @@ -166,7 +167,7 @@ function LocationHtml5Url(appBase, basePrefix) { * @param {string} appBase application base URL * @param {string} hashPrefix hashbang prefix */ -function LocationHashbangUrl(appBase, hashPrefix) { +function LocationHashbangUrl(appBase, hashPrefix, fixHashFragmentLinks) { var appBaseNoFile = stripFile(appBase); parseAbsoluteUrl(appBase, this); @@ -189,7 +190,7 @@ function LocationHashbangUrl(appBase, hashPrefix) { throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url, hashPrefix); } - parseAppUrl(withoutHashUrl, this); + parseAppUrl(withoutHashUrl, this, fixHashFragmentLinks); this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase); @@ -675,7 +676,8 @@ function $LocationProvider() { enabled: false, requireBase: true, rewriteLinks: true - }; + }, + fixHashFragmentLinks = false; /** * @ngdoc method @@ -736,6 +738,22 @@ function $LocationProvider() { } }; + /** + * @ngdoc method + * @name $locationProvider#fixHashFragmentLinks + * @description + * @param {boolean=} [enable=false] If set to true, will replace hashes in the URL with double hashes + * @returns {*} current value if used as getter or itself (chaining) if used as setter + */ + this.fixHashFragmentLinks = function(value) { + if (isDefined(value)) { + fixHashFragmentLinks = !!value; + return this; + } else { + return fixHashFragmentLinks; + } + }; + /** * @ngdoc event * @name $location#$locationChangeStart @@ -794,7 +812,7 @@ function $LocationProvider() { appBase = stripHash(initialUrl); LocationMode = LocationHashbangUrl; } - $location = new LocationMode(appBase, '#' + hashPrefix); + $location = new LocationMode(appBase, '#' + hashPrefix, fixHashFragmentLinks); $location.$$parseLinkUrl(initialUrl, initialUrl); $location.$$state = $browser.state(); diff --git a/test/e2e/fixtures/ng/location/hashFragmentScrolling/README.md b/test/e2e/fixtures/ng/location/hashFragmentScrolling/README.md new file mode 100644 index 000000000000..093db73d8559 --- /dev/null +++ b/test/e2e/fixtures/ng/location/hashFragmentScrolling/README.md @@ -0,0 +1,12 @@ +Regression test for [#8675](https://github.com/angular/angular.js/issues/8675). + +Makes sure that hash fragment links actually jump to the relevant document fragment when `$location` +is injected and configured to operate in hashbang mode. In order to use this fix, you need to inject +the `$anchorScroll` service somewhere in your application, and also add the following config block +to your application: + +```js +function($locationProvider) { + $locationProvider.fixHashFragmentLinks(true); +} +``` diff --git a/test/e2e/fixtures/ng/location/hashFragmentScrolling/index.html b/test/e2e/fixtures/ng/location/hashFragmentScrolling/index.html new file mode 100644 index 000000000000..742279cf27d6 --- /dev/null +++ b/test/e2e/fixtures/ng/location/hashFragmentScrolling/index.html @@ -0,0 +1,13 @@ + + +