@angular-wave/angular.ts 0.0.11 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular-ts.esm.js +1 -1
- package/dist/angular-ts.umd.js +1 -1
- package/package.json +4 -1
- package/src/exts/messages.md +30 -30
- package/src/index.js +1 -0
- package/src/public.js +2 -0
- package/src/router/adapter/directives/stateDirectives.js +695 -0
- package/src/router/adapter/directives/viewDirective.js +514 -0
- package/src/router/adapter/injectables.js +314 -0
- package/src/router/adapter/interface.js +1 -0
- package/src/router/adapter/locationServices.js +84 -0
- package/src/router/adapter/services.js +126 -0
- package/src/router/adapter/stateFilters.js +43 -0
- package/src/router/adapter/stateProvider.js +137 -0
- package/src/router/adapter/statebuilders/onEnterExitRetain.js +30 -0
- package/src/router/adapter/statebuilders/views.js +146 -0
- package/src/router/adapter/templateFactory.js +218 -0
- package/src/router/adapter/viewScroll.js +31 -0
- package/src/router/core/common/common.js +496 -0
- package/src/router/core/common/coreservices.js +15 -0
- package/src/router/core/common/glob.js +75 -0
- package/src/router/core/common/hof.js +194 -0
- package/src/router/core/common/predicates.js +44 -0
- package/src/router/core/common/queue.js +41 -0
- package/src/router/core/common/safeConsole.js +38 -0
- package/src/router/core/common/strings.js +141 -0
- package/src/router/core/common/trace.js +232 -0
- package/src/router/core/globals.js +29 -0
- package/src/router/core/hooks/coreResolvables.js +33 -0
- package/src/router/core/hooks/ignoredTransition.js +25 -0
- package/src/router/core/hooks/invalidTransition.js +14 -0
- package/src/router/core/hooks/lazyLoad.js +102 -0
- package/src/router/core/hooks/onEnterExitRetain.js +55 -0
- package/src/router/core/hooks/redirectTo.js +36 -0
- package/src/router/core/hooks/resolve.js +57 -0
- package/src/router/core/hooks/updateGlobals.js +30 -0
- package/src/router/core/hooks/url.js +25 -0
- package/src/router/core/hooks/views.js +39 -0
- package/src/router/core/interface.js +3 -0
- package/src/router/core/params/README.md +8 -0
- package/src/router/core/params/param.js +232 -0
- package/src/router/core/params/paramType.js +139 -0
- package/src/router/core/params/paramTypes.js +163 -0
- package/src/router/core/params/stateParams.js +35 -0
- package/src/router/core/path/pathNode.js +77 -0
- package/src/router/core/path/pathUtils.js +199 -0
- package/src/router/core/resolve/interface.js +10 -0
- package/src/router/core/resolve/resolvable.js +124 -0
- package/src/router/core/resolve/resolveContext.js +211 -0
- package/src/router/core/router.js +203 -0
- package/src/router/core/state/README.md +21 -0
- package/src/router/core/state/stateBuilder.js +332 -0
- package/src/router/core/state/stateMatcher.js +65 -0
- package/src/router/core/state/stateObject.js +117 -0
- package/src/router/core/state/stateQueueManager.js +89 -0
- package/src/router/core/state/stateRegistry.js +175 -0
- package/src/router/core/state/stateService.js +592 -0
- package/src/router/core/state/targetState.js +159 -0
- package/src/router/core/transition/hookBuilder.js +127 -0
- package/src/router/core/transition/hookRegistry.js +175 -0
- package/src/router/core/transition/interface.js +14 -0
- package/src/router/core/transition/rejectFactory.js +122 -0
- package/src/router/core/transition/transition.js +739 -0
- package/src/router/core/transition/transitionEventType.js +27 -0
- package/src/router/core/transition/transitionHook.js +199 -0
- package/src/router/core/transition/transitionService.js +311 -0
- package/src/router/core/url/interface.js +1 -0
- package/src/router/core/url/urlConfig.js +165 -0
- package/src/router/core/url/urlMatcher.js +548 -0
- package/src/router/core/url/urlMatcherFactory.js +123 -0
- package/src/router/core/url/urlRouter.js +115 -0
- package/src/router/core/url/urlRule.js +202 -0
- package/src/router/core/url/urlRules.js +348 -0
- package/src/router/core/url/urlService.js +268 -0
- package/src/router/core/view/interface.js +1 -0
- package/src/router/core/view/view.js +312 -0
- package/src/router/router.js +58 -0
- package/test/module-test.html +6 -2
- package/test/module-test.js +0 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { isObject, isString } from "../common/predicates";
|
|
2
|
+
import { stringify } from "../common/strings";
|
|
3
|
+
import { extend } from "../common/common";
|
|
4
|
+
/**
|
|
5
|
+
* Encapsulate the target (destination) state/params/options of a [[Transition]].
|
|
6
|
+
*
|
|
7
|
+
* This class is frequently used to redirect a transition to a new destination.
|
|
8
|
+
*
|
|
9
|
+
* See:
|
|
10
|
+
*
|
|
11
|
+
* - [[HookResult]]
|
|
12
|
+
* - [[TransitionHookFn]]
|
|
13
|
+
* - [[TransitionService.onStart]]
|
|
14
|
+
*
|
|
15
|
+
* To create a `TargetState`, use [[StateService.target]].
|
|
16
|
+
*
|
|
17
|
+
* ---
|
|
18
|
+
*
|
|
19
|
+
* This class wraps:
|
|
20
|
+
*
|
|
21
|
+
* 1) an identifier for a state
|
|
22
|
+
* 2) a set of parameters
|
|
23
|
+
* 3) and transition options
|
|
24
|
+
* 4) the registered state object (the [[StateDeclaration]])
|
|
25
|
+
*
|
|
26
|
+
* Many UI-Router APIs such as [[StateService.go]] take a [[StateOrName]] argument which can
|
|
27
|
+
* either be a *state object* (a [[StateDeclaration]] or [[StateObject]]) or a *state name* (a string).
|
|
28
|
+
* The `TargetState` class normalizes those options.
|
|
29
|
+
*
|
|
30
|
+
* A `TargetState` may be valid (the state being targeted exists in the registry)
|
|
31
|
+
* or invalid (the state being targeted is not registered).
|
|
32
|
+
*/
|
|
33
|
+
export class TargetState {
|
|
34
|
+
/**
|
|
35
|
+
* The TargetState constructor
|
|
36
|
+
*
|
|
37
|
+
* Note: Do not construct a `TargetState` manually.
|
|
38
|
+
* To create a `TargetState`, use the [[StateService.target]] factory method.
|
|
39
|
+
*
|
|
40
|
+
* @param _stateRegistry The StateRegistry to use to look up the _definition
|
|
41
|
+
* @param _identifier An identifier for a state.
|
|
42
|
+
* Either a fully-qualified state name, or the object used to define the state.
|
|
43
|
+
* @param _params Parameters for the target state
|
|
44
|
+
* @param _options Transition options.
|
|
45
|
+
*
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
constructor(_stateRegistry, _identifier, _params, _options) {
|
|
49
|
+
this._stateRegistry = _stateRegistry;
|
|
50
|
+
this._identifier = _identifier;
|
|
51
|
+
this._identifier = _identifier;
|
|
52
|
+
this._params = extend({}, _params || {});
|
|
53
|
+
this._options = extend({}, _options || {});
|
|
54
|
+
this._definition = _stateRegistry.matcher.find(
|
|
55
|
+
_identifier,
|
|
56
|
+
this._options.relative,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
/** The name of the state this object targets */
|
|
60
|
+
name() {
|
|
61
|
+
return (this._definition && this._definition.name) || this._identifier;
|
|
62
|
+
}
|
|
63
|
+
/** The identifier used when creating this TargetState */
|
|
64
|
+
identifier() {
|
|
65
|
+
return this._identifier;
|
|
66
|
+
}
|
|
67
|
+
/** The target parameter values */
|
|
68
|
+
params() {
|
|
69
|
+
return this._params;
|
|
70
|
+
}
|
|
71
|
+
/** The internal state object (if it was found) */
|
|
72
|
+
$state() {
|
|
73
|
+
return this._definition;
|
|
74
|
+
}
|
|
75
|
+
/** The internal state declaration (if it was found) */
|
|
76
|
+
state() {
|
|
77
|
+
return this._definition && this._definition.self;
|
|
78
|
+
}
|
|
79
|
+
/** The target options */
|
|
80
|
+
options() {
|
|
81
|
+
return this._options;
|
|
82
|
+
}
|
|
83
|
+
/** True if the target state was found */
|
|
84
|
+
exists() {
|
|
85
|
+
return !!(this._definition && this._definition.self);
|
|
86
|
+
}
|
|
87
|
+
/** True if the object is valid */
|
|
88
|
+
valid() {
|
|
89
|
+
return !this.error();
|
|
90
|
+
}
|
|
91
|
+
/** If the object is invalid, returns the reason why */
|
|
92
|
+
error() {
|
|
93
|
+
const base = this.options().relative;
|
|
94
|
+
if (!this._definition && !!base) {
|
|
95
|
+
const stateName = base.name ? base.name : base;
|
|
96
|
+
return `Could not resolve '${this.name()}' from state '${stateName}'`;
|
|
97
|
+
}
|
|
98
|
+
if (!this._definition) return `No such state '${this.name()}'`;
|
|
99
|
+
if (!this._definition.self)
|
|
100
|
+
return `State '${this.name()}' has an invalid definition`;
|
|
101
|
+
}
|
|
102
|
+
toString() {
|
|
103
|
+
return `'${this.name()}'${stringify(this.params())}`;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Returns a copy of this TargetState which targets a different state.
|
|
107
|
+
* The new TargetState has the same parameter values and transition options.
|
|
108
|
+
*
|
|
109
|
+
* @param state The new state that should be targeted
|
|
110
|
+
*/
|
|
111
|
+
withState(state) {
|
|
112
|
+
return new TargetState(
|
|
113
|
+
this._stateRegistry,
|
|
114
|
+
state,
|
|
115
|
+
this._params,
|
|
116
|
+
this._options,
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Returns a copy of this TargetState, using the specified parameter values.
|
|
121
|
+
*
|
|
122
|
+
* @param params the new parameter values to use
|
|
123
|
+
* @param replace When false (default) the new parameter values will be merged with the current values.
|
|
124
|
+
* When true the parameter values will be used instead of the current values.
|
|
125
|
+
*/
|
|
126
|
+
withParams(params, replace = false) {
|
|
127
|
+
const newParams = replace ? params : extend({}, this._params, params);
|
|
128
|
+
return new TargetState(
|
|
129
|
+
this._stateRegistry,
|
|
130
|
+
this._identifier,
|
|
131
|
+
newParams,
|
|
132
|
+
this._options,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Returns a copy of this TargetState, using the specified Transition Options.
|
|
137
|
+
*
|
|
138
|
+
* @param options the new options to use
|
|
139
|
+
* @param replace When false (default) the new options will be merged with the current options.
|
|
140
|
+
* When true the options will be used instead of the current options.
|
|
141
|
+
*/
|
|
142
|
+
withOptions(options, replace = false) {
|
|
143
|
+
const newOpts = replace ? options : extend({}, this._options, options);
|
|
144
|
+
return new TargetState(
|
|
145
|
+
this._stateRegistry,
|
|
146
|
+
this._identifier,
|
|
147
|
+
this._params,
|
|
148
|
+
newOpts,
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/** Returns true if the object has a state property that might be a state or state name */
|
|
153
|
+
TargetState.isDef = (obj) => {
|
|
154
|
+
return (
|
|
155
|
+
obj &&
|
|
156
|
+
obj.state &&
|
|
157
|
+
(isString(obj.state) || (isObject(obj.state) && isString(obj.state.name)))
|
|
158
|
+
);
|
|
159
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { extend, assertPredicate, unnestR, identity } from "../common/common";
|
|
2
|
+
import { isArray } from "../common/predicates";
|
|
3
|
+
import { TransitionHookPhase, TransitionHookScope } from "./interface";
|
|
4
|
+
import { TransitionHook } from "./transitionHook";
|
|
5
|
+
/**
|
|
6
|
+
* This class returns applicable TransitionHooks for a specific Transition instance.
|
|
7
|
+
*
|
|
8
|
+
* Hooks ([[RegisteredHook]]) may be registered globally, e.g., $transitions.onEnter(...), or locally, e.g.
|
|
9
|
+
* myTransition.onEnter(...). The HookBuilder finds matching RegisteredHooks (where the match criteria is
|
|
10
|
+
* determined by the type of hook)
|
|
11
|
+
*
|
|
12
|
+
* The HookBuilder also converts RegisteredHooks objects to TransitionHook objects, which are used to run a Transition.
|
|
13
|
+
*
|
|
14
|
+
* The HookBuilder constructor is given the $transitions service and a Transition instance. Thus, a HookBuilder
|
|
15
|
+
* instance may only be used for one specific Transition object. (side note: the _treeChanges accessor is private
|
|
16
|
+
* in the Transition class, so we must also provide the Transition's _treeChanges)
|
|
17
|
+
*/
|
|
18
|
+
export class HookBuilder {
|
|
19
|
+
constructor(transition) {
|
|
20
|
+
this.transition = transition;
|
|
21
|
+
}
|
|
22
|
+
buildHooksForPhase(phase) {
|
|
23
|
+
const $transitions = this.transition.router.transitionService;
|
|
24
|
+
return $transitions._pluginapi
|
|
25
|
+
._getEvents(phase)
|
|
26
|
+
.map((type) => this.buildHooks(type))
|
|
27
|
+
.reduce(unnestR, [])
|
|
28
|
+
.filter(identity);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Returns an array of newly built TransitionHook objects.
|
|
32
|
+
*
|
|
33
|
+
* - Finds all RegisteredHooks registered for the given `hookType` which matched the transition's [[TreeChanges]].
|
|
34
|
+
* - Finds [[PathNode]] (or `PathNode[]`) to use as the TransitionHook context(s)
|
|
35
|
+
* - For each of the [[PathNode]]s, creates a TransitionHook
|
|
36
|
+
*
|
|
37
|
+
* @param hookType the type of the hook registration function, e.g., 'onEnter', 'onFinish'.
|
|
38
|
+
*/
|
|
39
|
+
buildHooks(hookType) {
|
|
40
|
+
const transition = this.transition;
|
|
41
|
+
const treeChanges = transition.treeChanges();
|
|
42
|
+
// Find all the matching registered hooks for a given hook type
|
|
43
|
+
const matchingHooks = this.getMatchingHooks(
|
|
44
|
+
hookType,
|
|
45
|
+
treeChanges,
|
|
46
|
+
transition,
|
|
47
|
+
);
|
|
48
|
+
if (!matchingHooks) return [];
|
|
49
|
+
const baseHookOptions = {
|
|
50
|
+
transition: transition,
|
|
51
|
+
current: transition.options().current,
|
|
52
|
+
};
|
|
53
|
+
const makeTransitionHooks = (hook) => {
|
|
54
|
+
// Fetch the Nodes that caused this hook to match.
|
|
55
|
+
const matches = hook.matches(treeChanges, transition);
|
|
56
|
+
// Select the PathNode[] that will be used as TransitionHook context objects
|
|
57
|
+
const matchingNodes = matches[hookType.criteriaMatchPath.name];
|
|
58
|
+
// Return an array of HookTuples
|
|
59
|
+
return matchingNodes.map((node) => {
|
|
60
|
+
const _options = extend(
|
|
61
|
+
{
|
|
62
|
+
bind: hook.bind,
|
|
63
|
+
traceData: { hookType: hookType.name, context: node },
|
|
64
|
+
},
|
|
65
|
+
baseHookOptions,
|
|
66
|
+
);
|
|
67
|
+
const state =
|
|
68
|
+
hookType.criteriaMatchPath.scope === TransitionHookScope.STATE
|
|
69
|
+
? node.state.self
|
|
70
|
+
: null;
|
|
71
|
+
const transitionHook = new TransitionHook(
|
|
72
|
+
transition,
|
|
73
|
+
state,
|
|
74
|
+
hook,
|
|
75
|
+
_options,
|
|
76
|
+
);
|
|
77
|
+
return { hook, node, transitionHook };
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
return matchingHooks
|
|
81
|
+
.map(makeTransitionHooks)
|
|
82
|
+
.reduce(unnestR, [])
|
|
83
|
+
.sort(tupleSort(hookType.reverseSort))
|
|
84
|
+
.map((tuple) => tuple.transitionHook);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Finds all RegisteredHooks from:
|
|
88
|
+
* - The Transition object instance hook registry
|
|
89
|
+
* - The TransitionService ($transitions) global hook registry
|
|
90
|
+
*
|
|
91
|
+
* which matched:
|
|
92
|
+
* - the eventType
|
|
93
|
+
* - the matchCriteria (to, from, exiting, retained, entering)
|
|
94
|
+
*
|
|
95
|
+
* @returns an array of matched [[RegisteredHook]]s
|
|
96
|
+
*/
|
|
97
|
+
getMatchingHooks(hookType, treeChanges, transition) {
|
|
98
|
+
const isCreate = hookType.hookPhase === TransitionHookPhase.CREATE;
|
|
99
|
+
// Instance and Global hook registries
|
|
100
|
+
const $transitions = this.transition.router.transitionService;
|
|
101
|
+
const registries = isCreate
|
|
102
|
+
? [$transitions]
|
|
103
|
+
: [this.transition, $transitions];
|
|
104
|
+
return registries
|
|
105
|
+
.map((reg) => reg.getHooks(hookType.name)) // Get named hooks from registries
|
|
106
|
+
.filter(assertPredicate(isArray, `broken event named: ${hookType.name}`)) // Sanity check
|
|
107
|
+
.reduce(unnestR, []) // Un-nest RegisteredHook[][] to RegisteredHook[] array
|
|
108
|
+
.filter((hook) => hook.matches(treeChanges, transition)); // Only those satisfying matchCriteria
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* A factory for a sort function for HookTuples.
|
|
113
|
+
*
|
|
114
|
+
* The sort function first compares the PathNode depth (how deep in the state tree a node is), then compares
|
|
115
|
+
* the EventHook priority.
|
|
116
|
+
*
|
|
117
|
+
* @param reverseDepthSort a boolean, when true, reverses the sort order for the node depth
|
|
118
|
+
* @returns a tuple sort function
|
|
119
|
+
*/
|
|
120
|
+
function tupleSort(reverseDepthSort = false) {
|
|
121
|
+
return function nodeDepthThenPriority(l, r) {
|
|
122
|
+
const factor = reverseDepthSort ? -1 : 1;
|
|
123
|
+
const depthDelta =
|
|
124
|
+
(l.node.state.path.length - r.node.state.path.length) * factor;
|
|
125
|
+
return depthDelta !== 0 ? depthDelta : r.hook.priority - l.hook.priority;
|
|
126
|
+
};
|
|
127
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { extend, removeFrom, tail, identity, mapObj } from "../common/common";
|
|
2
|
+
import { isString, isFunction } from "../common/predicates";
|
|
3
|
+
import { Glob } from "../common/glob";
|
|
4
|
+
import {
|
|
5
|
+
// has or is using
|
|
6
|
+
TransitionHookScope,
|
|
7
|
+
} from "./interface";
|
|
8
|
+
/**
|
|
9
|
+
* Determines if the given state matches the matchCriteria
|
|
10
|
+
*
|
|
11
|
+
* @internal
|
|
12
|
+
*
|
|
13
|
+
* @param state a State Object to test against
|
|
14
|
+
* @param criterion
|
|
15
|
+
* - If a string, matchState uses the string as a glob-matcher against the state name
|
|
16
|
+
* - If an array (of strings), matchState uses each string in the array as a glob-matchers against the state name
|
|
17
|
+
* and returns a positive match if any of the globs match.
|
|
18
|
+
* - If a function, matchState calls the function with the state and returns true if the function's result is truthy.
|
|
19
|
+
* @returns {boolean}
|
|
20
|
+
*/
|
|
21
|
+
export function matchState(state, criterion, transition) {
|
|
22
|
+
const toMatch = isString(criterion) ? [criterion] : criterion;
|
|
23
|
+
function matchGlobs(_state) {
|
|
24
|
+
const globStrings = toMatch;
|
|
25
|
+
for (let i = 0; i < globStrings.length; i++) {
|
|
26
|
+
const glob = new Glob(globStrings[i]);
|
|
27
|
+
if (
|
|
28
|
+
(glob && glob.matches(_state.name)) ||
|
|
29
|
+
(!glob && globStrings[i] === _state.name)
|
|
30
|
+
) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
const matchFn = isFunction(toMatch) ? toMatch : matchGlobs;
|
|
37
|
+
return !!matchFn(state, transition);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The registration data for a registered transition hook
|
|
41
|
+
*/
|
|
42
|
+
export class RegisteredHook {
|
|
43
|
+
constructor(
|
|
44
|
+
tranSvc,
|
|
45
|
+
eventType,
|
|
46
|
+
callback,
|
|
47
|
+
matchCriteria,
|
|
48
|
+
removeHookFromRegistry,
|
|
49
|
+
options = {},
|
|
50
|
+
) {
|
|
51
|
+
this.tranSvc = tranSvc;
|
|
52
|
+
this.eventType = eventType;
|
|
53
|
+
this.callback = callback;
|
|
54
|
+
this.matchCriteria = matchCriteria;
|
|
55
|
+
this.removeHookFromRegistry = removeHookFromRegistry;
|
|
56
|
+
this.invokeCount = 0;
|
|
57
|
+
this._deregistered = false;
|
|
58
|
+
this.priority = options.priority || 0;
|
|
59
|
+
this.bind = options.bind || null;
|
|
60
|
+
this.invokeLimit = options.invokeLimit;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Gets the matching [[PathNode]]s
|
|
64
|
+
*
|
|
65
|
+
* Given an array of [[PathNode]]s, and a [[HookMatchCriterion]], returns an array containing
|
|
66
|
+
* the [[PathNode]]s that the criteria matches, or `null` if there were no matching nodes.
|
|
67
|
+
*
|
|
68
|
+
* Returning `null` is significant to distinguish between the default
|
|
69
|
+
* "match-all criterion value" of `true` compared to a `() => true` function,
|
|
70
|
+
* when the nodes is an empty array.
|
|
71
|
+
*
|
|
72
|
+
* This is useful to allow a transition match criteria of `entering: true`
|
|
73
|
+
* to still match a transition, even when `entering === []`. Contrast that
|
|
74
|
+
* with `entering: (state) => true` which only matches when a state is actually
|
|
75
|
+
* being entered.
|
|
76
|
+
*/
|
|
77
|
+
_matchingNodes(nodes, criterion, transition) {
|
|
78
|
+
if (criterion === true) return nodes;
|
|
79
|
+
const matching = nodes.filter((node) =>
|
|
80
|
+
matchState(node.state, criterion, transition),
|
|
81
|
+
);
|
|
82
|
+
return matching.length ? matching : null;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Gets the default match criteria (all `true`)
|
|
86
|
+
*
|
|
87
|
+
* Returns an object which has all the criteria match paths as keys and `true` as values, i.e.:
|
|
88
|
+
*
|
|
89
|
+
* ```js
|
|
90
|
+
* {
|
|
91
|
+
* to: true,
|
|
92
|
+
* from: true,
|
|
93
|
+
* entering: true,
|
|
94
|
+
* exiting: true,
|
|
95
|
+
* retained: true,
|
|
96
|
+
* }
|
|
97
|
+
*/
|
|
98
|
+
_getDefaultMatchCriteria() {
|
|
99
|
+
return mapObj(this.tranSvc._pluginapi._getPathTypes(), () => true);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Gets matching nodes as [[IMatchingNodes]]
|
|
103
|
+
*
|
|
104
|
+
* Create a IMatchingNodes object from the TransitionHookTypes that is roughly equivalent to:
|
|
105
|
+
*
|
|
106
|
+
* ```js
|
|
107
|
+
* let matches: IMatchingNodes = {
|
|
108
|
+
* to: _matchingNodes([tail(treeChanges.to)], mc.to),
|
|
109
|
+
* from: _matchingNodes([tail(treeChanges.from)], mc.from),
|
|
110
|
+
* exiting: _matchingNodes(treeChanges.exiting, mc.exiting),
|
|
111
|
+
* retained: _matchingNodes(treeChanges.retained, mc.retained),
|
|
112
|
+
* entering: _matchingNodes(treeChanges.entering, mc.entering),
|
|
113
|
+
* };
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
_getMatchingNodes(treeChanges, transition) {
|
|
117
|
+
const criteria = extend(
|
|
118
|
+
this._getDefaultMatchCriteria(),
|
|
119
|
+
this.matchCriteria,
|
|
120
|
+
);
|
|
121
|
+
const paths = Object.values(this.tranSvc._pluginapi._getPathTypes());
|
|
122
|
+
return paths.reduce((mn, pathtype) => {
|
|
123
|
+
// STATE scope criteria matches against every node in the path.
|
|
124
|
+
// TRANSITION scope criteria matches against only the last node in the path
|
|
125
|
+
const isStateHook = pathtype.scope === TransitionHookScope.STATE;
|
|
126
|
+
const path = treeChanges[pathtype.name] || [];
|
|
127
|
+
const nodes = isStateHook ? path : [tail(path)];
|
|
128
|
+
mn[pathtype.name] = this._matchingNodes(
|
|
129
|
+
nodes,
|
|
130
|
+
criteria[pathtype.name],
|
|
131
|
+
transition,
|
|
132
|
+
);
|
|
133
|
+
return mn;
|
|
134
|
+
}, {});
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Determines if this hook's [[matchCriteria]] match the given [[TreeChanges]]
|
|
138
|
+
*
|
|
139
|
+
* @returns an IMatchingNodes object, or null. If an IMatchingNodes object is returned, its values
|
|
140
|
+
* are the matching [[PathNode]]s for each [[HookMatchCriterion]] (to, from, exiting, retained, entering)
|
|
141
|
+
*/
|
|
142
|
+
matches(treeChanges, transition) {
|
|
143
|
+
const matches = this._getMatchingNodes(treeChanges, transition);
|
|
144
|
+
// Check if all the criteria matched the TreeChanges object
|
|
145
|
+
const allMatched = Object.values(matches).every(identity);
|
|
146
|
+
return allMatched ? matches : null;
|
|
147
|
+
}
|
|
148
|
+
deregister() {
|
|
149
|
+
this.removeHookFromRegistry(this);
|
|
150
|
+
this._deregistered = true;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/** Return a registration function of the requested type. */
|
|
154
|
+
export function makeEvent(registry, transitionService, eventType) {
|
|
155
|
+
// Create the object which holds the registered transition hooks.
|
|
156
|
+
const _registeredHooks = (registry._registeredHooks =
|
|
157
|
+
registry._registeredHooks || {});
|
|
158
|
+
const hooks = (_registeredHooks[eventType.name] = []);
|
|
159
|
+
const removeHookFn = removeFrom(hooks);
|
|
160
|
+
// Create hook registration function on the IHookRegistry for the event
|
|
161
|
+
registry[eventType.name] = hookRegistrationFn;
|
|
162
|
+
function hookRegistrationFn(matchObject, callback, options = {}) {
|
|
163
|
+
const registeredHook = new RegisteredHook(
|
|
164
|
+
transitionService,
|
|
165
|
+
eventType,
|
|
166
|
+
callback,
|
|
167
|
+
matchObject,
|
|
168
|
+
removeHookFn,
|
|
169
|
+
options,
|
|
170
|
+
);
|
|
171
|
+
hooks.push(registeredHook);
|
|
172
|
+
return registeredHook.deregister.bind(registeredHook);
|
|
173
|
+
}
|
|
174
|
+
return hookRegistrationFn;
|
|
175
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
var TransitionHookPhase;
|
|
2
|
+
(function (TransitionHookPhase) {
|
|
3
|
+
TransitionHookPhase[(TransitionHookPhase["CREATE"] = 0)] = "CREATE";
|
|
4
|
+
TransitionHookPhase[(TransitionHookPhase["BEFORE"] = 1)] = "BEFORE";
|
|
5
|
+
TransitionHookPhase[(TransitionHookPhase["RUN"] = 2)] = "RUN";
|
|
6
|
+
TransitionHookPhase[(TransitionHookPhase["SUCCESS"] = 3)] = "SUCCESS";
|
|
7
|
+
TransitionHookPhase[(TransitionHookPhase["ERROR"] = 4)] = "ERROR";
|
|
8
|
+
})(TransitionHookPhase || (TransitionHookPhase = {}));
|
|
9
|
+
var TransitionHookScope;
|
|
10
|
+
(function (TransitionHookScope) {
|
|
11
|
+
TransitionHookScope[(TransitionHookScope["TRANSITION"] = 0)] = "TRANSITION";
|
|
12
|
+
TransitionHookScope[(TransitionHookScope["STATE"] = 1)] = "STATE";
|
|
13
|
+
})(TransitionHookScope || (TransitionHookScope = {}));
|
|
14
|
+
export { TransitionHookPhase, TransitionHookScope };
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
import { extend, silentRejection } from "../common/common";
|
|
3
|
+
import { stringify } from "../common/strings";
|
|
4
|
+
import { is } from "../common/hof";
|
|
5
|
+
/** An enum for Transition Rejection reasons */
|
|
6
|
+
var RejectType;
|
|
7
|
+
(function (RejectType) {
|
|
8
|
+
/**
|
|
9
|
+
* A new transition superseded this one.
|
|
10
|
+
*
|
|
11
|
+
* While this transition was running, a new transition started.
|
|
12
|
+
* This transition is cancelled because it was superseded by new transition.
|
|
13
|
+
*/
|
|
14
|
+
RejectType[(RejectType["SUPERSEDED"] = 2)] = "SUPERSEDED";
|
|
15
|
+
/**
|
|
16
|
+
* The transition was aborted
|
|
17
|
+
*
|
|
18
|
+
* The transition was aborted by a hook which returned `false`
|
|
19
|
+
*/
|
|
20
|
+
RejectType[(RejectType["ABORTED"] = 3)] = "ABORTED";
|
|
21
|
+
/**
|
|
22
|
+
* The transition was invalid
|
|
23
|
+
*
|
|
24
|
+
* The transition was never started because it was invalid
|
|
25
|
+
*/
|
|
26
|
+
RejectType[(RejectType["INVALID"] = 4)] = "INVALID";
|
|
27
|
+
/**
|
|
28
|
+
* The transition was ignored
|
|
29
|
+
*
|
|
30
|
+
* The transition was ignored because it would have no effect.
|
|
31
|
+
*
|
|
32
|
+
* Either:
|
|
33
|
+
*
|
|
34
|
+
* - The transition is targeting the current state and parameter values
|
|
35
|
+
* - The transition is targeting the same state and parameter values as the currently running transition.
|
|
36
|
+
*/
|
|
37
|
+
RejectType[(RejectType["IGNORED"] = 5)] = "IGNORED";
|
|
38
|
+
/**
|
|
39
|
+
* The transition errored.
|
|
40
|
+
*
|
|
41
|
+
* This generally means a hook threw an error or returned a rejected promise
|
|
42
|
+
*/
|
|
43
|
+
RejectType[(RejectType["ERROR"] = 6)] = "ERROR";
|
|
44
|
+
})(RejectType || (RejectType = {}));
|
|
45
|
+
export { RejectType };
|
|
46
|
+
/** @internal */
|
|
47
|
+
let id = 0;
|
|
48
|
+
export class Rejection {
|
|
49
|
+
/** Returns true if the obj is a rejected promise created from the `asPromise` factory */
|
|
50
|
+
static isRejectionPromise(obj) {
|
|
51
|
+
return (
|
|
52
|
+
obj &&
|
|
53
|
+
typeof obj.then === "function" &&
|
|
54
|
+
is(Rejection)(obj._transitionRejection)
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
/** Returns a Rejection due to transition superseded */
|
|
58
|
+
static superseded(detail, options) {
|
|
59
|
+
const message =
|
|
60
|
+
"The transition has been superseded by a different transition";
|
|
61
|
+
const rejection = new Rejection(RejectType.SUPERSEDED, message, detail);
|
|
62
|
+
if (options && options.redirected) {
|
|
63
|
+
rejection.redirected = true;
|
|
64
|
+
}
|
|
65
|
+
return rejection;
|
|
66
|
+
}
|
|
67
|
+
/** Returns a Rejection due to redirected transition */
|
|
68
|
+
static redirected(detail) {
|
|
69
|
+
return Rejection.superseded(detail, { redirected: true });
|
|
70
|
+
}
|
|
71
|
+
/** Returns a Rejection due to invalid transition */
|
|
72
|
+
static invalid(detail) {
|
|
73
|
+
const message = "This transition is invalid";
|
|
74
|
+
return new Rejection(RejectType.INVALID, message, detail);
|
|
75
|
+
}
|
|
76
|
+
/** Returns a Rejection due to ignored transition */
|
|
77
|
+
static ignored(detail) {
|
|
78
|
+
const message = "The transition was ignored";
|
|
79
|
+
return new Rejection(RejectType.IGNORED, message, detail);
|
|
80
|
+
}
|
|
81
|
+
/** Returns a Rejection due to aborted transition */
|
|
82
|
+
static aborted(detail) {
|
|
83
|
+
const message = "The transition has been aborted";
|
|
84
|
+
return new Rejection(RejectType.ABORTED, message, detail);
|
|
85
|
+
}
|
|
86
|
+
/** Returns a Rejection due to aborted transition */
|
|
87
|
+
static errored(detail) {
|
|
88
|
+
const message = "The transition errored";
|
|
89
|
+
return new Rejection(RejectType.ERROR, message, detail);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Returns a Rejection
|
|
93
|
+
*
|
|
94
|
+
* Normalizes a value as a Rejection.
|
|
95
|
+
* If the value is already a Rejection, returns it.
|
|
96
|
+
* Otherwise, wraps and returns the value as a Rejection (Rejection type: ERROR).
|
|
97
|
+
*
|
|
98
|
+
* @returns `detail` if it is already a `Rejection`, else returns an ERROR Rejection.
|
|
99
|
+
*/
|
|
100
|
+
static normalize(detail) {
|
|
101
|
+
return is(Rejection)(detail) ? detail : Rejection.errored(detail);
|
|
102
|
+
}
|
|
103
|
+
constructor(type, message, detail) {
|
|
104
|
+
/** @internal */
|
|
105
|
+
this.$id = id++;
|
|
106
|
+
this.type = type;
|
|
107
|
+
this.message = message;
|
|
108
|
+
this.detail = detail;
|
|
109
|
+
}
|
|
110
|
+
toString() {
|
|
111
|
+
const detailString = (d) =>
|
|
112
|
+
d && d.toString !== Object.prototype.toString
|
|
113
|
+
? d.toString()
|
|
114
|
+
: stringify(d);
|
|
115
|
+
const detail = detailString(this.detail);
|
|
116
|
+
const { $id, type, message } = this;
|
|
117
|
+
return `Transition Rejection($id: ${$id} type: ${type}, message: ${message}, detail: ${detail})`;
|
|
118
|
+
}
|
|
119
|
+
toPromise() {
|
|
120
|
+
return extend(silentRejection(this), { _transitionRejection: this });
|
|
121
|
+
}
|
|
122
|
+
}
|