fix(angular1_router): support link generation with custom hashPrefixes

This commit is contained in:
Peter Bacon Darwin 2016-03-21 11:49:37 +00:00 committed by Pete Bacon Darwin
parent 69c1405196
commit 0f8efce799
3 changed files with 151 additions and 131 deletions

View File

@ -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;
};

View File

@ -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`.

View File

@ -2,8 +2,23 @@
describe('ngLink', function () {
describe('html5Mode enabled', function () {
runHrefTestsAndExpectPrefix(true);
});
describe('html5Mode disabled', function () {
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();
setup({html5Mode: html5Mode, hashPrefix: hashPrefix});
configureRouter([
{ path: '/a', component: 'oneCmp' },
{ path: '/b', component: 'twoCmp', name: 'Two' }
@ -11,11 +26,11 @@ describe('ngLink', function () {
var elt = compile('<a ng-link="[\'/Two\']">link</a> | outer { <div ng-outlet></div> }');
navigateTo('/a');
expect(elt.find('a').attr('href')).toBe('./b');
expect(elt.find('a').attr('href')).toBe(prefix + '/b');
});
it('should allow linking from the child and the parent', function () {
setup();
setup({html5Mode: html5Mode, hashPrefix: hashPrefix});
configureRouter([
{ path: '/a', component: 'oneCmp' },
{ path: '/b', component: 'twoCmp', name: 'Two' }
@ -23,12 +38,12 @@ describe('ngLink', function () {
var elt = compile('outer { <div ng-outlet></div> }');
navigateTo('/b');
expect(elt.find('a').attr('href')).toBe('./b');
expect(elt.find('a').attr('href')).toBe(prefix + '/b');
});
it('should allow params in routerLink directive', function () {
setup();
setup({html5Mode: html5Mode, hashPrefix: hashPrefix});
registerComponent('twoLinkCmp', '<div><a ng-link="[\'/Two\', {param: \'lol\'}]">{{twoLinkCmp.number}}</a></div>', function () {this.number = 'two'});
configureRouter([
{ path: '/a', component: 'twoLinkCmp' },
@ -37,12 +52,12 @@ describe('ngLink', function () {
var elt = compile('<div ng-outlet></div>');
navigateTo('/a');
expect(elt.find('a').attr('href')).toBe('./b/lol');
expect(elt.find('a').attr('href')).toBe(prefix + '/b/lol');
});
it('should update the href of links with bound params', function () {
setup();
setup({html5Mode: html5Mode, hashPrefix: hashPrefix});
registerComponent('twoLinkCmp', '<div><a ng-link="[\'/Two\', {param: $ctrl.number}]">{{$ctrl.number}}</a></div>', function () {this.number = 43});
configureRouter([
{ path: '/a', component: 'twoLinkCmp' },
@ -52,12 +67,12 @@ describe('ngLink', function () {
var elt = compile('<div ng-outlet></div>');
navigateTo('/a');
expect(elt.find('a').text()).toBe('43');
expect(elt.find('a').attr('href')).toBe('./b/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();
setup({html5Mode: html5Mode, hashPrefix: hashPrefix});
configureRouter([
{ path: '/', component: 'oneCmp' },
{ path: '/two', component: 'twoCmp', name: 'Two'}
@ -65,7 +80,7 @@ describe('ngLink', function () {
var elt = compile('<a ng-link="[\'/Two\']">link</a> | <div ng-outlet></div>');
expect(elt.text()).toBe('link | one');
expect(elt.find('a').attr('href')).toBe('./two');
expect(elt.find('a').attr('href')).toBe(prefix + '/two');
elt.find('a')[0].click();
inject(function($rootScope) { $rootScope.$digest(); });
@ -74,7 +89,7 @@ describe('ngLink', function () {
it('should not navigate on non-left mouse click when a link url matches a route', function() {
setup();
setup({html5Mode: html5Mode, hashPrefix: hashPrefix});
configureRouter([
{ path: '/', component: 'oneCmp' },
{ path: '/two', component: 'twoCmp', name: 'Two'}
@ -90,7 +105,7 @@ describe('ngLink', function () {
// See https://github.com/angular/router/issues/206
it('should not navigate a link without an href', function () {
setup();
setup({html5Mode: html5Mode, hashPrefix: hashPrefix});
configureRouter([
{ path: '/', component: 'oneCmp' },
{ path: '/two', component: 'twoCmp', name: 'Two'}
@ -104,7 +119,7 @@ describe('ngLink', function () {
});
it('should add an ng-link-active class on the current link', function() {
setup();
setup({html5Mode: html5Mode, hashPrefix: hashPrefix});
configureRouter([
{ path: '/', component: 'oneCmp', name: 'One' }
]);
@ -113,22 +128,7 @@ describe('ngLink', function () {
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('<a ng-link="[\'/Two\']">link</a>');
expect(elt.find('a').attr('href')).toBe('#/b');
});
});
}
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', '<div>hello {{$ctrl.$routeParams.name}}</div>', function () {});
registerComponent('oneCmp', '<div>{{$ctrl.number}}</div>', function () {this.number = 'one'});