UNPKG

9.2 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.TransitionHook = void 0;
4var interface_1 = require("./interface");
5var common_1 = require("../common/common");
6var strings_1 = require("../common/strings");
7var predicates_1 = require("../common/predicates");
8var hof_1 = require("../common/hof");
9var trace_1 = require("../common/trace");
10var coreservices_1 = require("../common/coreservices");
11var rejectFactory_1 = require("./rejectFactory");
12var targetState_1 = require("../state/targetState");
13var defaultOptions = {
14 current: common_1.noop,
15 transition: null,
16 traceData: {},
17 bind: null,
18};
19var TransitionHook = /** @class */ (function () {
20 function TransitionHook(transition, stateContext, registeredHook, options) {
21 var _this = this;
22 this.transition = transition;
23 this.stateContext = stateContext;
24 this.registeredHook = registeredHook;
25 this.options = options;
26 this.isSuperseded = function () { return _this.type.hookPhase === interface_1.TransitionHookPhase.RUN && !_this.options.transition.isActive(); };
27 this.options = common_1.defaults(options, defaultOptions);
28 this.type = registeredHook.eventType;
29 }
30 /**
31 * Chains together an array of TransitionHooks.
32 *
33 * Given a list of [[TransitionHook]] objects, chains them together.
34 * Each hook is invoked after the previous one completes.
35 *
36 * #### Example:
37 * ```js
38 * var hooks: TransitionHook[] = getHooks();
39 * let promise: Promise<any> = TransitionHook.chain(hooks);
40 *
41 * promise.then(handleSuccess, handleError);
42 * ```
43 *
44 * @param hooks the list of hooks to chain together
45 * @param waitFor if provided, the chain is `.then()`'ed off this promise
46 * @returns a `Promise` for sequentially invoking the hooks (in order)
47 */
48 TransitionHook.chain = function (hooks, waitFor) {
49 // Chain the next hook off the previous
50 var createHookChainR = function (prev, nextHook) { return prev.then(function () { return nextHook.invokeHook(); }); };
51 return hooks.reduce(createHookChainR, waitFor || coreservices_1.services.$q.when());
52 };
53 /**
54 * Invokes all the provided TransitionHooks, in order.
55 * Each hook's return value is checked.
56 * If any hook returns a promise, then the rest of the hooks are chained off that promise, and the promise is returned.
57 * If no hook returns a promise, then all hooks are processed synchronously.
58 *
59 * @param hooks the list of TransitionHooks to invoke
60 * @param doneCallback a callback that is invoked after all the hooks have successfully completed
61 *
62 * @returns a promise for the async result, or the result of the callback
63 */
64 TransitionHook.invokeHooks = function (hooks, doneCallback) {
65 for (var idx = 0; idx < hooks.length; idx++) {
66 var hookResult = hooks[idx].invokeHook();
67 if (predicates_1.isPromise(hookResult)) {
68 var remainingHooks = hooks.slice(idx + 1);
69 return TransitionHook.chain(remainingHooks, hookResult).then(doneCallback);
70 }
71 }
72 return doneCallback();
73 };
74 /**
75 * Run all TransitionHooks, ignoring their return value.
76 */
77 TransitionHook.runAllHooks = function (hooks) {
78 hooks.forEach(function (hook) { return hook.invokeHook(); });
79 };
80 TransitionHook.prototype.logError = function (err) {
81 this.transition.router.stateService.defaultErrorHandler()(err);
82 };
83 TransitionHook.prototype.invokeHook = function () {
84 var _this = this;
85 var hook = this.registeredHook;
86 if (hook._deregistered)
87 return;
88 var notCurrent = this.getNotCurrentRejection();
89 if (notCurrent)
90 return notCurrent;
91 var options = this.options;
92 trace_1.trace.traceHookInvocation(this, this.transition, options);
93 var invokeCallback = function () { return hook.callback.call(options.bind, _this.transition, _this.stateContext); };
94 var normalizeErr = function (err) { return rejectFactory_1.Rejection.normalize(err).toPromise(); };
95 var handleError = function (err) { return hook.eventType.getErrorHandler(_this)(err); };
96 var handleResult = function (result) { return hook.eventType.getResultHandler(_this)(result); };
97 try {
98 var result = invokeCallback();
99 if (!this.type.synchronous && predicates_1.isPromise(result)) {
100 return result.catch(normalizeErr).then(handleResult, handleError);
101 }
102 else {
103 return handleResult(result);
104 }
105 }
106 catch (err) {
107 // If callback throws (synchronously)
108 return handleError(rejectFactory_1.Rejection.normalize(err));
109 }
110 finally {
111 if (hook.invokeLimit && ++hook.invokeCount >= hook.invokeLimit) {
112 hook.deregister();
113 }
114 }
115 };
116 /**
117 * This method handles the return value of a Transition Hook.
118 *
119 * A hook can return false (cancel), a TargetState (redirect),
120 * or a promise (which may later resolve to false or a redirect)
121 *
122 * This also handles "transition superseded" -- when a new transition
123 * was started while the hook was still running
124 */
125 TransitionHook.prototype.handleHookResult = function (result) {
126 var _this = this;
127 var notCurrent = this.getNotCurrentRejection();
128 if (notCurrent)
129 return notCurrent;
130 // Hook returned a promise
131 if (predicates_1.isPromise(result)) {
132 // Wait for the promise, then reprocess with the resulting value
133 return result.then(function (val) { return _this.handleHookResult(val); });
134 }
135 trace_1.trace.traceHookResult(result, this.transition, this.options);
136 // Hook returned false
137 if (result === false) {
138 // Abort this Transition
139 return rejectFactory_1.Rejection.aborted('Hook aborted transition').toPromise();
140 }
141 var isTargetState = hof_1.is(targetState_1.TargetState);
142 // hook returned a TargetState
143 if (isTargetState(result)) {
144 // Halt the current Transition and redirect (a new Transition) to the TargetState.
145 return rejectFactory_1.Rejection.redirected(result).toPromise();
146 }
147 };
148 /**
149 * Return a Rejection promise if the transition is no longer current due
150 * to a stopped router (disposed), or a new transition has started and superseded this one.
151 */
152 TransitionHook.prototype.getNotCurrentRejection = function () {
153 var router = this.transition.router;
154 // The router is stopped
155 if (router._disposed) {
156 return rejectFactory_1.Rejection.aborted("UIRouter instance #" + router.$id + " has been stopped (disposed)").toPromise();
157 }
158 if (this.transition._aborted) {
159 return rejectFactory_1.Rejection.aborted().toPromise();
160 }
161 // This transition is no longer current.
162 // Another transition started while this hook was still running.
163 if (this.isSuperseded()) {
164 // Abort this transition
165 return rejectFactory_1.Rejection.superseded(this.options.current()).toPromise();
166 }
167 };
168 TransitionHook.prototype.toString = function () {
169 var _a = this, options = _a.options, registeredHook = _a.registeredHook;
170 var event = hof_1.parse('traceData.hookType')(options) || 'internal', context = hof_1.parse('traceData.context.state.name')(options) || hof_1.parse('traceData.context')(options) || 'unknown', name = strings_1.fnToString(registeredHook.callback);
171 return event + " context: " + context + ", " + strings_1.maxLength(200, name);
172 };
173 /**
174 * These GetResultHandler(s) are used by [[invokeHook]] below
175 * Each HookType chooses a GetResultHandler (See: [[TransitionService._defineCoreEvents]])
176 */
177 TransitionHook.HANDLE_RESULT = function (hook) { return function (result) {
178 return hook.handleHookResult(result);
179 }; };
180 /**
181 * If the result is a promise rejection, log it.
182 * Otherwise, ignore the result.
183 */
184 TransitionHook.LOG_REJECTED_RESULT = function (hook) { return function (result) {
185 predicates_1.isPromise(result) && result.catch(function (err) { return hook.logError(rejectFactory_1.Rejection.normalize(err)); });
186 return undefined;
187 }; };
188 /**
189 * These GetErrorHandler(s) are used by [[invokeHook]] below
190 * Each HookType chooses a GetErrorHandler (See: [[TransitionService._defineCoreEvents]])
191 */
192 TransitionHook.LOG_ERROR = function (hook) { return function (error) { return hook.logError(error); }; };
193 TransitionHook.REJECT_ERROR = function (hook) { return function (error) { return common_1.silentRejection(error); }; };
194 TransitionHook.THROW_ERROR = function (hook) { return function (error) {
195 throw error;
196 }; };
197 return TransitionHook;
198}());
199exports.TransitionHook = TransitionHook;
200//# sourceMappingURL=transitionHook.js.map
\No newline at end of file