2
2
import { TransitionHookOptions , IEventHook , HookResult } from "./interface" ;
3
3
import { defaults , noop } from "../common/common" ;
4
4
import { fnToString , maxLength } from "../common/strings" ;
5
- import { isDefined , isPromise } from "../common/predicates" ;
6
- import { pattern , val , eq , is , parse } from "../common/hof" ;
5
+ import { isPromise } from "../common/predicates" ;
6
+ import { val , is , parse } from "../common/hof" ;
7
7
import { trace } from "../common/trace" ;
8
8
import { services } from "../common/coreservices" ;
9
9
10
10
import { Rejection } from "./rejectFactory" ;
11
11
import { TargetState } from "../state/targetState" ;
12
- import { ResolveContext } from "../resolve/resolveContext" ;
13
12
import { Transition } from "./transition" ;
14
13
import { State } from "../state/stateObject" ;
15
14
@@ -31,7 +30,8 @@ export class TransitionHook {
31
30
this . options = defaults ( options , defaultOptions ) ;
32
31
}
33
32
34
- private isSuperseded = ( ) => this . options . current ( ) !== this . options . transition ;
33
+ private isSuperseded = ( ) =>
34
+ this . options . current ( ) !== this . options . transition ;
35
35
36
36
invokeHook ( ) : Promise < HookResult > {
37
37
let { options, eventHook } = this ;
@@ -40,38 +40,50 @@ export class TransitionHook {
40
40
return Rejection . superseded ( options . current ( ) ) . toPromise ( ) ;
41
41
}
42
42
43
- let hookResult = ! eventHook . _deregistered
43
+ let synchronousHookResult = ! eventHook . _deregistered
44
44
? eventHook . callback . call ( options . bind , this . transition , this . stateContext )
45
45
: undefined ;
46
- return this . handleHookResult ( hookResult ) ;
46
+
47
+ return this . handleHookResult ( synchronousHookResult ) ;
47
48
}
48
49
49
50
/**
50
51
* This method handles the return value of a Transition Hook.
51
52
*
52
- * A hook can return false, a redirect (TargetState), or a promise (which may resolve to false or a redirect)
53
+ * A hook can return false (cancel), a TargetState (redirect),
54
+ * or a promise (which may later resolve to false or a redirect)
55
+ *
56
+ * This also handles "transition superseded" -- when a new transition
57
+ * was started while the hook was still running
53
58
*/
54
- handleHookResult ( hookResult : HookResult ) : Promise < any > {
55
- if ( ! isDefined ( hookResult ) ) return undefined ;
56
-
57
- /**
58
- * Handles transition superseded, transition aborted and transition redirect.
59
- */
60
- const mapHookResult = pattern ( [
61
- // Transition is no longer current
62
- [ this . isSuperseded , ( ) => Rejection . superseded ( this . options . current ( ) ) . toPromise ( ) ] ,
63
- // If the hook returns false, abort the current Transition
64
- [ eq ( false ) , ( ) => Rejection . aborted ( "Hook aborted transition" ) . toPromise ( ) ] ,
65
- // If the hook returns a Transition, halt the current Transition and redirect to that Transition.
66
- [ is ( TargetState ) , ( target : TargetState ) => Rejection . redirected ( target ) . toPromise ( ) ] ,
67
- // A promise was returned, wait for the promise and then chain another hookHandler
68
- [ isPromise , ( promise : Promise < any > ) => promise . then ( this . handleHookResult . bind ( this ) ) ]
69
- ] ) ;
70
-
71
- let transitionResult = mapHookResult ( hookResult ) ;
72
- if ( transitionResult ) trace . traceHookResult ( hookResult , transitionResult , this . options ) ;
73
-
74
- return transitionResult ;
59
+ handleHookResult ( result : HookResult ) : Promise < any > {
60
+ // This transition is no longer current.
61
+ // Another transition started while this hook was still running.
62
+ if ( this . isSuperseded ( ) ) {
63
+ // Abort this transition
64
+ return Rejection . superseded ( this . options . current ( ) ) . toPromise ( ) ;
65
+ }
66
+
67
+ // Hook returned a promise
68
+ if ( isPromise ( result ) ) {
69
+ // Wait for the promise, then reprocess the resolved value
70
+ return result . then ( this . handleHookResult . bind ( this ) ) ;
71
+ }
72
+
73
+ trace . traceHookResult ( result , this . options ) ;
74
+
75
+ // Hook returned false
76
+ if ( result === false ) {
77
+ // Abort this Transition
78
+ return Rejection . aborted ( "Hook aborted transition" ) . toPromise ( ) ;
79
+ }
80
+
81
+ const isTargetState = is ( TargetState ) ;
82
+ // hook returned a TargetState
83
+ if ( isTargetState ( result ) ) {
84
+ // Halt the current Transition and start a redirected Transition (to the TargetState).
85
+ return Rejection . redirected ( result ) . toPromise ( ) ;
86
+ }
75
87
}
76
88
77
89
toString ( ) {
0 commit comments