-
Notifications
You must be signed in to change notification settings - Fork 105
/
transition.js
73 lines (61 loc) · 2.35 KB
/
transition.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import asyncProcess from './async'
import constants from './constants'
let nameToIDs = name => {
return name.split('.').reduce((ids, name) => {
return ids.concat(ids.length ? ids[ids.length - 1] + '.' + name : name)
}, [])
}
export default function transition(router, toState, fromState, callback) {
let cancelled = false
let cancel = () => cancelled = true
let done = (err, res) => callback(cancelled ? constants.TRANSITION_CANCELLED : err, res)
let i
let fromStateIds = fromState ? nameToIDs(fromState.name) : []
let toStateIds = nameToIDs(toState.name)
let maxI = Math.min(fromStateIds.length, toStateIds.length)
for (i = 0; i < maxI; i += 1) {
if (fromStateIds[i] !== toStateIds[i]) break
}
let toDeactivate = fromStateIds.slice(i).reverse()
let toActivate = toStateIds.slice(i)
let intersection = fromState ? (i > 0 ? fromStateIds[i - 1] : '') : null
let canDeactivate = (toState, fromState, cb) => {
if (cancelled) done()
else {
let canDeactivateFunctions = toDeactivate
.map(name => router._cmps[name])
.filter(comp => comp && comp.canDeactivate)
.map(comp => comp.canDeactivate)
asyncProcess(
canDeactivateFunctions, toState, fromState,
(err, res) => cb(err ? constants.CANNOT_DEACTIVATE : null, res)
)
}
}
let canActivate = (toState, fromState, cb) => {
if (cancelled) done()
else {
let canActivateFunctions = toActivate
.map(name => router._canAct[name])
.filter(_ => _)
asyncProcess(
canActivateFunctions, toState, fromState,
(err, res) => cb(err ? constants.CANNOT_ACTIVATE : null, res)
)
}
}
let nodeListener = (toState, fromState, cb) => {
if (cancelled) done()
else {
let listeners = router._cbs['^' + intersection] || []
asyncProcess(
listeners, toState, fromState,
(err, res) => cb(err ? constants.NODE_LISTENER_ERR : null, res),
true
)
}
}
let pipeline = fromState ? [canDeactivate, canActivate, nodeListener] : [canActivate]
asyncProcess(pipeline, toState, fromState, done)
return cancel
}