3
3
* @module url
4
4
*/
5
5
/** for typedoc */
6
- import { composeSort , createProxyFunctions , extend , inArray , removeFrom , sortBy } from '../common/common' ;
6
+ import { createProxyFunctions , extend , removeFrom } from '../common/common' ;
7
7
import { isDefined , isFunction , isString } from '../common/predicates' ;
8
8
import { UrlMatcher } from './urlMatcher' ;
9
9
import { RawParams } from '../params/interface' ;
10
10
import { Disposable } from '../interface' ;
11
11
import { UIRouter } from '../router' ;
12
- import { is , pattern , pipe , prop , val } from '../common/hof' ;
12
+ import { is , pattern , val } from '../common/hof' ;
13
13
import { UrlRuleFactory } from './urlRule' ;
14
14
import { TargetState } from '../state/targetState' ;
15
- import { MatchResult , UrlParts , UrlRule , UrlRuleHandlerFn , UrlRuleMatchFn , UrlRulesApi , UrlSyncApi } from './interface' ;
15
+ import { MatcherUrlRule , MatchResult , UrlParts , UrlRule , UrlRuleHandlerFn , UrlRuleMatchFn , UrlRulesApi , UrlSyncApi , } from './interface' ;
16
16
import { TargetStateDef } from '../state/interface' ;
17
17
18
18
/** @hidden */
@@ -24,7 +24,26 @@ function appendBasePath(url: string, isHtml5: boolean, absolute: boolean, baseHr
24
24
}
25
25
26
26
/** @hidden */
27
- const getMatcher = prop ( "urlMatcher" ) ;
27
+ const prioritySort = ( a : UrlRule , b : UrlRule ) =>
28
+ ( b . priority || 0 ) - ( a . priority || 0 ) ;
29
+
30
+ /** @hidden */
31
+ const typeSort = ( a : UrlRule , b : UrlRule ) => {
32
+ const weights = { "STATE" : 4 , "URLMATCHER" : 4 , "REGEXP" : 3 , "RAW" : 2 , "OTHER" : 1 } ;
33
+ return ( weights [ a . type ] || 0 ) - ( weights [ b . type ] || 0 ) ;
34
+ } ;
35
+
36
+ /** @hidden */
37
+ const urlMatcherSort = ( a : MatcherUrlRule , b : MatcherUrlRule ) =>
38
+ ! a . urlMatcher || ! b . urlMatcher ? 0 : UrlMatcher . compare ( a . urlMatcher , b . urlMatcher ) ;
39
+
40
+ /** @hidden */
41
+ const idSort = ( a : UrlRule , b : UrlRule ) => {
42
+ // Identically sorted STATE and URLMATCHER best rule will be chosen by `matchPriority` after each rule matches the URL
43
+ const useMatchPriority = { STATE : true , URLMATCHER : true } ;
44
+ const equal = useMatchPriority [ a . type ] && useMatchPriority [ b . type ] ;
45
+ return equal ? 0 : ( a . $id || 0 ) - ( b . $id || 0 ) ;
46
+ } ;
28
47
29
48
/**
30
49
* Default rule priority sorting function.
@@ -34,17 +53,25 @@ const getMatcher = prop("urlMatcher");
34
53
* - Explicit priority (set rule priority using [[UrlRulesApi.when]])
35
54
* - Rule type (STATE: 4, URLMATCHER: 4, REGEXP: 3, RAW: 2, OTHER: 1)
36
55
* - `UrlMatcher` specificity ([[UrlMatcher.compare]]): works for STATE and URLMATCHER types to pick the most specific rule.
37
- * - Registration order (for rule types other than STATE and URLMATCHER)
56
+ * - Rule registration order (for rule types other than STATE and URLMATCHER)
57
+ * - Equally sorted State and UrlMatcher rules will each match the URL.
58
+ * Then, the *best* match is chosen based on how many parameter values were matched.
38
59
*
39
60
* @coreapi
40
61
*/
41
62
let defaultRuleSortFn : ( a : UrlRule , b : UrlRule ) => number ;
42
- defaultRuleSortFn = composeSort (
43
- sortBy ( pipe ( prop ( "priority" ) , x => - x ) ) ,
44
- sortBy ( pipe ( prop ( "type" ) , type => ( { "STATE" : 4 , "URLMATCHER" : 4 , "REGEXP" : 3 , "RAW" : 2 , "OTHER" : 1 } ) [ type ] ) ) ,
45
- ( a , b ) => ( getMatcher ( a ) && getMatcher ( b ) ) ? UrlMatcher . compare ( getMatcher ( a ) , getMatcher ( b ) ) : 0 ,
46
- sortBy ( prop ( "$id" ) , inArray ( [ "REGEXP" , "RAW" , "OTHER" ] ) ) ,
47
- ) ;
63
+ defaultRuleSortFn = ( a , b ) => {
64
+ let cmp = prioritySort ( a , b ) ;
65
+ if ( cmp !== 0 ) return cmp ;
66
+
67
+ cmp = typeSort ( a , b ) ;
68
+ if ( cmp !== 0 ) return cmp ;
69
+
70
+ cmp = urlMatcherSort ( a as MatcherUrlRule , b as MatcherUrlRule ) ;
71
+ if ( cmp !== 0 ) return cmp ;
72
+
73
+ return idSort ( a , b ) ;
74
+ } ;
48
75
49
76
/**
50
77
* Updates URL and responds to URL changes
@@ -229,7 +256,7 @@ export class UrlRouter implements UrlRulesApi, UrlSyncApi, Disposable {
229
256
href ( urlMatcher : UrlMatcher , params ?: any , options ?: { absolute : boolean } ) : string {
230
257
let url = urlMatcher . format ( params ) ;
231
258
if ( url == null ) return null ;
232
-
259
+
233
260
options = options || { absolute : false } ;
234
261
235
262
let cfg = this . _router . urlService . config ;
0 commit comments