22import { TransitionHookOptions , IEventHook , HookResult } from "./interface" ;
33import { defaults , noop } from "../common/common" ;
44import { 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" ;
77import { trace } from "../common/trace" ;
88import { services } from "../common/coreservices" ;
99
1010import { Rejection } from "./rejectFactory" ;
1111import { TargetState } from "../state/targetState" ;
12- import { ResolveContext } from "../resolve/resolveContext" ;
1312import { Transition } from "./transition" ;
1413import { State } from "../state/stateObject" ;
1514
@@ -31,7 +30,8 @@ export class TransitionHook {
3130 this . options = defaults ( options , defaultOptions ) ;
3231 }
3332
34- private isSuperseded = ( ) => this . options . current ( ) !== this . options . transition ;
33+ private isSuperseded = ( ) =>
34+ this . options . current ( ) !== this . options . transition ;
3535
3636 invokeHook ( ) : Promise < HookResult > {
3737 let { options, eventHook } = this ;
@@ -40,38 +40,50 @@ export class TransitionHook {
4040 return Rejection . superseded ( options . current ( ) ) . toPromise ( ) ;
4141 }
4242
43- let hookResult = ! eventHook . _deregistered
43+ let synchronousHookResult = ! eventHook . _deregistered
4444 ? eventHook . callback . call ( options . bind , this . transition , this . stateContext )
4545 : undefined ;
46- return this . handleHookResult ( hookResult ) ;
46+
47+ return this . handleHookResult ( synchronousHookResult ) ;
4748 }
4849
4950 /**
5051 * This method handles the return value of a Transition Hook.
5152 *
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
5358 */
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+ }
7587 }
7688
7789 toString ( ) {
0 commit comments