1
1
/**
2
2
* State-based routing for AngularJS
3
- * @version v0.2.11
3
+ * @version v0.2.11-dev-2014-09-29
4
4
* @link http://angular-ui.github.com/
5
5
* @license MIT License, http://www.opensource.org/licenses/MIT
6
6
*/
@@ -285,6 +285,7 @@ function $Resolve( $q, $injector) {
285
285
*/
286
286
this . study = function ( invocables ) {
287
287
if ( ! isObject ( invocables ) ) throw new Error ( "'invocables' must be an object" ) ;
288
+ var invocableKeys = Object . keys ( invocables || { } ) ;
288
289
289
290
// Perform a topological sort of invocables to build an ordered plan
290
291
var plan = [ ] , cycle = [ ] , visited = { } ;
@@ -345,7 +346,7 @@ function $Resolve( $q, $injector) {
345
346
if ( ! -- wait ) {
346
347
if ( ! merged ) merge ( values , parent . $$values ) ;
347
348
result . $$values = values ;
348
- result . $$promises = true ; // keep for isResolve()
349
+ result . $$promises = result . $$promises || true ; // keep for isResolve()
349
350
delete result . $$inheritedValues ;
350
351
resolution . resolve ( values ) ;
351
352
}
@@ -355,28 +356,36 @@ function $Resolve( $q, $injector) {
355
356
result . $$failure = reason ;
356
357
resolution . reject ( reason ) ;
357
358
}
358
-
359
+
360
+ // TODO: Remove this when we merge in 'new' branch
361
+ function omit ( obj ) {
362
+ var copy = { } , keys = angular . isArray ( arguments [ 1 ] ) ? arguments [ 1 ] : arguments . slice ( 1 ) ;
363
+ for ( var key in obj )
364
+ if ( keys . indexOf ( key ) == - 1 ) copy [ key ] = obj [ key ] ;
365
+ return copy ;
366
+ }
367
+
359
368
// Short-circuit if parent has already failed
360
369
if ( isDefined ( parent . $$failure ) ) {
361
370
fail ( parent . $$failure ) ;
362
371
return result ;
363
372
}
364
373
365
374
if ( parent . $$inheritedValues ) {
366
- merge ( values , parent . $$inheritedValues ) ;
375
+ merge ( values , omit ( parent . $$inheritedValues , invocableKeys ) ) ;
367
376
}
368
377
369
378
// Merge parent values if the parent has already resolved, or merge
370
379
// parent promises and wait if the parent resolve is still in progress.
380
+ extend ( promises , parent . $$promises ) ;
371
381
if ( parent . $$values ) {
372
- merged = merge ( values , parent . $$values ) ;
373
- result . $$inheritedValues = parent . $$values ;
382
+ merged = merge ( values , omit ( parent . $$values , invocableKeys ) ) ;
383
+ result . $$inheritedValues = omit ( parent . $$values , invocableKeys ) ;
374
384
done ( ) ;
375
385
} else {
376
386
if ( parent . $$inheritedValues ) {
377
- result . $$inheritedValues = parent . $$inheritedValues ;
387
+ result . $$inheritedValues = omit ( parent . $$inheritedValues , invocableKeys ) ;
378
388
}
379
- extend ( promises , parent . $$promises ) ;
380
389
parent . then ( done , fail ) ;
381
390
}
382
391
@@ -579,7 +588,7 @@ function $TemplateFactory( $http, $templateCache, $injector) {
579
588
if ( isFunction ( url ) ) url = url ( params ) ;
580
589
if ( url == null ) return null ;
581
590
else return $http
582
- . get ( url , { cache : $templateCache } )
591
+ . get ( url , { cache : $templateCache , headers : { Accept : 'text/html' } } )
583
592
. then ( function ( response ) { return response . data ; } ) ;
584
593
} ;
585
594
@@ -917,7 +926,7 @@ UrlMatcher.prototype.format = function (values) {
917
926
value = values [ param ] ;
918
927
cfg = this . params [ param ] ;
919
928
920
- if ( ! isDefined ( value ) && ( segments [ i ] === '/' || segments [ i + 1 ] === '/' ) ) continue ;
929
+ if ( ! isDefined ( value ) && ( segments [ i ] === '/' && segments [ i + 1 ] === '/' ) ) continue ;
921
930
if ( value != null ) result += encodeURIComponent ( cfg . type . encode ( value ) ) ;
922
931
result += segments [ i + 1 ] ;
923
932
}
@@ -934,7 +943,7 @@ UrlMatcher.prototype.format = function (values) {
934
943
result += ( search ? '&' : '?' ) + param + '=' + ( array ? value : encodeURIComponent ( value ) ) ;
935
944
search = true ;
936
945
}
937
- return result ;
946
+ return result . replace ( '//' , '/' ) ;
938
947
} ;
939
948
940
949
UrlMatcher . prototype . $types = { } ;
@@ -1710,6 +1719,10 @@ function $UrlRouterProvider( $locationProvider, $urlMatcherFactory) {
1710
1719
if ( ! urlMatcher . validates ( params ) ) return null ;
1711
1720
1712
1721
var isHtml5 = $locationProvider . html5Mode ( ) ;
1722
+ if ( angular . isObject ( isHtml5 ) ) {
1723
+ isHtml5 = isHtml5 . enabled ;
1724
+ }
1725
+
1713
1726
var url = urlMatcher . format ( params ) ;
1714
1727
options = options || { } ;
1715
1728
@@ -1872,6 +1885,8 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
1872
1885
1873
1886
if ( path ) {
1874
1887
if ( ! base ) throw new Error ( "No reference point given for path '" + name + "'" ) ;
1888
+ base = findState ( base ) ;
1889
+
1875
1890
var rel = name . split ( "." ) , i = 0 , pathLength = rel . length , current = base ;
1876
1891
1877
1892
for ( ; i < pathLength ; i ++ ) {
@@ -2379,9 +2394,12 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
2379
2394
* reload: true, inherit: false, notify: false
2380
2395
* });
2381
2396
* </pre>
2397
+ *
2398
+ * @returns {promise } A promise representing the state of the new transition. See
2399
+ * {@link ui.router.state.$state#methods_go $state.go}.
2382
2400
*/
2383
2401
$state . reload = function reload ( ) {
2384
- $state . transitionTo ( $state . current , $stateParams , { reload : true , inherit : false , notify : false } ) ;
2402
+ return $state . transitionTo ( $state . current , $stateParams , { reload : true , inherit : false , notify : false } ) ;
2385
2403
} ;
2386
2404
2387
2405
/**
@@ -2521,7 +2539,13 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
2521
2539
throw new Error ( "Could not resolve '" + to + "' from state '" + options . relative + "'" ) ;
2522
2540
}
2523
2541
}
2524
- if ( toState [ abstractKey ] ) throw new Error ( "Cannot transition to abstract state '" + to + "'" ) ;
2542
+ var abstract = toState [ abstractKey ] ;
2543
+ if ( typeof abstract === 'string' ) {
2544
+ return $state . transitionTo ( abstract . toParams , options ) ;
2545
+ } else if ( abstract === true ) {
2546
+ throw new Error ( "Cannot transition to abstract state '" + to + "'" ) ;
2547
+ }
2548
+
2525
2549
if ( options . inherit ) toParams = inheritParams ( $stateParams , toParams || { } , $state . $current , toState ) ;
2526
2550
to = toState ;
2527
2551
@@ -2705,8 +2729,8 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
2705
2729
*
2706
2730
* @description
2707
2731
* Similar to {@link ui.router.state.$state#methods_includes $state.includes},
2708
- * but only checks for the full state name. If params is supplied then it will be
2709
- * tested for strict equality against the current active params object, so all params
2732
+ * but only checks for the full state name. If params is supplied then it will be
2733
+ * tested for strict equality against the current active params object, so all params
2710
2734
* must match with none missing and no extras.
2711
2735
*
2712
2736
* @example
@@ -2722,13 +2746,19 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
2722
2746
* <div ng-class="{highlighted: $state.is('.item')}">Item</div>
2723
2747
* </pre>
2724
2748
*
2725
- * @param {string|object } stateName The state name (absolute or relative) or state object you'd like to check.
2726
- * @param {object= } params A param object, e.g. `{sectionId: section.id}`, that you'd like
2749
+ * @param {string|object } stateOrName The state name (absolute or relative) or state object you'd like to check.
2750
+ * @param {object= } params A param object, e.g. `{sectionId: section.id}`, that you'd like
2727
2751
* to test against the current active state.
2752
+ * @param {object= } options An options object. The options are:
2753
+ *
2754
+ * - **`relative`** - {string|object} - If `stateOrName` is a relative state name and `options.relative` is set, .is will
2755
+ * test relative to `options.relative` state (or name).
2756
+ *
2728
2757
* @returns {boolean } Returns true if it is the state.
2729
2758
*/
2730
- $state . is = function is ( stateOrName , params ) {
2731
- var state = findState ( stateOrName ) ;
2759
+ $state . is = function is ( stateOrName , params , options ) {
2760
+ options = extend ( { relative : $state . $current } , options || { } ) ;
2761
+ var state = findState ( stateOrName , options . relative ) ;
2732
2762
2733
2763
if ( ! isDefined ( state ) ) {
2734
2764
return undefined ;
@@ -2783,19 +2813,25 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
2783
2813
*
2784
2814
* @param {string } stateOrName A partial name, relative name, or glob pattern
2785
2815
* to be searched for within the current state name.
2786
- * @param {object } params A param object, e.g. `{sectionId: section.id}`,
2816
+ * @param {object= } params A param object, e.g. `{sectionId: section.id}`,
2787
2817
* that you'd like to test against the current active state.
2818
+ * @param {object= } options An options object. The options are:
2819
+ *
2820
+ * - **`relative`** - {string|object=} - If `stateOrName` is a relative state reference and `options.relative` is set,
2821
+ * .includes will test relative to `options.relative` state (or name).
2822
+ *
2788
2823
* @returns {boolean } Returns true if it does include the state
2789
2824
*/
2790
- $state . includes = function includes ( stateOrName , params ) {
2825
+ $state . includes = function includes ( stateOrName , params , options ) {
2826
+ options = extend ( { relative : $state . $current } , options || { } ) ;
2791
2827
if ( isString ( stateOrName ) && isGlob ( stateOrName ) ) {
2792
2828
if ( ! doesStateMatchGlob ( stateOrName ) ) {
2793
2829
return false ;
2794
2830
}
2795
2831
stateOrName = $state . $current . name ;
2796
2832
}
2797
- var state = findState ( stateOrName ) ;
2798
2833
2834
+ var state = findState ( stateOrName , options . relative ) ;
2799
2835
if ( ! isDefined ( state ) ) {
2800
2836
return undefined ;
2801
2837
}
@@ -2848,7 +2884,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
2848
2884
2849
2885
var nav = ( state && options . lossy ) ? state . navigable : state ;
2850
2886
2851
- if ( ! nav || ! nav . url ) {
2887
+ if ( ! nav || nav . url === undefined || nav . url === null ) {
2852
2888
return null ;
2853
2889
}
2854
2890
return $urlRouter . href ( nav . url , filterByKeys ( objectKeys ( state . params ) , params || { } ) , {
@@ -2864,13 +2900,14 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
2864
2900
* @description
2865
2901
* Returns the state configuration object for any specific state or all states.
2866
2902
*
2867
- * @param {string|Sbject = } stateOrName (absolute or relative) If provided, will only get the config for
2903
+ * @param {string|object = } stateOrName (absolute or relative) If provided, will only get the config for
2868
2904
* the requested state. If not provided, returns an array of ALL state configs.
2905
+ * @param {string|object= } context When stateOrName is a relative state reference, the state will be retrieved relative to context.
2869
2906
* @returns {Object|Array } State configuration object or array of all objects.
2870
2907
*/
2871
2908
$state . get = function ( stateOrName , context ) {
2872
2909
if ( arguments . length === 0 ) return objectKeys ( states ) . map ( function ( name ) { return states [ name ] . self ; } ) ;
2873
- var state = findState ( stateOrName , context ) ;
2910
+ var state = findState ( stateOrName , context || $state . $current ) ;
2874
2911
return ( state && state . self ) ? state . self : null ;
2875
2912
} ;
2876
2913
@@ -3075,7 +3112,7 @@ angular.module('ui.router.state').provider('$uiViewScroll', $ViewScrollProvider)
3075
3112
* @description
3076
3113
* The ui-view directive tells $state where to place your templates.
3077
3114
*
3078
- * @param {string= } ui-view A view name. The name should be unique amongst the other views in the
3115
+ * @param {string= } name A view name. The name should be unique amongst the other views in the
3079
3116
* same state. You can have views of the same name that live in different states.
3080
3117
*
3081
3118
* @param {string= } autoscroll It allows you to set the scroll behavior of the browser window
@@ -3172,8 +3209,8 @@ angular.module('ui.router.state').provider('$uiViewScroll', $ViewScrollProvider)
3172
3209
* <ui-view autoscroll='scopeVariable'/>
3173
3210
* </pre>
3174
3211
*/
3175
- $ViewDirective . $inject = [ '$state' , '$injector' , '$uiViewScroll' ] ;
3176
- function $ViewDirective ( $state , $injector , $uiViewScroll ) {
3212
+ $ViewDirective . $inject = [ '$state' , '$injector' , '$uiViewScroll' , '$interpolate' ] ;
3213
+ function $ViewDirective ( $state , $injector , $uiViewScroll , $interpolate ) {
3177
3214
3178
3215
function getService ( ) {
3179
3216
return ( $injector . has ) ? function ( service ) {
@@ -3203,8 +3240,14 @@ function $ViewDirective( $state, $injector, $uiViewScroll) {
3203
3240
3204
3241
if ( $animate ) {
3205
3242
return {
3206
- enter : function ( element , target , cb ) { $animate . enter ( element , null , target , cb ) ; } ,
3207
- leave : function ( element , cb ) { $animate . leave ( element , cb ) ; }
3243
+ enter : function ( element , target , cb ) {
3244
+ var promise = $animate . enter ( element , null , target , cb ) ;
3245
+ if ( promise && promise . then ) promise . then ( cb ) ;
3246
+ } ,
3247
+ leave : function ( element , cb ) {
3248
+ var promise = $animate . leave ( element , cb ) ;
3249
+ if ( promise && promise . then ) promise . then ( cb ) ;
3250
+ }
3208
3251
} ;
3209
3252
}
3210
3253
@@ -3264,7 +3307,7 @@ function $ViewDirective( $state, $injector, $uiViewScroll) {
3264
3307
3265
3308
function updateView ( firstTime ) {
3266
3309
var newScope ,
3267
- name = getUiViewName ( attrs , $element . inheritedData ( '$uiView' ) ) ,
3310
+ name = getUiViewName ( scope , attrs , $element , $interpolate ) ,
3268
3311
previousLocals = name && $state . $current && $state . $current . locals [ name ] ;
3269
3312
3270
3313
if ( ! firstTime && previousLocals === latestLocals ) return ; // nothing to do
@@ -3273,6 +3316,10 @@ function $ViewDirective( $state, $injector, $uiViewScroll) {
3273
3316
3274
3317
var clone = $transclude ( newScope , function ( clone ) {
3275
3318
renderer . enter ( clone , $element , function onUiViewEnter ( ) {
3319
+ if ( currentScope ) {
3320
+ currentScope . $emit ( '$viewContentAnimationEnded' ) ;
3321
+ }
3322
+
3276
3323
if ( angular . isDefined ( autoScrollExp ) && ! autoScrollExp || scope . $eval ( autoScrollExp ) ) {
3277
3324
$uiViewScroll ( clone ) ;
3278
3325
}
@@ -3302,16 +3349,16 @@ function $ViewDirective( $state, $injector, $uiViewScroll) {
3302
3349
return directive ;
3303
3350
}
3304
3351
3305
- $ViewDirectiveFill . $inject = [ '$compile' , '$controller' , '$state' ] ;
3306
- function $ViewDirectiveFill ( $compile , $controller , $state ) {
3352
+ $ViewDirectiveFill . $inject = [ '$compile' , '$controller' , '$state' , '$interpolate' ] ;
3353
+ function $ViewDirectiveFill ( $compile , $controller , $state , $interpolate ) {
3307
3354
return {
3308
3355
restrict : 'ECA' ,
3309
3356
priority : - 400 ,
3310
3357
compile : function ( tElement ) {
3311
3358
var initial = tElement . html ( ) ;
3312
3359
return function ( scope , $element , attrs ) {
3313
3360
var current = $state . $current ,
3314
- name = getUiViewName ( attrs , $element . inheritedData ( '$uiView' ) ) ,
3361
+ name = getUiViewName ( scope , attrs , $element , $interpolate ) ,
3315
3362
locals = current && current . locals [ name ] ;
3316
3363
3317
3364
if ( ! locals ) {
@@ -3341,10 +3388,11 @@ function $ViewDirectiveFill ($compile, $controller, $state) {
3341
3388
3342
3389
/**
3343
3390
* Shared ui-view code for both directives:
3344
- * Given attributes and inherited $uiView data , return the view's name
3391
+ * Given scope, element, and its attributes , return the view's name
3345
3392
*/
3346
- function getUiViewName ( attrs , inherited ) {
3347
- var name = attrs . uiView || attrs . name || '' ;
3393
+ function getUiViewName ( scope , attrs , element , $interpolate ) {
3394
+ var name = $interpolate ( attrs . uiView || attrs . name || '' ) ( scope ) ;
3395
+ var inherited = element . inheritedData ( '$uiView' ) ;
3348
3396
return name . indexOf ( '@' ) >= 0 ? name : ( name + '@' + ( inherited ? inherited . state . name : '' ) ) ;
3349
3397
}
3350
3398
@@ -3439,6 +3487,7 @@ function $StateRefDirective($state, $timeout) {
3439
3487
link : function ( scope , element , attrs , uiSrefActive ) {
3440
3488
var ref = parseStateRef ( attrs . uiSref , $state . current . name ) ;
3441
3489
var params = null , url = null , base = stateContext ( element ) || $state . $current ;
3490
+ var newHref = null , isAnchor = element . prop ( "tagName" ) === "A" ;
3442
3491
var isForm = element [ 0 ] . nodeName === "FORM" ;
3443
3492
var attr = isForm ? "action" : "href" , nav = true ;
3444
3493
@@ -3452,10 +3501,10 @@ function $StateRefDirective($state, $timeout) {
3452
3501
} ) ;
3453
3502
3454
3503
var update = function ( newVal ) {
3455
- if ( newVal ) params = newVal ;
3504
+ if ( newVal ) params = angular . copy ( newVal ) ;
3456
3505
if ( ! nav ) return ;
3457
3506
3458
- var newHref = $state . href ( ref . state , params , options ) ;
3507
+ newHref = $state . href ( ref . state , params , options ) ;
3459
3508
3460
3509
var activeDirective = uiSrefActive [ 1 ] || uiSrefActive [ 0 ] ;
3461
3510
if ( activeDirective ) {
@@ -3465,14 +3514,14 @@ function $StateRefDirective($state, $timeout) {
3465
3514
nav = false ;
3466
3515
return false ;
3467
3516
}
3468
- element [ 0 ] [ attr ] = newHref ;
3517
+ attrs . $set ( attr , newHref ) ;
3469
3518
} ;
3470
3519
3471
3520
if ( ref . paramExpr ) {
3472
3521
scope . $watch ( ref . paramExpr , function ( newVal , oldVal ) {
3473
3522
if ( newVal !== params ) update ( newVal ) ;
3474
3523
} , true ) ;
3475
- params = scope . $eval ( ref . paramExpr ) ;
3524
+ params = angular . copy ( scope . $eval ( ref . paramExpr ) ) ;
3476
3525
}
3477
3526
update ( ) ;
3478
3527
@@ -3487,8 +3536,11 @@ function $StateRefDirective($state, $timeout) {
3487
3536
} ) ;
3488
3537
e . preventDefault ( ) ;
3489
3538
3539
+ // if the state has no URL, ignore one preventDefault from the <a> directive.
3540
+ var ignorePreventDefaultCount = isAnchor && ! newHref ? 1 : 0 ;
3490
3541
e . preventDefault = function ( ) {
3491
- $timeout . cancel ( transition ) ;
3542
+ if ( ignorePreventDefaultCount -- <= 0 )
3543
+ $timeout . cancel ( transition ) ;
3492
3544
} ;
3493
3545
}
3494
3546
} ) ;
@@ -3604,7 +3656,7 @@ function $StateRefActiveDirective($state, $stateParams, $interpolate) {
3604
3656
if ( typeof $attrs . uiSrefActiveEq !== 'undefined' ) {
3605
3657
return $state . $current . self === state && matchesParams ( ) ;
3606
3658
} else {
3607
- return $state . includes ( state . name ) && matchesParams ( ) ;
3659
+ return state && $state . includes ( state . name ) && matchesParams ( ) ;
3608
3660
}
3609
3661
}
3610
3662
@@ -3655,4 +3707,4 @@ function $IncludedByStateFilter($state) {
3655
3707
angular . module ( 'ui.router.state' )
3656
3708
. filter ( 'isState' , $IsStateFilter )
3657
3709
. filter ( 'includedByState' , $IncludedByStateFilter ) ;
3658
- } ) ( window , window . angular ) ;
3710
+ } ) ( window , window . angular ) ;
0 commit comments