fix(angular1_router): support link generation with custom hashPrefixes
This commit is contained in:
parent
69c1405196
commit
0f8efce799
|
@ -320,9 +320,5 @@ Location.prototype.prepareExternalUrl = function(url) {
|
||||||
if (url.length > 0 && !url.startsWith('/')) {
|
if (url.length > 0 && !url.startsWith('/')) {
|
||||||
url = '/' + url;
|
url = '/' + url;
|
||||||
}
|
}
|
||||||
if(!$location.$$html5) {
|
return $location.$$html5 ? '.' + url : '#' + $locationHashPrefix + url;
|
||||||
return '#' + url;
|
|
||||||
} else {
|
|
||||||
return '.' + url;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,9 +4,33 @@ angular.module('ngComponentRouter').
|
||||||
// Because Angular 1 has no notion of a root component, we use an object with unique identity
|
// 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
|
// to represent this. Can be overloaded with a component name
|
||||||
value('$routerRootComponent', new Object()).
|
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
|
// When this file is processed, the line below is replaced with
|
||||||
// the contents of `../lib/facades.es5`.
|
// the contents of `../lib/facades.es5`.
|
||||||
|
|
|
@ -2,133 +2,133 @@
|
||||||
|
|
||||||
describe('ngLink', function () {
|
describe('ngLink', function () {
|
||||||
|
|
||||||
it('should allow linking from the parent to the child', function () {
|
describe('html5Mode enabled', function () {
|
||||||
setup();
|
runHrefTestsAndExpectPrefix(true);
|
||||||
configureRouter([
|
|
||||||
{ path: '/a', component: 'oneCmp' },
|
|
||||||
{ path: '/b', component: 'twoCmp', name: 'Two' }
|
|
||||||
]);
|
|
||||||
|
|
||||||
var elt = compile('<a ng-link="[\'/Two\']">link</a> | outer { <div ng-outlet></div> }');
|
|
||||||
navigateTo('/a');
|
|
||||||
expect(elt.find('a').attr('href')).toBe('./b');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
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 { <div ng-outlet></div> }');
|
|
||||||
navigateTo('/b');
|
|
||||||
expect(elt.find('a').attr('href')).toBe('./b');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should allow params in routerLink directive', function () {
|
|
||||||
setup();
|
|
||||||
registerComponent('twoLinkCmp', '<div><a ng-link="[\'/Two\', {param: \'lol\'}]">{{twoLinkCmp.number}}</a></div>', function () {this.number = 'two'});
|
|
||||||
configureRouter([
|
|
||||||
{ path: '/a', component: 'twoLinkCmp' },
|
|
||||||
{ path: '/b/:param', component: 'twoCmp', name: 'Two' }
|
|
||||||
]);
|
|
||||||
|
|
||||||
var elt = compile('<div ng-outlet></div>');
|
|
||||||
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', '<div><a ng-link="[\'/Two\', {param: $ctrl.number}]">{{$ctrl.number}}</a></div>', function () {this.number = 43});
|
|
||||||
configureRouter([
|
|
||||||
{ path: '/a', component: 'twoLinkCmp' },
|
|
||||||
{ path: '/b/:param', component: 'twoCmp', name: 'Two' }
|
|
||||||
]);
|
|
||||||
|
|
||||||
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');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
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('<a ng-link="[\'/Two\']">link</a> | <div ng-outlet></div>');
|
|
||||||
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('<a ng-link="[\'/Two\']">link</a> | <div ng-outlet></div>');
|
|
||||||
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('<a>link</a>');
|
|
||||||
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('<a ng-link="[\'/One\']">one</a> | <div ng-outlet></div>');
|
|
||||||
navigateTo('/');
|
|
||||||
expect(elt.find('a').attr('class')).toBe('ng-link-active');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('html5Mode disabled', function () {
|
describe('html5Mode disabled', function () {
|
||||||
it('should prepend href with a hash', function () {
|
runHrefTestsAndExpectPrefix(false, '');
|
||||||
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');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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('<a ng-link="[\'/Two\']">link</a> | outer { <div ng-outlet></div> }');
|
||||||
|
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 { <div ng-outlet></div> }');
|
||||||
|
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', '<div><a ng-link="[\'/Two\', {param: \'lol\'}]">{{twoLinkCmp.number}}</a></div>', function () {this.number = 'two'});
|
||||||
|
configureRouter([
|
||||||
|
{ path: '/a', component: 'twoLinkCmp' },
|
||||||
|
{ path: '/b/:param', component: 'twoCmp', name: 'Two' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
var elt = compile('<div ng-outlet></div>');
|
||||||
|
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', '<div><a ng-link="[\'/Two\', {param: $ctrl.number}]">{{$ctrl.number}}</a></div>', function () {this.number = 43});
|
||||||
|
configureRouter([
|
||||||
|
{ path: '/a', component: 'twoLinkCmp' },
|
||||||
|
{ path: '/b/:param', component: 'twoCmp', name: 'Two' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
var elt = compile('<div ng-outlet></div>');
|
||||||
|
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('<a ng-link="[\'/Two\']">link</a> | <div ng-outlet></div>');
|
||||||
|
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('<a ng-link="[\'/Two\']">link</a> | <div ng-outlet></div>');
|
||||||
|
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('<a>link</a>');
|
||||||
|
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('<a ng-link="[\'/One\']">one</a> | <div ng-outlet></div>');
|
||||||
|
navigateTo('/');
|
||||||
|
expect(elt.find('a').attr('class')).toBe('ng-link-active');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function registerComponent(name, template, controller) {
|
function registerComponent(name, template, controller) {
|
||||||
module(function($compileProvider) {
|
module(function($compileProvider) {
|
||||||
|
@ -140,10 +140,10 @@ describe('ngLink', function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setup(config) {
|
function setup(config) {
|
||||||
var html5Mode = !(config && config.html5Mode === false);
|
|
||||||
module('ngComponentRouter')
|
module('ngComponentRouter')
|
||||||
module(function($locationProvider) {
|
module(function($locationProvider) {
|
||||||
$locationProvider.html5Mode(html5Mode);
|
$locationProvider.html5Mode(config.html5Mode);
|
||||||
|
$locationProvider.hashPrefix(config.hashPrefix);
|
||||||
});
|
});
|
||||||
registerComponent('userCmp', '<div>hello {{$ctrl.$routeParams.name}}</div>', function () {});
|
registerComponent('userCmp', '<div>hello {{$ctrl.$routeParams.name}}</div>', function () {});
|
||||||
registerComponent('oneCmp', '<div>{{$ctrl.number}}</div>', function () {this.number = 'one'});
|
registerComponent('oneCmp', '<div>{{$ctrl.number}}</div>', function () {this.number = 'one'});
|
||||||
|
|
Loading…
Reference in New Issue