Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit c639261

Browse files
mprobstIgorMinar
authored andcommitted
fix($route): support route params not separated with slashes.
Commit 773ac4a broke support for route parameters that are not seperated from other route parts by slashes, which this change fixes. It also adds some documentation about path parameters to the when() method and escapes all regular expression special characters in the URL, not just some.
1 parent 74dd2f7 commit c639261

File tree

3 files changed

+67
-24
lines changed

3 files changed

+67
-24
lines changed

src/ng/route.js

+33-14
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,13 @@ function $RouteProvider(){
2020
*
2121
* @param {string} path Route path (matched against `$location.path`). If `$location.path`
2222
* contains redundant trailing slash or is missing one, the route will still match and the
23-
* `$location.path` will be updated to add or drop the trailing slash to exacly match the
23+
* `$location.path` will be updated to add or drop the trailing slash to exactly match the
2424
* route definition.
25+
*
26+
* `path` can contain named groups starting with a colon (`:name`). All characters up to the
27+
* next slash are matched and stored in `$routeParams` under the given `name` when the route
28+
* matches.
29+
*
2530
* @param {Object} route Mapping information to be assigned to `$route.current` on route
2631
* match.
2732
*
@@ -286,8 +291,7 @@ function $RouteProvider(){
286291
* instance of the Controller.
287292
*/
288293

289-
var matcher = switchRouteMatcher,
290-
forceReload = false,
294+
var forceReload = false,
291295
$route = {
292296
routes: routes,
293297

@@ -315,21 +319,36 @@ function $RouteProvider(){
315319

316320
/////////////////////////////////////////////////////
317321

322+
/**
323+
* @param on {string} current url
324+
* @param when {string} route when template to match the url against
325+
* @return {?Object}
326+
*/
318327
function switchRouteMatcher(on, when) {
319328
// TODO(i): this code is convoluted and inefficient, we should construct the route matching
320329
// regex only once and then reuse it
321-
var regex = '^' + when.replace(/([\.\\\(\)\^\$])/g, "\\$1") + '$',
330+
331+
// Escape regexp special characters.
332+
when = '^' + when.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&") + '$';
333+
var regex = '',
322334
params = [],
323335
dst = {};
324-
forEach(when.split(/[^\w:]/), function(param) {
325-
if (param && param.charAt(0) === ':') {
326-
var paramRegExp = new RegExp(param + "([\\W])");
327-
if (regex.match(paramRegExp)) {
328-
regex = regex.replace(paramRegExp, "([^\\/]*)$1");
329-
params.push(param.substr(1));
330-
}
331-
}
332-
});
336+
337+
var re = /:(\w+)/g,
338+
paramMatch,
339+
lastMatchedIndex = 0;
340+
341+
while ((paramMatch = re.exec(when)) !== null) {
342+
// Find each :param in `when` and replace it with a capturing group.
343+
// Append all other sections of when unchanged.
344+
regex += when.slice(lastMatchedIndex, paramMatch.index);
345+
regex += '([^\\/]*)';
346+
params.push(paramMatch[1]);
347+
lastMatchedIndex = re.lastIndex;
348+
}
349+
// Append trailing path part.
350+
regex += when.substr(lastMatchedIndex);
351+
333352
var match = on.match(new RegExp(regex));
334353
if (match) {
335354
forEach(params, function(name, index) {
@@ -418,7 +437,7 @@ function $RouteProvider(){
418437
// Match a route
419438
var params, match;
420439
forEach(routes, function(route, path) {
421-
if (!match && (params = matcher($location.path(), path))) {
440+
if (!match && (params = switchRouteMatcher($location.path(), path))) {
422441
match = inherit(route, {
423442
params: extend({}, $location.search(), params),
424443
pathParams: params});

test/ng/routeParamsSpec.js

+12
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,16 @@ describe('$routeParams', function() {
2929
expect($routeParams).toEqual({bar:'barvalue', foo:'foovalue'});
3030
});
3131
});
32+
33+
it('should support route params not preceded by slashes', function() {
34+
module(function($routeProvider) {
35+
$routeProvider.when('/bar:barId/foo:fooId/', {});
36+
});
37+
38+
inject(function($rootScope, $route, $location, $routeParams) {
39+
$location.path('/barbarvalue/foofoovalue/');
40+
$rootScope.$digest();
41+
expect($routeParams).toEqual({barId: 'barvalue', fooId: 'foovalue'});
42+
});
43+
});
3244
});

test/ng/routeSpec.js

+22-10
Original file line numberDiff line numberDiff line change
@@ -82,28 +82,40 @@ describe('$route', function() {
8282
});
8383

8484

85-
it('should match a route that contains special chars in the path', function() {
86-
module(function($routeProvider) {
87-
$routeProvider.when('/$test.23/foo(bar)/:baz', {templateUrl: 'test.html'});
88-
});
89-
inject(function($route, $location, $rootScope) {
85+
describe('should match a route that contains special chars in the path', function() {
86+
beforeEach(module(function($routeProvider) {
87+
$routeProvider.when('/$test.23/foo*(bar)/:baz', {templateUrl: 'test.html'});
88+
}));
9089

90+
it('matches the full path', inject(function($route, $location, $rootScope) {
9191
$location.path('/test');
9292
$rootScope.$digest();
9393
expect($route.current).toBeUndefined();
94+
}));
9495

95-
$location.path('/$testX23/foo(bar)/222');
96+
it('matches literal .', inject(function($route, $location, $rootScope) {
97+
$location.path('/$testX23/foo*(bar)/222');
9698
$rootScope.$digest();
9799
expect($route.current).toBeUndefined();
100+
}));
98101

99-
$location.path('/$test.23/foo(bar)/222');
102+
it('matches literal *', inject(function($route, $location, $rootScope) {
103+
$location.path('/$test.23/foooo(bar)/222');
100104
$rootScope.$digest();
101-
expect($route.current).toBeDefined();
105+
expect($route.current).toBeUndefined();
106+
}));
102107

103-
$location.path('/$test.23/foo\\(bar)/222');
108+
it('treats backslashes normally', inject(function($route, $location, $rootScope) {
109+
$location.path('/$test.23/foo*\\(bar)/222');
104110
$rootScope.$digest();
105111
expect($route.current).toBeUndefined();
106-
});
112+
}));
113+
114+
it('matches a URL with special chars', inject(function($route, $location, $rootScope) {
115+
$location.path('/$test.23/foo*(bar)/222');
116+
$rootScope.$digest();
117+
expect($route.current).toBeDefined();
118+
}));
107119
});
108120

109121

0 commit comments

Comments
 (0)