@@ -70,12 +70,14 @@ function UrlMatcher(pattern, config) {
70
70
// The regular expression is somewhat complicated due to the need to allow curly braces
71
71
// inside the regular expression. The placeholder regexp breaks down as follows:
72
72
// ([:*])(\w+) classic placeholder ($1 / $2)
73
- // \{(\w+)(?:\:( ... ))?\} curly brace placeholder ($3) with optional regexp ... ($4)
73
+ // ([:]?)([\w-]+) classic search placeholder (supports snake-case-params) ($1 / $2)
74
+ // \{(\w+)(?:\:( ... ))?\} curly brace placeholder ($3) with optional regexp/type ... ($4)
74
75
// (?: ... | ... | ... )+ the regexp consists of any number of atoms, an atom being either
75
76
// [^{}\\]+ - anything other than curly braces or backslash
76
77
// \\. - a backslash escape
77
78
// \{(?:[^{}\\]+|\\.)*\} - a matched set of curly braces containing other atoms
78
79
var placeholder = / ( [: * ] ) ( \w + ) | \{ ( \w + ) (?: \: ( (?: [ ^ { } \\ ] + | \\ .| \{ (?: [ ^ { } \\ ] + | \\ .) * \} ) + ) ) ? \} / g,
80
+ searchPlaceholder = / ( [: ] ? ) ( [ \w - ] + ) | \{ ( \w + ) (?: \: ( (?: [ ^ { } \\ ] + | \\ .| \{ (?: [ ^ { } \\ ] + | \\ .) * \} ) + ) ) ? \} / g,
79
81
compiled = '^' , last = 0 , m ,
80
82
segments = this . segments = [ ] ,
81
83
params = this . params = new $$UrlMatcherFactoryProvider . ParamSet ( ) ;
@@ -106,20 +108,26 @@ function UrlMatcher(pattern, config) {
106
108
107
109
// Split into static segments separated by path parameter placeholders.
108
110
// The number of segments is always 1 more than the number of parameters.
109
- var id , regexp , segment , type , cfg ;
110
-
111
- while ( ( m = placeholder . exec ( pattern ) ) ) {
111
+ function matchDetails ( m , isSearch ) {
112
+ var id , regexp , segment , type , cfg ;
112
113
id = m [ 2 ] || m [ 3 ] ; // IE[78] returns '' for unmatched groups instead of null
113
- regexp = m [ 4 ] || ( m [ 1 ] == '*' ? '.*' : '[^/]*' ) ;
114
+ regexp = isSearch ? m [ 4 ] : m [ 4 ] || ( m [ 1 ] == '*' ? '.*' : '[^/]*' ) ;
114
115
segment = pattern . substring ( last , m . index ) ;
115
- type = this . $types [ regexp ] || regexpType ( regexp ) ;
116
+ type = regexp ? UrlMatcher . prototype . $types [ regexp ] || regexpType ( regexp ) : undefined ;
116
117
cfg = config . params [ id ] ;
118
+ return {
119
+ id : id , regexp : regexp , segment : segment , type : type , cfg : cfg
120
+ } ;
121
+ }
117
122
118
- if ( segment . indexOf ( '?' ) >= 0 ) break ; // we're into the search part
123
+ var p , param , segment ;
124
+ while ( ( m = placeholder . exec ( pattern ) ) ) {
125
+ p = matchDetails ( m , false ) ;
126
+ if ( p . segment . indexOf ( '?' ) >= 0 ) break ; // we're into the search part
119
127
120
- var param = addParameter ( id , type , cfg ) ;
121
- compiled += quoteRegExp ( segment , type . $subPattern ( ) , param . isOptional ) ;
122
- segments . push ( segment ) ;
128
+ param = addParameter ( p . id , p . type , p . cfg ) ;
129
+ compiled += quoteRegExp ( p . segment , p . type . $subPattern ( ) , param . isOptional ) ;
130
+ segments . push ( p . segment ) ;
123
131
last = placeholder . lastIndex ;
124
132
}
125
133
segment = pattern . substring ( last ) ;
@@ -132,10 +140,15 @@ function UrlMatcher(pattern, config) {
132
140
segment = segment . substring ( 0 , i ) ;
133
141
this . sourcePath = pattern . substring ( 0 , last + i ) ;
134
142
135
- // Allow parameters to be separated by '?' as well as '&' to make concat() easier
136
- forEach ( search . substring ( 1 ) . split ( / [ & ? ] / ) , function ( key ) {
137
- addParameter ( key , null , config . params [ key ] ) ;
138
- } ) ;
143
+ if ( search . length > 0 ) {
144
+ last = 0 ;
145
+ while ( ( m = searchPlaceholder . exec ( search ) ) ) {
146
+ p = matchDetails ( m , true ) ;
147
+ param = addParameter ( p . id , p . type , p . cfg ) ;
148
+ last = placeholder . lastIndex ;
149
+ // check if ?&
150
+ }
151
+ }
139
152
} else {
140
153
this . sourcePath = pattern ;
141
154
this . sourceSearch = '' ;
@@ -385,7 +398,7 @@ Type.prototype.encode = function(val, key) {
385
398
* @methodOf ui.router.util.type:Type
386
399
*
387
400
* @description
388
- * Converts a string URL parameter value to a custom/native value.
401
+ * Converts a parameter value (from URL string or transition param) to a custom/native value.
389
402
*
390
403
* @param {string } val The URL parameter value to decode.
391
404
* @param {string } key The name of the parameter in which `val` is stored. Can be used for
@@ -433,7 +446,36 @@ function $UrlMatcherFactory() {
433
446
434
447
var isCaseInsensitive = false , isStrictMode = true ;
435
448
449
+ function safeString ( val ) { return isDefined ( val ) ? val . toString ( ) : val ; }
450
+ function coerceEquals ( left , right ) { return left == right ; }
451
+ function angularEquals ( left , right ) { return angular . equals ( left , right ) ; }
452
+ // TODO: function regexpMatches(val) { return isDefined(val) && this.pattern.test(val); }
453
+ function regexpMatches ( val ) { /*jshint validthis:true */ return this . pattern . test ( val ) ; }
454
+ function normalizeStringOrArray ( val ) {
455
+ if ( isArray ( val ) ) {
456
+ var encoded = [ ] ;
457
+ forEach ( val , function ( item ) { encoded . push ( safeString ( item ) ) ; } ) ;
458
+ return encoded ;
459
+ } else {
460
+ return safeString ( val ) ;
461
+ }
462
+ }
463
+
436
464
var enqueue = true , typeQueue = [ ] , injector , defaultTypes = {
465
+ "searchParam" : {
466
+ encode : normalizeStringOrArray ,
467
+ decode : normalizeStringOrArray ,
468
+ equals : angularEquals ,
469
+ is : regexpMatches ,
470
+ pattern : / [ ^ & ? ] * /
471
+ } ,
472
+ "pathParam" : {
473
+ encde : safeString ,
474
+ decode : safeString ,
475
+ equals : coerceEquals ,
476
+ is : regexpMatches ,
477
+ pattern : / [ ^ / ] * /
478
+ } ,
437
479
int : {
438
480
decode : function ( val ) {
439
481
return parseInt ( val , 10 ) ;
@@ -449,7 +491,7 @@ function $UrlMatcherFactory() {
449
491
return val ? 1 : 0 ;
450
492
} ,
451
493
decode : function ( val ) {
452
- return parseInt ( val , 10 ) === 0 ? false : true ;
494
+ return parseInt ( val , 10 ) !== 0 ;
453
495
} ,
454
496
is : function ( val ) {
455
497
return val === true || val === false ;
@@ -720,8 +762,9 @@ function $UrlMatcherFactory() {
720
762
721
763
function getType ( config , urlType ) {
722
764
if ( config . type && urlType ) throw new Error ( "Param '" + id + "' has two type configurations." ) ;
723
- if ( urlType && ! config . type ) return urlType ;
724
- return config . type instanceof Type ? config . type : new Type ( config . type || { } ) ;
765
+ if ( urlType ) return urlType ;
766
+ if ( ! config . type ) return UrlMatcher . prototype . $types . pathParam ;
767
+ return config . type instanceof Type ? config . type : new Type ( config . type ) ;
725
768
}
726
769
727
770
/**
0 commit comments