@@ -7,45 +7,33 @@ import {services} from "../common/coreservices";
7
7
import { PathFactory } from "../path/pathFactory" ;
8
8
import { PathNode } from "../path/node" ;
9
9
10
- import { ViewService } from "../view/view" ;
11
-
12
- import { StateParams } from "../params/stateParams" ;
13
-
14
- import { UrlRouter } from "../url/urlRouter" ;
15
-
16
10
import { TransitionOptions } from "../transition/interface" ;
17
- import { TransitionService , defaultTransOpts } from "../transition/transitionService" ;
18
- import { Rejection } from "../transition/rejectFactory" ;
11
+ import { defaultTransOpts } from "../transition/transitionService" ;
12
+ import { Rejection , RejectType } from "../transition/rejectFactory" ;
19
13
import { Transition } from "../transition/transition" ;
20
14
21
15
import { StateOrName , StateDeclaration , TransitionPromise } from "./interface" ;
22
- import { StateRegistry } from "./stateRegistry" ;
23
16
import { State } from "./stateObject" ;
24
17
import { TargetState } from "./targetState" ;
25
18
26
19
import { RawParams } from "../params/interface" ;
27
20
import { ParamsOrArray } from "../params/interface" ;
28
- import { TransitionManager } from "../hooks/transitionManager" ;
29
21
import { Param } from "../params/param" ;
30
22
import { Glob } from "../common/glob" ;
31
23
import { equalForKeys } from "../common/common" ;
32
24
import { HrefOptions } from "./interface" ;
33
- import { StateProvider } from "./state" ;
34
25
import { bindFunctions } from "../common/common" ;
35
- import { UiRouterGlobals , Globals } from "../globals" ;
26
+ import { Globals } from "../globals" ;
27
+ import { UiRouter } from "../router" ;
28
+ import { StateParams } from "../params/stateParams" ; // for params() return type
36
29
37
30
export class StateService {
38
- get transition ( ) { return this . globals . transition ; }
39
- get params ( ) { return this . globals . params ; }
40
- get current ( ) { return this . globals . current ; }
41
- get $current ( ) { return this . globals . $current ; }
42
-
43
- constructor ( private $view : ViewService ,
44
- private $urlRouter : UrlRouter ,
45
- private $transitions : TransitionService ,
46
- private stateRegistry : StateRegistry ,
47
- private stateProvider : StateProvider ,
48
- private globals : Globals ) {
31
+ get transition ( ) { return this . router . globals . transition ; }
32
+ get params ( ) { return this . router . globals . params ; }
33
+ get current ( ) { return this . router . globals . current ; }
34
+ get $current ( ) { return this . router . globals . $current ; }
35
+
36
+ constructor ( private router : UiRouter ) {
49
37
let getters = [ 'current' , '$current' , 'params' , 'transition' ] ;
50
38
let boundFns = Object . keys ( StateService . prototype ) . filter ( key => getters . indexOf ( key ) === - 1 ) ;
51
39
bindFunctions ( StateService . prototype , this , this , boundFns ) ;
@@ -60,10 +48,11 @@ export class StateService {
60
48
* the result returned.
61
49
*/
62
50
private _handleInvalidTargetState ( fromPath : PathNode [ ] , $to$ : TargetState ) {
63
- const latestThing = ( ) => this . globals . transitionHistory . peekTail ( ) ;
51
+ let globals = < Globals > this . router . globals ;
52
+ const latestThing = ( ) => globals . transitionHistory . peekTail ( ) ;
64
53
let latest = latestThing ( ) ;
65
54
let $from$ = PathFactory . makeTargetState ( fromPath ) ;
66
- let callbackQueue = new Queue < Function > ( [ ] . concat ( this . stateProvider . invalidCallbacks ) ) ;
55
+ let callbackQueue = new Queue < Function > ( [ ] . concat ( this . router . stateProvider . invalidCallbacks ) ) ;
67
56
let { $q, $injector} = services ;
68
57
69
58
const invokeCallback = ( callback : Function ) => $q . when ( $injector . invoke ( callback , null , { $to$, $from$ } ) ) ;
@@ -221,12 +210,13 @@ export class StateService {
221
210
// If we're reloading, find the state object to reload from
222
211
if ( isObject ( options . reload ) && ! ( < any > options . reload ) . name )
223
212
throw new Error ( 'Invalid reload state object' ) ;
224
- options . reloadState = options . reload === true ? this . stateRegistry . root ( ) : this . stateRegistry . matcher . find ( < any > options . reload , options . relative ) ;
213
+ let reg = this . router . stateRegistry ;
214
+ options . reloadState = options . reload === true ? reg . root ( ) : reg . matcher . find ( < any > options . reload , options . relative ) ;
225
215
226
216
if ( options . reload && ! options . reloadState )
227
217
throw new Error ( `No such reload state '${ ( isString ( options . reload ) ? options . reload : ( < any > options . reload ) . name ) } '` ) ;
228
218
229
- let stateDefinition = this . stateRegistry . matcher . find ( identifier , options . relative ) ;
219
+ let stateDefinition = reg . matcher . find ( identifier , options . relative ) ;
230
220
return new TargetState ( identifier , stateDefinition , params , options ) ;
231
221
} ;
232
222
@@ -269,25 +259,56 @@ export class StateService {
269
259
* {@link ui.router.state.$state#methods_go $state.go}.
270
260
*/
271
261
transitionTo ( to : StateOrName , toParams : RawParams = { } , options : TransitionOptions = { } ) : TransitionPromise {
272
- let transHistory = this . globals . transitionHistory ;
262
+ let router = this . router ;
263
+ let globals = < Globals > router . globals ;
264
+ let transHistory = globals . transitionHistory ;
273
265
options = defaults ( options , defaultTransOpts ) ;
274
266
options = extend ( options , { current : transHistory . peekTail . bind ( transHistory ) } ) ;
275
267
276
268
let ref : TargetState = this . target ( to , toParams , options ) ;
277
- let latestSuccess : Transition = this . globals . successfulTransitions . peekTail ( ) ;
278
- const rootPath = ( ) => [ new PathNode ( this . stateRegistry . root ( ) ) ] ;
269
+ let latestSuccess : Transition = globals . successfulTransitions . peekTail ( ) ;
270
+ const rootPath = ( ) => [ new PathNode ( this . router . stateRegistry . root ( ) ) ] ;
279
271
let currentPath : PathNode [ ] = latestSuccess ? latestSuccess . treeChanges ( ) . to : rootPath ( ) ;
280
272
281
273
if ( ! ref . exists ( ) )
282
274
return this . _handleInvalidTargetState ( currentPath , ref ) ;
275
+
283
276
if ( ! ref . valid ( ) )
284
277
return services . $q . reject ( ref . error ( ) ) ;
285
278
286
- let transition = this . $transitions . create ( currentPath , ref ) ;
287
- let tMgr = new TransitionManager ( transition , this . $transitions , this . $urlRouter , this . $view , < StateService > this , this . globals ) ;
288
- let transitionPromise = tMgr . runTransition ( ) ;
279
+ /**
280
+ * Special handling for Ignored, Aborted, and Redirected transitions
281
+ *
282
+ * The semantics for the transition.run() promise and the StateService.transitionTo()
283
+ * promise differ. For instance, the run() promise may be rejected because it was
284
+ * IGNORED, but the transitionTo() promise is resolved because from the user perspective
285
+ * no error occurred. Likewise, the transition.run() promise may be rejected because of
286
+ * a Redirect, but the transitionTo() promise is chained to the new Transition's promise.
287
+ */
288
+ const rejectedTransitionHandler = ( transition ) => ( error ) => {
289
+ if ( error instanceof Rejection ) {
290
+ if ( error . type === RejectType . IGNORED ) {
291
+ router . urlRouter . update ( ) ;
292
+ return globals . current ;
293
+ }
294
+
295
+ if ( error . type === RejectType . SUPERSEDED && error . redirected && error . detail instanceof TargetState ) {
296
+ let redirect : Transition = transition . redirect ( error . detail ) ;
297
+ return redirect . run ( ) . catch ( rejectedTransitionHandler ( redirect ) ) ;
298
+ }
299
+
300
+ if ( error . type === RejectType . ABORTED ) {
301
+ router . urlRouter . update ( ) ;
302
+ }
303
+ }
304
+
305
+ return services . $q . reject ( error ) ;
306
+ } ;
307
+
308
+ let transition = this . router . transitionService . create ( currentPath , ref ) ;
309
+ let transitionToPromise = transition . run ( ) . catch ( rejectedTransitionHandler ( transition ) ) ;
289
310
// Return a promise for the transition, which also has the transition object on it.
290
- return extend ( transitionPromise , { transition } ) ;
311
+ return extend ( transitionToPromise , { transition } ) ;
291
312
} ;
292
313
293
314
/**
@@ -326,7 +347,7 @@ export class StateService {
326
347
*/
327
348
is ( stateOrName : StateOrName , params ?: RawParams , options ?: TransitionOptions ) : boolean {
328
349
options = defaults ( options , { relative : this . $current } ) ;
329
- let state = this . stateRegistry . matcher . find ( stateOrName , options . relative ) ;
350
+ let state = this . router . stateRegistry . matcher . find ( stateOrName , options . relative ) ;
330
351
if ( ! isDefined ( state ) ) return undefined ;
331
352
if ( this . $current !== state ) return false ;
332
353
return isDefined ( params ) && params !== null ? Param . equals ( state . parameters ( ) , this . params , params ) : true ;
@@ -391,7 +412,7 @@ export class StateService {
391
412
if ( ! glob . matches ( this . $current . name ) ) return false ;
392
413
stateOrName = this . $current . name ;
393
414
}
394
- let state = this . stateRegistry . matcher . find ( stateOrName , options . relative ) , include = this . $current . includes ;
415
+ let state = this . router . stateRegistry . matcher . find ( stateOrName , options . relative ) , include = this . $current . includes ;
395
416
396
417
if ( ! isDefined ( state ) ) return undefined ;
397
418
if ( ! isDefined ( include [ state . name ] ) ) return false ;
@@ -436,7 +457,7 @@ export class StateService {
436
457
} ;
437
458
options = defaults ( options , defaultHrefOpts ) ;
438
459
439
- let state = this . stateRegistry . matcher . find ( stateOrName , options . relative ) ;
460
+ let state = this . router . stateRegistry . matcher . find ( stateOrName , options . relative ) ;
440
461
441
462
if ( ! isDefined ( state ) ) return null ;
442
463
if ( options . inherit ) params = < any > this . params . $inherit ( params || { } , this . $current , state ) ;
@@ -446,7 +467,7 @@ export class StateService {
446
467
if ( ! nav || nav . url === undefined || nav . url === null ) {
447
468
return null ;
448
469
}
449
- return this . $ urlRouter. href ( nav . url , Param . values ( state . parameters ( ) , params ) , {
470
+ return this . router . urlRouter . href ( nav . url , Param . values ( state . parameters ( ) , params ) , {
450
471
absolute : options . absolute
451
472
} ) ;
452
473
} ;
@@ -468,7 +489,8 @@ export class StateService {
468
489
get ( stateOrName : StateOrName ) : StateDeclaration ;
469
490
get ( stateOrName : StateOrName , base : StateOrName ) : StateDeclaration ;
470
491
get ( stateOrName ?: StateOrName , base ?: StateOrName ) : any {
471
- if ( arguments . length === 0 ) return this . stateRegistry . get ( ) ;
472
- return this . stateRegistry . get ( stateOrName , base || this . $current ) ;
492
+ let reg = this . router . stateRegistry ;
493
+ if ( arguments . length === 0 ) return reg . get ( ) ;
494
+ return reg . get ( stateOrName , base || this . $current ) ;
473
495
}
474
496
}
0 commit comments