UNPKG

13.3 kBJavaScriptView Raw
1var __extends = (this && this.__extends) || (function () {
2 var extendStatics = function (d, b) {
3 extendStatics = Object.setPrototypeOf ||
4 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
5 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
6 return extendStatics(d, b);
7 };
8 return function (d, b) {
9 extendStatics(d, b);
10 function __() { this.constructor = d; }
11 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
12 };
13})();
14(function (factory) {
15 if (typeof module === "object" && typeof module.exports === "object") {
16 var v = factory(require, exports);
17 if (v !== undefined) module.exports = v;
18 }
19 else if (typeof define === "function" && define.amd) {
20 define(["require", "exports", "@uirouter/core"], factory);
21 }
22})(function (require, exports) {
23 "use strict";
24 Object.defineProperty(exports, "__esModule", { value: true });
25 var core_1 = require("@uirouter/core");
26 var isChildOf = function (parent) { return function (node) { return node.state.parent === parent.state; }; };
27 var isChildOfAny = function (_parents) {
28 return function (node) { return _parents.map(function (parent) { return isChildOf(parent)(node); }).reduce(core_1.anyTrueR, false); };
29 };
30 var ancestorPath = function (state) { return (state.parent ? ancestorPath(state.parent).concat(state) : [state]); };
31 var isDescendantOf = function (_ancestor) {
32 var ancestor = _ancestor.state;
33 return function (node) { return ancestorPath(node.state).indexOf(ancestor) !== -1; };
34 };
35 var isDescendantOfAny = function (ancestors) { return function (node) {
36 return ancestors.map(function (ancestor) { return isDescendantOf(ancestor)(node); }).reduce(core_1.anyTrueR, false);
37 }; };
38 /**
39 * Given a path, returns a function which takes a node.
40 * Given a node, finds a node in the path which has the same state.
41 */
42 var findInPath = function (path) { return function (node) { return path.find(function (pathNode) { return pathNode.state == node.state; }); }; };
43 var notFoundInPath = function (path) { return core_1.not(findInPath(path)); };
44 /** uirouter/core 5.x/6.x compatibility code */
45 var cloneNode = function (node) {
46 var n = node;
47 return (core_1.isFunction(n.clone) && n.clone()) || core_1.PathNode.clone(node);
48 };
49 var applyParamsFromPath = function (path, dest) {
50 var sourceNode = findInPath(path)(dest);
51 if (!sourceNode)
52 throw new Error("Could not find matching node for " + dest.state.name + " in source path [" + path
53 .map(function (node) { return node.state.name; })
54 .join(', ') + "]");
55 return core_1.extend(cloneNode(dest), { paramValues: sourceNode.paramValues });
56 };
57 /**
58 * Sorts fn that sorts by:
59 * 1) node depth (how deep a state is nested)
60 * 2) the order in which the state was inactivated (later in wins)
61 */
62 function nodeDepthThenInactivateOrder(inactives) {
63 return function (l, r) {
64 var depthDelta = l.state.path.length - r.state.path.length;
65 return depthDelta !== 0 ? depthDelta : inactives.indexOf(r) - inactives.indexOf(l);
66 };
67 }
68 /**
69 * The sticky-states plugin class
70 *
71 * router.plugin(StickyStatesPlugin);
72 */
73 var StickyStatesPlugin = /** @class */ (function (_super) {
74 __extends(StickyStatesPlugin, _super);
75 function StickyStatesPlugin(router) {
76 var _this = _super.call(this) || this;
77 _this.router = router;
78 _this.name = 'sticky-states';
79 _this._inactives = [];
80 _this.pluginAPI = router.transitionService._pluginapi;
81 _this._defineStickyPaths();
82 _this._defineStickyEvents();
83 _this._addCreateHook();
84 _this._addStateCallbacks();
85 _this._addDefaultTransitionOption();
86 return _this;
87 }
88 StickyStatesPlugin.prototype.inactives = function () {
89 return this._inactives.map(function (node) { return node.state.self; });
90 };
91 StickyStatesPlugin.prototype._addCreateHook = function () {
92 var _this = this;
93 this.router.transitionService.onCreate({}, function (trans) {
94 trans['_treeChanges'] = _this._calculateStickyTreeChanges(trans);
95 }, { priority: 100 });
96 };
97 StickyStatesPlugin.prototype._defineStickyPaths = function () {
98 // let paths = this.pluginAPI._getPathTypes();
99 this.pluginAPI._definePathType('inactivating', core_1.TransitionHookScope.STATE);
100 this.pluginAPI._definePathType('reactivating', core_1.TransitionHookScope.STATE);
101 };
102 StickyStatesPlugin.prototype._defineStickyEvents = function () {
103 var paths = this.pluginAPI._getPathTypes();
104 this.pluginAPI._defineEvent('onInactivate', core_1.TransitionHookPhase.RUN, 5, paths.inactivating, true);
105 this.pluginAPI._defineEvent('onReactivate', core_1.TransitionHookPhase.RUN, 35, paths.reactivating);
106 };
107 // Process state.onInactivate or state.onReactivate callbacks
108 StickyStatesPlugin.prototype._addStateCallbacks = function () {
109 var inactivateCriteria = { inactivating: function (state) { return !!state.onInactivate; } };
110 this.router.transitionService.onInactivate(inactivateCriteria, function (trans, state) {
111 return state.onInactivate(trans, state);
112 });
113 var reactivateCriteria = { reactivating: function (state) { return !!state.onReactivate; } };
114 this.router.transitionService.onReactivate(reactivateCriteria, function (trans, state) {
115 return state.onReactivate(trans, state);
116 });
117 };
118 StickyStatesPlugin.prototype._calculateExitSticky = function (tc, trans) {
119 // Process the inactive states that are going to exit due to $stickyState.reset()
120 var exitSticky = trans.options().exitSticky || [];
121 if (!core_1.isArray(exitSticky))
122 exitSticky = [exitSticky];
123 var $state = trans.router.stateService;
124 var states = exitSticky
125 .map(core_1.assertMap(function (stateOrName) { return $state.get(stateOrName); }, function (state) { return 'State not found: ' + state; }))
126 .map(function (state) { return state.$$state(); });
127 var potentialExitingStickies = this._inactives.concat(tc.inactivating).reduce(core_1.uniqR, []);
128 var findInactive = function (state) { return potentialExitingStickies.find(function (node) { return node.state === state; }); };
129 var notInactiveMsg = function (state) { return 'State not inactive: ' + state; };
130 var exitingInactives = states.map(core_1.assertMap(findInactive, notInactiveMsg));
131 var exiting = potentialExitingStickies.filter(isDescendantOfAny(exitingInactives));
132 var inToPathMsg = function (node) { return 'Can not exit a sticky state that is currently active/activating: ' + node.state.name; };
133 exiting.map(core_1.assertMap(function (node) { return !core_1.inArray(tc.to, node); }, inToPathMsg));
134 return exiting;
135 };
136 StickyStatesPlugin.prototype._calculateStickyTreeChanges = function (trans) {
137 var _this = this;
138 var inactives = this._inactives;
139 var tc = trans.treeChanges();
140 tc.inactivating = [];
141 tc.reactivating = [];
142 /****************
143 * Process states that are about to be inactivated
144 ****************/
145 if (tc.entering.length && tc.exiting[0] && tc.exiting[0].state.sticky) {
146 tc.inactivating = tc.exiting;
147 tc.exiting = [];
148 }
149 /****************
150 * Determine which states are about to be reactivated
151 ****************/
152 // Simulate a transition where the fromPath is a clone of the toPath, but use the inactivated nodes
153 // This will calculate which inactive nodes that need to be exited/entered due to param changes
154 var inactiveFromPath = tc.retained.concat(tc.entering.map(findInPath(inactives))).filter(core_1.identity);
155 var simulatedTC = core_1.PathUtils.treeChanges(inactiveFromPath, tc.to, trans.options().reloadState);
156 var shouldRewritePaths = ['retained', 'entering', 'exiting'].some(function (path) { return !!simulatedTC[path].length; });
157 if (shouldRewritePaths) {
158 // The 'retained' nodes from the simulated transition's TreeChanges are the ones that will be reactivated.
159 // (excluding the nodes that are in the original retained path)
160 var reactivating = simulatedTC.retained.slice(tc.retained.length);
161 // Apply the toParams to the reactivating states (to get dynamic param changes)
162 tc.reactivating = reactivating.map(function (node) { return applyParamsFromPath(tc.to, node); });
163 // Entering nodes are the same as the simulated transition's entering
164 tc.entering = simulatedTC.entering;
165 // The simulatedTC 'exiting' nodes are inactives that are being exited because:
166 // - The inactive state's params changed
167 // - The inactive state is being reloaded
168 // - The inactive state is a child of the to state
169 tc.exiting = tc.exiting.concat(simulatedTC.exiting);
170 // Rewrite the to path
171 var retainedWithToParams = tc.retained.map(function (node) { return applyParamsFromPath(tc.to, node); });
172 tc.to = retainedWithToParams.concat(tc.reactivating).concat(tc.entering);
173 }
174 /****************
175 * Determine which additional inactive states should be exited
176 ****************/
177 // Any inactive state whose parent state is exactly activated will be exited
178 var childrenOfToState = inactives.filter(isChildOf(core_1.tail(tc.to)));
179 // Any inactive non-sticky state whose parent state is activated (and is itself not activated) will be exited
180 var childrenOfToPath = inactives
181 .filter(isChildOfAny(tc.to))
182 .filter(notFoundInPath(tc.to))
183 .filter(function (node) { return !node.state.sticky; });
184 var exitingChildren = childrenOfToState.concat(childrenOfToPath).filter(notFoundInPath(tc.exiting));
185 var exitingRoots = tc.exiting.concat(exitingChildren);
186 // Any inactive descendant of an exiting state will be exited
187 var orphans = inactives
188 .filter(isDescendantOfAny(exitingRoots))
189 .filter(notFoundInPath(exitingRoots))
190 .concat(exitingChildren)
191 .reduce(core_1.uniqR, [])
192 .sort(nodeDepthThenInactivateOrder(inactives));
193 tc.exiting = orphans.concat(tc.exiting);
194 // commit all changes to inactives once transition is complete and successful
195 trans.onSuccess({}, function () {
196 tc.exiting.map(findInPath(inactives)).forEach(core_1.removeFrom(inactives));
197 tc.entering.map(findInPath(inactives)).forEach(core_1.removeFrom(inactives));
198 tc.reactivating.map(findInPath(inactives)).forEach(core_1.removeFrom(inactives));
199 tc.inactivating.forEach(core_1.pushTo(_this._inactives));
200 });
201 // console.log('inactives will be:', inactives.map(x => x.state.name));
202 // let tcCopy: any = Object.assign({}, tc);
203 // Object.keys(tcCopy).forEach(key => tcCopy[key] = tcCopy[key].map(x => x.state.name));
204 // console.table(tcCopy);
205 // Process the inactive sticky states that should be exited
206 var exitSticky = this._calculateExitSticky(tc, trans);
207 exitSticky.filter(function (node) { return !findInPath(tc.exiting)(node); }).forEach(core_1.pushTo(tc.exiting));
208 // Also process the active sticky states that are about to be inactivated, but should be exited
209 exitSticky.filter(findInPath(tc.inactivating)).forEach(core_1.removeFrom(tc.inactivating));
210 return tc;
211 };
212 StickyStatesPlugin.prototype._addDefaultTransitionOption = function () {
213 core_1.defaultTransOpts.exitSticky = [];
214 };
215 StickyStatesPlugin.prototype.exitSticky = function (states) {
216 var $state = this.router.stateService;
217 if (states === undefined)
218 states = this._inactives.map(function (node) { return node.state.name; });
219 if (core_1.isString(states))
220 states = [states];
221 return $state.go($state.current, {}, {
222 inherit: true,
223 exitSticky: states,
224 });
225 };
226 return StickyStatesPlugin;
227 }(core_1.UIRouterPluginBase));
228 exports.StickyStatesPlugin = StickyStatesPlugin;
229});
230//# sourceMappingURL=stickyStates.js.map
\No newline at end of file