diff --git a/modules/angular1_router/lib/facades.es5 b/modules/angular1_router/lib/facades.es5 index aa2153e313..1744f10d53 100644 --- a/modules/angular1_router/lib/facades.es5 +++ b/modules/angular1_router/lib/facades.es5 @@ -320,9 +320,5 @@ Location.prototype.prepareExternalUrl = function(url) { if (url.length > 0 && !url.startsWith('/')) { url = '/' + url; } - if(!$location.$$html5) { - return '#' + url; - } else { - return '.' + url; - } + return $location.$$html5 ? '.' + url : '#' + $locationHashPrefix + url; }; diff --git a/modules/angular1_router/src/module_template.js b/modules/angular1_router/src/module_template.js index ca4352dff2..e257e3e855 100644 --- a/modules/angular1_router/src/module_template.js +++ b/modules/angular1_router/src/module_template.js @@ -4,9 +4,33 @@ angular.module('ngComponentRouter'). // Because Angular 1 has no notion of a root component, we use an object with unique identity // to represent this. Can be overloaded with a component name value('$routerRootComponent', new Object()). - factory('$rootRouter', ['$q', '$location', '$browser', '$rootScope', '$injector', '$routerRootComponent', routerFactory]); -function routerFactory($q, $location, $browser, $rootScope, $injector, $routerRootComponent) { + // Unfortunately, $location doesn't expose what the current hashPrefix is + // So we have to monkey patch the $locationProvider to capture this value + provider('$locationHashPrefix', ['$locationProvider', $locationHashPrefixProvider]). + factory('$rootRouter', ['$q', '$location', '$browser', '$rootScope', '$injector', '$routerRootComponent', '$locationHashPrefix', routerFactory]); + +function $locationHashPrefixProvider($locationProvider) { + + // Get hold of the original hashPrefix method + var hashPrefixFn = $locationProvider.hashPrefix.bind($locationProvider); + + // Read the current hashPrefix (in case it was set before this monkey-patch occurred) + var hashPrefix = hashPrefixFn(); + + // Override the helper so that we can read any changes to the prefix (after this monkey-patch) + $locationProvider.hashPrefix = function(prefix) { + if (angular.isDefined(prefix)) { + hashPrefix = prefix; + } + return hashPrefixFn(prefix); + } + + // Return the final hashPrefix as the value of this service + this.$get = function() { return hashPrefix; }; +} + +function routerFactory($q, $location, $browser, $rootScope, $injector, $routerRootComponent, $locationHashPrefix) { // When this file is processed, the line below is replaced with // the contents of `../lib/facades.es5`. diff --git a/modules/angular1_router/test/ng_link_spec.js b/modules/angular1_router/test/ng_link_spec.js index 4556230c2b..1a16fd8c92 100644 --- a/modules/angular1_router/test/ng_link_spec.js +++ b/modules/angular1_router/test/ng_link_spec.js @@ -2,133 +2,133 @@ describe('ngLink', function () { - it('should allow linking from the parent to the child', function () { - setup(); - configureRouter([ - { path: '/a', component: 'oneCmp' }, - { path: '/b', component: 'twoCmp', name: 'Two' } - ]); - - var elt = compile('link | outer {
}'); - navigateTo('/a'); - expect(elt.find('a').attr('href')).toBe('./b'); + describe('html5Mode enabled', function () { + runHrefTestsAndExpectPrefix(true); }); - it('should allow linking from the child and the parent', function () { - setup(); - configureRouter([ - { path: '/a', component: 'oneCmp' }, - { path: '/b', component: 'twoCmp', name: 'Two' } - ]); - - var elt = compile('outer { }'); - navigateTo('/b'); - expect(elt.find('a').attr('href')).toBe('./b'); - }); - - - it('should allow params in routerLink directive', function () { - setup(); - registerComponent('twoLinkCmp', '', function () {this.number = 'two'}); - configureRouter([ - { path: '/a', component: 'twoLinkCmp' }, - { path: '/b/:param', component: 'twoCmp', name: 'Two' } - ]); - - var elt = compile(''); - navigateTo('/a'); - expect(elt.find('a').attr('href')).toBe('./b/lol'); - }); - - - it('should update the href of links with bound params', function () { - setup(); - registerComponent('twoLinkCmp', '', function () {this.number = 43}); - configureRouter([ - { path: '/a', component: 'twoLinkCmp' }, - { path: '/b/:param', component: 'twoCmp', name: 'Two' } - ]); - - var elt = compile(''); - navigateTo('/a'); - expect(elt.find('a').text()).toBe('43'); - expect(elt.find('a').attr('href')).toBe('./b/43'); - }); - - - it('should navigate on left-mouse click when a link url matches a route', function () { - setup(); - configureRouter([ - { path: '/', component: 'oneCmp' }, - { path: '/two', component: 'twoCmp', name: 'Two'} - ]); - - var elt = compile('link | '); - expect(elt.text()).toBe('link | one'); - expect(elt.find('a').attr('href')).toBe('./two'); - - elt.find('a')[0].click(); - inject(function($rootScope) { $rootScope.$digest(); }); - expect(elt.text()).toBe('link | two'); - }); - - - it('should not navigate on non-left mouse click when a link url matches a route', function() { - setup(); - configureRouter([ - { path: '/', component: 'oneCmp' }, - { path: '/two', component: 'twoCmp', name: 'Two'} - ]); - - var elt = compile('link | '); - expect(elt.text()).toBe('link | one'); - elt.find('a').triggerHandler({ type: 'click', which: 3 }); - inject(function($rootScope) { $rootScope.$digest(); }); - expect(elt.text()).toBe('link | one'); - }); - - - // See https://github.com/angular/router/issues/206 - it('should not navigate a link without an href', function () { - setup(); - configureRouter([ - { path: '/', component: 'oneCmp' }, - { path: '/two', component: 'twoCmp', name: 'Two'} - ]); - expect(function () { - var elt = compile('link'); - expect(elt.text()).toBe('link'); - elt.find('a')[0].click(); - inject(function($rootScope) { $rootScope.$digest(); }); - }).not.toThrow(); - }); - - it('should add an ng-link-active class on the current link', function() { - setup(); - configureRouter([ - { path: '/', component: 'oneCmp', name: 'One' } - ]); - - var elt = compile('one | '); - navigateTo('/'); - expect(elt.find('a').attr('class')).toBe('ng-link-active'); - }); - - describe('html5Mode disabled', function () { - it('should prepend href with a hash', function () { - setup({ html5Mode: false }); - module(function($locationProvider) { - $locationProvider.html5Mode(false); - }); - configureRouter([ - { path: '/b', component: 'twoCmp', name: 'Two' } - ]); - var elt = compile('link'); - expect(elt.find('a').attr('href')).toBe('#/b'); - }); + runHrefTestsAndExpectPrefix(false, ''); }); + describe('html5Mode disabled, with hash prefix', function () { + runHrefTestsAndExpectPrefix(false, '!'); + }); + + function runHrefTestsAndExpectPrefix(html5Mode, hashPrefix) { + var prefix = html5Mode ? '.' : '#' + hashPrefix; + + it('should allow linking from the parent to the child', function () { + setup({html5Mode: html5Mode, hashPrefix: hashPrefix}); + configureRouter([ + { path: '/a', component: 'oneCmp' }, + { path: '/b', component: 'twoCmp', name: 'Two' } + ]); + + var elt = compile('link | outer { }'); + navigateTo('/a'); + expect(elt.find('a').attr('href')).toBe(prefix + '/b'); + }); + + it('should allow linking from the child and the parent', function () { + setup({html5Mode: html5Mode, hashPrefix: hashPrefix}); + configureRouter([ + { path: '/a', component: 'oneCmp' }, + { path: '/b', component: 'twoCmp', name: 'Two' } + ]); + + var elt = compile('outer { }'); + navigateTo('/b'); + expect(elt.find('a').attr('href')).toBe(prefix + '/b'); + }); + + + it('should allow params in routerLink directive', function () { + setup({html5Mode: html5Mode, hashPrefix: hashPrefix}); + registerComponent('twoLinkCmp', '', function () {this.number = 'two'}); + configureRouter([ + { path: '/a', component: 'twoLinkCmp' }, + { path: '/b/:param', component: 'twoCmp', name: 'Two' } + ]); + + var elt = compile(''); + navigateTo('/a'); + expect(elt.find('a').attr('href')).toBe(prefix + '/b/lol'); + }); + + + it('should update the href of links with bound params', function () { + setup({html5Mode: html5Mode, hashPrefix: hashPrefix}); + registerComponent('twoLinkCmp', '', function () {this.number = 43}); + configureRouter([ + { path: '/a', component: 'twoLinkCmp' }, + { path: '/b/:param', component: 'twoCmp', name: 'Two' } + ]); + + var elt = compile(''); + navigateTo('/a'); + expect(elt.find('a').text()).toBe('43'); + expect(elt.find('a').attr('href')).toBe(prefix + '/b/43'); + }); + + + it('should navigate on left-mouse click when a link url matches a route', function () { + setup({html5Mode: html5Mode, hashPrefix: hashPrefix}); + configureRouter([ + { path: '/', component: 'oneCmp' }, + { path: '/two', component: 'twoCmp', name: 'Two'} + ]); + + var elt = compile('link | '); + expect(elt.text()).toBe('link | one'); + expect(elt.find('a').attr('href')).toBe(prefix + '/two'); + + elt.find('a')[0].click(); + inject(function($rootScope) { $rootScope.$digest(); }); + expect(elt.text()).toBe('link | two'); + }); + + + it('should not navigate on non-left mouse click when a link url matches a route', function() { + setup({html5Mode: html5Mode, hashPrefix: hashPrefix}); + configureRouter([ + { path: '/', component: 'oneCmp' }, + { path: '/two', component: 'twoCmp', name: 'Two'} + ]); + + var elt = compile('link | '); + expect(elt.text()).toBe('link | one'); + elt.find('a').triggerHandler({ type: 'click', which: 3 }); + inject(function($rootScope) { $rootScope.$digest(); }); + expect(elt.text()).toBe('link | one'); + }); + + + // See https://github.com/angular/router/issues/206 + it('should not navigate a link without an href', function () { + setup({html5Mode: html5Mode, hashPrefix: hashPrefix}); + configureRouter([ + { path: '/', component: 'oneCmp' }, + { path: '/two', component: 'twoCmp', name: 'Two'} + ]); + expect(function () { + var elt = compile('link'); + expect(elt.text()).toBe('link'); + elt.find('a')[0].click(); + inject(function($rootScope) { $rootScope.$digest(); }); + }).not.toThrow(); + }); + + it('should add an ng-link-active class on the current link', function() { + setup({html5Mode: html5Mode, hashPrefix: hashPrefix}); + configureRouter([ + { path: '/', component: 'oneCmp', name: 'One' } + ]); + + var elt = compile('one | '); + navigateTo('/'); + expect(elt.find('a').attr('class')).toBe('ng-link-active'); + }); + } function registerComponent(name, template, controller) { module(function($compileProvider) { @@ -140,10 +140,10 @@ describe('ngLink', function () { } function setup(config) { - var html5Mode = !(config && config.html5Mode === false); module('ngComponentRouter') module(function($locationProvider) { - $locationProvider.html5Mode(html5Mode); + $locationProvider.html5Mode(config.html5Mode); + $locationProvider.hashPrefix(config.hashPrefix); }); registerComponent('userCmp', '