@@ -7,12 +7,10 @@ import {not, pattern, val, eq, is, parse } from "../common/hof";
7
7
import { trace } from "../common/trace" ;
8
8
import { services } from "../common/coreservices" ;
9
9
10
- import { TransitionRejection , RejectFactory } from "./rejectFactory" ;
10
+ import { Rejection } from "./rejectFactory" ;
11
11
import { TargetState } from "../state/module" ;
12
12
import { ResolveContext } from "../resolve/module" ;
13
13
14
- let REJECT = new RejectFactory ( ) ;
15
-
16
14
let defaultOptions : TransitionHookOptions = {
17
15
async : true ,
18
16
rejectIfSuperseded : true ,
@@ -32,43 +30,45 @@ export class TransitionHook {
32
30
33
31
private isSuperseded = ( ) => this . options . current ( ) !== this . options . transition ;
34
32
35
- /**
36
- * Handles transition abort and transition redirect. Also adds any returned resolvables
37
- * to the pathContext for the current pathElement. If the transition is rejected, then a rejected
38
- * promise is returned here, otherwise undefined is returned.
39
- */
40
- mapHookResult : Function = pattern ( [
41
- // Transition is no longer current
42
- [ this . isSuperseded , ( ) => REJECT . superseded ( this . options . current ( ) ) ] ,
43
- // If the hook returns false, abort the current Transition
44
- [ eq ( false ) , ( ) => REJECT . aborted ( "Hook aborted transition" ) ] ,
45
- // If the hook returns a Transition, halt the current Transition and redirect to that Transition.
46
- [ is ( TargetState ) , ( target ) => REJECT . redirected ( target ) ] ,
47
- // A promise was returned, wait for the promise and then chain another hookHandler
48
- [ isPromise , ( promise ) => promise . then ( this . handleHookResult . bind ( this ) ) ]
49
- ] ) ;
50
-
51
- invokeStep = ( moreLocals ) => { // bind to this
33
+ invokeHook ( moreLocals ) {
52
34
let { options, fn, resolveContext } = this ;
53
35
let locals = extend ( { } , this . locals , moreLocals ) ;
54
36
trace . traceHookInvocation ( this , options ) ;
55
37
if ( options . rejectIfSuperseded && this . isSuperseded ( ) ) {
56
- return REJECT . superseded ( options . current ( ) ) ;
38
+ return Rejection . superseded ( options . current ( ) ) . toPromise ( ) ;
57
39
}
58
40
59
41
// TODO: Need better integration of returned promises in synchronous code.
60
42
if ( ! options . async ) {
61
43
let hookResult = resolveContext . invokeNow ( fn , locals , options ) ;
62
44
return this . handleHookResult ( hookResult ) ;
63
45
}
64
- return resolveContext . invokeLater ( fn , locals , options ) . then ( this . handleHookResult . bind ( this ) ) ;
46
+ return resolveContext . invokeLater ( fn , locals , options ) . then ( val => this . handleHookResult ( val ) ) ;
65
47
} ;
66
48
67
- handleHookResult ( hookResult ) {
49
+ /**
50
+ * This method handles the return value of a Transition Hook.
51
+ *
52
+ * A hook can return false, a redirect (TargetState), or a promise (which may resolve to false or a redirect)
53
+ */
54
+ handleHookResult ( hookResult ) : Promise < any > {
68
55
if ( ! isDefined ( hookResult ) ) return undefined ;
69
- trace . traceHookResult ( hookResult , undefined , this . options ) ;
70
56
71
- let transitionResult = this . mapHookResult ( hookResult ) ;
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 ) => Rejection . redirected ( target ) . toPromise ( ) ] ,
67
+ // A promise was returned, wait for the promise and then chain another hookHandler
68
+ [ isPromise , ( promise ) => promise . then ( this . handleHookResult . bind ( this ) ) ]
69
+ ] ) ;
70
+
71
+ let transitionResult = mapHookResult ( hookResult ) ;
72
72
if ( transitionResult ) trace . traceHookResult ( hookResult , transitionResult , this . options ) ;
73
73
74
74
return transitionResult ;
@@ -92,24 +92,21 @@ export class TransitionHook {
92
92
let results = [ ] ;
93
93
for ( let i = 0 ; i < hooks . length ; i ++ ) {
94
94
try {
95
- results . push ( hooks [ i ] . invokeStep ( locals ) ) ;
95
+ results . push ( hooks [ i ] . invokeHook ( locals ) ) ;
96
96
} catch ( exception ) {
97
- if ( ! swallowExceptions ) return REJECT . aborted ( exception ) ;
98
- console . log ( "Swallowed exception during synchronous hook handler: " + exception ) ; // TODO: What to do here?
97
+ if ( ! swallowExceptions ) {
98
+ return Rejection . aborted ( exception ) . toPromise ( ) ;
99
+ }
100
+
101
+ console . error ( "Swallowed exception during synchronous hook handler: " + exception ) ; // TODO: What to do here?
99
102
}
100
103
}
101
104
102
- let rejections = results . filter ( TransitionHook . isRejection ) ;
105
+ let rejections = results . filter ( Rejection . isTransitionRejectionPromise ) ;
103
106
if ( rejections . length ) return rejections [ 0 ] ;
104
107
105
108
return results
106
- . filter ( not ( TransitionHook . isRejection ) )
107
109
. filter ( < Predicate < any > > isPromise )
108
110
. reduce ( ( chain , promise ) => chain . then ( val ( promise ) ) , services . $q . when ( ) ) ;
109
111
}
110
-
111
-
112
- static isRejection ( hookResult ) {
113
- return hookResult && hookResult . reason instanceof TransitionRejection && hookResult ;
114
- }
115
112
}
0 commit comments