@@ -35,11 +35,13 @@ function $RouteProvider(){
35
35
*
36
36
* * `path` can contain named groups starting with a colon (`:name`). All characters up
37
37
* to the next slash are matched and stored in `$routeParams` under the given `name`
38
- * after the route is resolved.
39
- * * `path` can contain named groups starting with a star (`*name`). All characters are
40
- * eagerly stored in `$routeParams` under the given `name` after the route is resolved.
38
+ * when the route matches.
39
+ * * `path` can contain named groups starting with a colon and ending with a star (`:name*`).
40
+ * All characters are eagerly stored in `$routeParams` under the given `name`
41
+ * when the route matches.
42
+ * * `path` can contain optional named groups with a question mark (`:name?`).
41
43
*
42
- * For example, routes like `/color/:color/largecode/* largecode/edit` will match
44
+ * For example, routes like `/color/:color/largecode/: largecode*\ /edit` will match
43
45
* `/color/brown/largecode/code/with/slashs/edit` and extract:
44
46
*
45
47
* * `color: brown`
@@ -117,20 +119,66 @@ function $RouteProvider(){
117
119
* Adds a new route definition to the `$route` service.
118
120
*/
119
121
this . when = function ( path , route ) {
120
- routes [ path ] = extend ( { reloadOnSearch : true , caseInsensitiveMatch : false } , route ) ;
122
+ routes [ path ] = extend (
123
+ { reloadOnSearch : true } ,
124
+ route ,
125
+ path && pathRegExp ( path , route )
126
+ ) ;
121
127
122
128
// create redirection for trailing slashes
123
129
if ( path ) {
124
130
var redirectPath = ( path [ path . length - 1 ] == '/' )
125
131
? path . substr ( 0 , path . length - 1 )
126
132
: path + '/' ;
127
133
128
- routes [ redirectPath ] = { redirectTo : path } ;
134
+ routes [ redirectPath ] = extend (
135
+ { redirectTo : path } ,
136
+ pathRegExp ( redirectPath , route )
137
+ ) ;
129
138
}
130
139
131
140
return this ;
132
141
} ;
133
142
143
+ /**
144
+ * @param path {string} path
145
+ * @param opts {Object} options
146
+ * @return {?Object }
147
+ *
148
+ * @description
149
+ * Normalizes the given path, returning a regular expression
150
+ * and the original path.
151
+ *
152
+ * Inspired by pathRexp in visionmedia/express/lib/utils.js.
153
+ */
154
+ function pathRegExp ( path , opts ) {
155
+ var insensitive = opts . caseInsensitiveMatch ,
156
+ ret = {
157
+ originalPath : path ,
158
+ regexp : path
159
+ } ,
160
+ keys = ret . keys = [ ] ;
161
+
162
+ path = path
163
+ . replace ( / ( [ ( ) . ] ) / g, '\\$1' )
164
+ . replace ( / ( \/ ) ? : ( \w + ) ( [ \? | \* ] ) ? / g, function ( _ , slash , key , option ) {
165
+ var optional = option === '?' ? option : null ;
166
+ var star = option === '*' ? option : null ;
167
+ keys . push ( { name : key , optional : ! ! optional } ) ;
168
+ slash = slash || '' ;
169
+ return ''
170
+ + ( optional ? '' : slash )
171
+ + '(?:'
172
+ + ( optional ? slash : '' )
173
+ + ( star && '(.+)?' || '([^/]+)?' ) + ')'
174
+ + ( optional || '' ) ;
175
+ } )
176
+ . replace ( / ( [ \/ $ \* ] ) / g, '\\$1' ) ;
177
+
178
+ ret . regexp = new RegExp ( '^' + path + '$' , insensitive ? 'i' : '' ) ;
179
+ return ret ;
180
+ }
181
+
134
182
/**
135
183
* @ngdoc method
136
184
* @name ngRoute.$routeProvider#otherwise
@@ -362,50 +410,37 @@ function $RouteProvider(){
362
410
363
411
/**
364
412
* @param on {string} current url
365
- * @param when {string} route when template to match the url against
366
- * @param whenProperties {Object} properties to define when's matching behavior
413
+ * @param route {Object} route regexp to match the url against
367
414
* @return {?Object }
415
+ *
416
+ * @description
417
+ * Check if the route matches the current url.
418
+ *
419
+ * Inspired by match in
420
+ * visionmedia/express/lib/router/router.js.
368
421
*/
369
- function switchRouteMatcher ( on , when , whenProperties ) {
370
- // TODO(i): this code is convoluted and inefficient, we should construct the route matching
371
- // regex only once and then reuse it
372
-
373
- // Escape regexp special characters.
374
- when = '^' + when . replace ( / [ - \/ \\ ^ $ : * + ? . ( ) | [ \] { } ] / g, "\\$&" ) + '$' ;
375
-
376
- var regex = '' ,
377
- params = [ ] ,
378
- dst = { } ;
379
-
380
- var re = / \\ ( [: * ] ) ( \w + ) / g,
381
- paramMatch ,
382
- lastMatchedIndex = 0 ;
383
-
384
- while ( ( paramMatch = re . exec ( when ) ) !== null ) {
385
- // Find each :param in `when` and replace it with a capturing group.
386
- // Append all other sections of when unchanged.
387
- regex += when . slice ( lastMatchedIndex , paramMatch . index ) ;
388
- switch ( paramMatch [ 1 ] ) {
389
- case ':' :
390
- regex += '([^\\/]*)' ;
391
- break ;
392
- case '*' :
393
- regex += '(.*)' ;
394
- break ;
422
+ function switchRouteMatcher ( on , route ) {
423
+ var keys = route . keys ,
424
+ params = { } ;
425
+
426
+ if ( ! route . regexp ) return null ;
427
+
428
+ var m = route . regexp . exec ( on ) ;
429
+ if ( ! m ) return null ;
430
+
431
+ var N = 0 ;
432
+ for ( var i = 1 , len = m . length ; i < len ; ++ i ) {
433
+ var key = keys [ i - 1 ] ;
434
+
435
+ var val = 'string' == typeof m [ i ]
436
+ ? decodeURIComponent ( m [ i ] )
437
+ : m [ i ] ;
438
+
439
+ if ( key && val ) {
440
+ params [ key . name ] = val ;
395
441
}
396
- params . push ( paramMatch [ 2 ] ) ;
397
- lastMatchedIndex = re . lastIndex ;
398
- }
399
- // Append trailing path part.
400
- regex += when . substr ( lastMatchedIndex ) ;
401
-
402
- var match = on . match ( new RegExp ( regex , whenProperties . caseInsensitiveMatch ? 'i' : '' ) ) ;
403
- if ( match ) {
404
- forEach ( params , function ( name , index ) {
405
- dst [ name ] = match [ index + 1 ] ;
406
- } ) ;
407
442
}
408
- return match ? dst : null ;
443
+ return params ;
409
444
}
410
445
411
446
function updateRoute ( ) {
@@ -489,7 +524,7 @@ function $RouteProvider(){
489
524
// Match a route
490
525
var params , match ;
491
526
forEach ( routes , function ( route , path ) {
492
- if ( ! match && ( params = switchRouteMatcher ( $location . path ( ) , path , route ) ) ) {
527
+ if ( ! match && ( params = switchRouteMatcher ( $location . path ( ) , route ) ) ) {
493
528
match = inherit ( route , {
494
529
params : extend ( { } , $location . search ( ) , params ) ,
495
530
pathParams : params } ) ;
0 commit comments