1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 | import { ng as angular } from '../angular';
|
12 | import { extend, forEach, tail, isString, isObject, isArray, parse, noop, unnestR, identity, uniqR, inArray, removeFrom, } from '@uirouter/core';
|
13 |
|
14 | function parseStateRef(ref) {
|
15 | var paramsOnly = ref.match(/^\s*({[^}]*})\s*$/);
|
16 | if (paramsOnly)
|
17 | ref = '(' + paramsOnly[1] + ')';
|
18 | var parsed = ref.replace(/\n/g, ' ').match(/^\s*([^(]*?)\s*(\((.*)\))?\s*$/);
|
19 | if (!parsed || parsed.length !== 4)
|
20 | throw new Error("Invalid state ref '" + ref + "'");
|
21 | return { state: parsed[1] || null, paramExpr: parsed[3] || null };
|
22 | }
|
23 |
|
24 | function stateContext(el) {
|
25 | var $uiView = el.parent().inheritedData('$uiView');
|
26 | var path = parse('$cfg.path')($uiView);
|
27 | return path ? tail(path).state.name : undefined;
|
28 | }
|
29 |
|
30 | function processedDef($state, $element, def) {
|
31 | var uiState = def.uiState || $state.current.name;
|
32 | var uiStateOpts = extend(defaultOpts($element, $state), def.uiStateOpts || {});
|
33 | var href = $state.href(uiState, def.uiStateParams, uiStateOpts);
|
34 | return { uiState: uiState, uiStateParams: def.uiStateParams, uiStateOpts: uiStateOpts, href: href };
|
35 | }
|
36 |
|
37 | function getTypeInfo(el) {
|
38 |
|
39 | var isSvg = Object.prototype.toString.call(el.prop('href')) === '[object SVGAnimatedString]';
|
40 | var isForm = el[0].nodeName === 'FORM';
|
41 | return {
|
42 | attr: isForm ? 'action' : isSvg ? 'xlink:href' : 'href',
|
43 | isAnchor: el.prop('tagName').toUpperCase() === 'A',
|
44 | clickable: !isForm,
|
45 | };
|
46 | }
|
47 |
|
48 | function clickHook(el, $state, $timeout, type, getDef) {
|
49 | return function (e) {
|
50 | var button = e.which || e.button, target = getDef();
|
51 | if (!(button > 1 || e.ctrlKey || e.metaKey || e.shiftKey || e.altKey || el.attr('target'))) {
|
52 |
|
53 | var transition_1 = $timeout(function () {
|
54 | if (!el.attr('disabled')) {
|
55 | $state.go(target.uiState, target.uiStateParams, target.uiStateOpts);
|
56 | }
|
57 | });
|
58 | e.preventDefault();
|
59 |
|
60 | var ignorePreventDefaultCount_1 = type.isAnchor && !target.href ? 1 : 0;
|
61 | e.preventDefault = function () {
|
62 | if (ignorePreventDefaultCount_1-- <= 0)
|
63 | $timeout.cancel(transition_1);
|
64 | };
|
65 | }
|
66 | };
|
67 | }
|
68 | /** @hidden */
|
69 | function defaultOpts(el, $state) {
|
70 | return {
|
71 | relative: stateContext(el) || $state.$current,
|
72 | inherit: true,
|
73 | source: 'sref',
|
74 | };
|
75 | }
|
76 | /** @hidden */
|
77 | function bindEvents(element, scope, hookFn, uiStateOpts) {
|
78 | var events;
|
79 | if (uiStateOpts) {
|
80 | events = uiStateOpts.events;
|
81 | }
|
82 | if (!isArray(events)) {
|
83 | events = ['click'];
|
84 | }
|
85 | var on = element.on ? 'on' : 'bind';
|
86 | for (var _i = 0, events_1 = events; _i < events_1.length; _i++) {
|
87 | var event_1 = events_1[_i];
|
88 | element[on](event_1, hookFn);
|
89 | }
|
90 | scope.$on('$destroy', function () {
|
91 | var off = element.off ? 'off' : 'unbind';
|
92 | for (var _i = 0, events_2 = events; _i < events_2.length; _i++) {
|
93 | var event_2 = events_2[_i];
|
94 | element[off](event_2, hookFn);
|
95 | }
|
96 | });
|
97 | }
|
98 | /**
|
99 | * `ui-sref`: A directive for linking to a state
|
100 | *
|
101 | * A directive which links to a state (and optionally, parameters).
|
102 | * When clicked, this directive activates the linked state with the supplied parameter values.
|
103 | *
|
104 | * ### Linked State
|
105 | * The attribute value of the `ui-sref` is the name of the state to link to.
|
106 | *
|
107 | * #### Example:
|
108 | * This will activate the `home` state when the link is clicked.
|
109 | * ```html
|
110 | * <a ui-sref="home">Home</a>
|
111 | * ```
|
112 | *
|
113 | * ### Relative Links
|
114 | * You can also use relative state paths within `ui-sref`, just like a relative path passed to `$state.go()` ([[StateService.go]]).
|
115 | * You just need to be aware that the path is relative to the state that *created* the link.
|
116 | * This allows a state to create a relative `ui-sref` which always targets the same destination.
|
117 | *
|
118 | * #### Example:
|
119 | * Both these links are relative to the parent state, even when a child state is currently active.
|
120 | * ```html
|
121 | * <a ui-sref=".child1">child 1 state</a>
|
122 | * <a ui-sref=".child2">child 2 state</a>
|
123 | * ```
|
124 | *
|
125 | * This link activates the parent state.
|
126 | * ```html
|
127 | * <a ui-sref="^">Return</a>
|
128 | * ```
|
129 | *
|
130 | * ### hrefs
|
131 | * If the linked state has a URL, the directive will automatically generate and
|
132 | * update the `href` attribute (using the [[StateService.href]] method).
|
133 | *
|
134 | * #### Example:
|
135 | * Assuming the `users` state has a url of `/users/`
|
136 | * ```html
|
137 | * <a ui-sref="users" href="/users/">Users</a>
|
138 | * ```
|
139 | *
|
140 | * ### Parameter Values
|
141 | * In addition to the state name, a `ui-sref` can include parameter values which are applied when activating the state.
|
142 | * Param values can be provided in the `ui-sref` value after the state name, enclosed by parentheses.
|
143 | * The content inside the parentheses is an expression, evaluated to the parameter values.
|
144 | *
|
145 | * #### Example:
|
146 | * This example renders a list of links to users.
|
147 | * The state's `userId` parameter value comes from each user's `user.id` property.
|
148 | * ```html
|
149 | * <li ng-repeat="user in users">
|
150 | * <a ui-sref="users.detail({ userId: user.id })">{{ user.displayName }}</a>
|
151 | * </li>
|
152 | * ```
|
153 | *
|
154 | * Note:
|
155 | * The parameter values expression is `$watch`ed for updates.
|
156 | *
|
157 | * ### Transition Options
|
158 | * You can specify [[TransitionOptions]] to pass to [[StateService.go]] by using the `ui-sref-opts` attribute.
|
159 | * Options are restricted to `location`, `inherit`, and `reload`.
|
160 | *
|
161 | * #### Example:
|
162 | * ```html
|
163 | * <a ui-sref="home" ui-sref-opts="{ reload: true }">Home</a>
|
164 | * ```
|
165 | *
|
166 | * ### Other DOM Events
|
167 | *
|
168 | * You can also customize which DOM events to respond to (instead of `click`) by
|
169 | * providing an `events` array in the `ui-sref-opts` attribute.
|
170 | *
|
171 | * #### Example:
|
172 | * ```html
|
173 | * <input type="text" ui-sref="contacts" ui-sref-opts="{ events: ['change', 'blur'] }">
|
174 | * ```
|
175 | *
|
176 | * ### Highlighting the active link
|
177 | * This directive can be used in conjunction with [[uiSrefActive]] to highlight the active link.
|
178 | *
|
179 | * ### Examples
|
180 | * If you have the following template:
|
181 | *
|
182 | * ```html
|
183 | * <a ui-sref="home">Home</a>
|
184 | * <a ui-sref="about">About</a>
|
185 | * <a ui-sref="{page: 2}">Next page</a>
|
186 | *
|
187 | * <ul>
|
188 | * <li ng-repeat="contact in contacts">
|
189 | * <a ui-sref="contacts.detail({ id: contact.id })">{{ contact.name }}</a>
|
190 | * </li>
|
191 | * </ul>
|
192 | * ```
|
193 | *
|
194 | * Then (assuming the current state is `contacts`) the rendered html including hrefs would be:
|
195 | *
|
196 | * ```html
|
197 | * <a href="#/home" ui-sref="home">Home</a>
|
198 | * <a href="#/about" ui-sref="about">About</a>
|
199 | * <a href="#/contacts?page=2" ui-sref="{page: 2}">Next page</a>
|
200 | *
|
201 | * <ul>
|
202 | * <li ng-repeat="contact in contacts">
|
203 | * <a href="#/contacts/1" ui-sref="contacts.detail({ id: contact.id })">Joe</a>
|
204 | * </li>
|
205 | * <li ng-repeat="contact in contacts">
|
206 | * <a href="#/contacts/2" ui-sref="contacts.detail({ id: contact.id })">Alice</a>
|
207 | * </li>
|
208 | * <li ng-repeat="contact in contacts">
|
209 | * <a href="#/contacts/3" ui-sref="contacts.detail({ id: contact.id })">Bob</a>
|
210 | * </li>
|
211 | * </ul>
|
212 | *
|
213 | * <a href="#/home" ui-sref="home" ui-sref-opts="{reload: true}">Home</a>
|
214 | * ```
|
215 | *
|
216 | * ### Notes
|
217 | *
|
218 | * - You can use `ui-sref` to change **only the parameter values** by omitting the state name and parentheses.
|
219 | * #### Example:
|
220 | * Sets the `lang` parameter to `en` and remains on the same state.
|
221 | *
|
222 | * ```html
|
223 | * <a ui-sref="{ lang: 'en' }">English</a>
|
224 | * ```
|
225 | *
|
226 | * - A middle-click, right-click, or ctrl-click is handled (natively) by the browser to open the href in a new window, for example.
|
227 | *
|
228 | * - Unlike the parameter values expression, the state name is not `$watch`ed (for performance reasons).
|
229 | * If you need to dynamically update the state being linked to, use the fully dynamic [[uiState]] directive.
|
230 | */
|
231 | var uiSrefDirective;
|
232 | uiSrefDirective = [
|
233 | '$uiRouter',
|
234 | '$timeout',
|
235 | function $StateRefDirective($uiRouter, $timeout) {
|
236 | var $state = $uiRouter.stateService;
|
237 | return {
|
238 | restrict: 'A',
|
239 | require: ['?^uiSrefActive', '?^uiSrefActiveEq'],
|
240 | link: function (scope, element, attrs, uiSrefActive) {
|
241 | var type = getTypeInfo(element);
|
242 | var active = uiSrefActive[1] || uiSrefActive[0];
|
243 | var unlinkInfoFn = null;
|
244 | var rawDef = {};
|
245 | var getDef = function () { return processedDef($state, element, rawDef); };
|
246 | var ref = parseStateRef(attrs.uiSref);
|
247 | rawDef.uiState = ref.state;
|
248 | rawDef.uiStateOpts = attrs.uiSrefOpts ? scope.$eval(attrs.uiSrefOpts) : {};
|
249 | function update() {
|
250 | var def = getDef();
|
251 | if (unlinkInfoFn)
|
252 | unlinkInfoFn();
|
253 | if (active)
|
254 | unlinkInfoFn = active.$$addStateInfo(def.uiState, def.uiStateParams);
|
255 | if (def.href != null)
|
256 | attrs.$set(type.attr, def.href);
|
257 | }
|
258 | if (ref.paramExpr) {
|
259 | scope.$watch(ref.paramExpr, function (val) {
|
260 | rawDef.uiStateParams = extend({}, val);
|
261 | update();
|
262 | }, true);
|
263 | rawDef.uiStateParams = extend({}, scope.$eval(ref.paramExpr));
|
264 | }
|
265 | update();
|
266 | scope.$on('$destroy', $uiRouter.stateRegistry.onStatesChanged(update));
|
267 | scope.$on('$destroy', $uiRouter.transitionService.onSuccess({}, update));
|
268 | if (!type.clickable)
|
269 | return;
|
270 | var hookFn = clickHook(element, $state, $timeout, type, getDef);
|
271 | bindEvents(element, scope, hookFn, rawDef.uiStateOpts);
|
272 | },
|
273 | };
|
274 | },
|
275 | ];
|
276 | /**
|
277 | * `ui-state`: A fully dynamic directive for linking to a state
|
278 | *
|
279 | * A directive which links to a state (and optionally, parameters).
|
280 | * When clicked, this directive activates the linked state with the supplied parameter values.
|
281 | *
|
282 | * **This directive is very similar to [[uiSref]], but it `$observe`s and `$watch`es/evaluates all its inputs.**
|
283 | *
|
284 | * A directive which links to a state (and optionally, parameters).
|
285 | * When clicked, this directive activates the linked state with the supplied parameter values.
|
286 | *
|
287 | * ### Linked State
|
288 | * The attribute value of `ui-state` is an expression which is `$watch`ed and evaluated as the state to link to.
|
289 | * **This is in contrast with `ui-sref`, which takes a state name as a string literal.**
|
290 | *
|
291 | * #### Example:
|
292 | * Create a list of links.
|
293 | * ```html
|
294 | * <li ng-repeat="link in navlinks">
|
295 | * <a ui-state="link.state">{{ link.displayName }}</a>
|
296 | * </li>
|
297 | * ```
|
298 | *
|
299 | * ### Relative Links
|
300 | * If the expression evaluates to a relative path, it is processed like [[uiSref]].
|
301 | * You just need to be aware that the path is relative to the state that *created* the link.
|
302 | * This allows a state to create relative `ui-state` which always targets the same destination.
|
303 | *
|
304 | * ### hrefs
|
305 | * If the linked state has a URL, the directive will automatically generate and
|
306 | * update the `href` attribute (using the [[StateService.href]] method).
|
307 | *
|
308 | * ### Parameter Values
|
309 | * In addition to the state name expression, a `ui-state` can include parameter values which are applied when activating the state.
|
310 | * Param values should be provided using the `ui-state-params` attribute.
|
311 | * The `ui-state-params` attribute value is `$watch`ed and evaluated as an expression.
|
312 | *
|
313 | * #### Example:
|
314 | * This example renders a list of links with param values.
|
315 | * The state's `userId` parameter value comes from each user's `user.id` property.
|
316 | * ```html
|
317 | * <li ng-repeat="link in navlinks">
|
318 | * <a ui-state="link.state" ui-state-params="link.params">{{ link.displayName }}</a>
|
319 | * </li>
|
320 | * ```
|
321 | *
|
322 | * ### Transition Options
|
323 | * You can specify [[TransitionOptions]] to pass to [[StateService.go]] by using the `ui-state-opts` attribute.
|
324 | * Options are restricted to `location`, `inherit`, and `reload`.
|
325 | * The value of the `ui-state-opts` is `$watch`ed and evaluated as an expression.
|
326 | *
|
327 | * #### Example:
|
328 | * ```html
|
329 | * <a ui-state="returnto.state" ui-state-opts="{ reload: true }">Home</a>
|
330 | * ```
|
331 | *
|
332 | * ### Other DOM Events
|
333 | *
|
334 | * You can also customize which DOM events to respond to (instead of `click`) by
|
335 | * providing an `events` array in the `ui-state-opts` attribute.
|
336 | *
|
337 | * #### Example:
|
338 | * ```html
|
339 | * <input type="text" ui-state="contacts" ui-state-opts="{ events: ['change', 'blur'] }">
|
340 | * ```
|
341 | *
|
342 | * ### Highlighting the active link
|
343 | * This directive can be used in conjunction with [[uiSrefActive]] to highlight the active link.
|
344 | *
|
345 | * ### Notes
|
346 | *
|
347 | * - You can use `ui-params` to change **only the parameter values** by omitting the state name and supplying only `ui-state-params`.
|
348 | * However, it might be simpler to use [[uiSref]] parameter-only links.
|
349 | *
|
350 | * #### Example:
|
351 | * Sets the `lang` parameter to `en` and remains on the same state.
|
352 | *
|
353 | * ```html
|
354 | * <a ui-state="" ui-state-params="{ lang: 'en' }">English</a>
|
355 | * ```
|
356 | *
|
357 | * - A middle-click, right-click, or ctrl-click is handled (natively) by the browser to open the href in a new window, for example.
|
358 | * ```
|
359 | */
|
360 | var uiStateDirective;
|
361 | uiStateDirective = [
|
362 | '$uiRouter',
|
363 | '$timeout',
|
364 | function $StateRefDynamicDirective($uiRouter, $timeout) {
|
365 | var $state = $uiRouter.stateService;
|
366 | return {
|
367 | restrict: 'A',
|
368 | require: ['?^uiSrefActive', '?^uiSrefActiveEq'],
|
369 | link: function (scope, element, attrs, uiSrefActive) {
|
370 | var type = getTypeInfo(element);
|
371 | var active = uiSrefActive[1] || uiSrefActive[0];
|
372 | var unlinkInfoFn = null;
|
373 | var hookFn;
|
374 | var rawDef = {};
|
375 | var getDef = function () { return processedDef($state, element, rawDef); };
|
376 | var inputAttrs = ['uiState', 'uiStateParams', 'uiStateOpts'];
|
377 | var watchDeregFns = inputAttrs.reduce(function (acc, attr) { return ((acc[attr] = noop), acc); }, {});
|
378 | function update() {
|
379 | var def = getDef();
|
380 | if (unlinkInfoFn)
|
381 | unlinkInfoFn();
|
382 | if (active)
|
383 | unlinkInfoFn = active.$$addStateInfo(def.uiState, def.uiStateParams);
|
384 | if (def.href != null)
|
385 | attrs.$set(type.attr, def.href);
|
386 | }
|
387 | inputAttrs.forEach(function (field) {
|
388 | rawDef[field] = attrs[field] ? scope.$eval(attrs[field]) : null;
|
389 | attrs.$observe(field, function (expr) {
|
390 | watchDeregFns[field]();
|
391 | watchDeregFns[field] = scope.$watch(expr, function (newval) {
|
392 | rawDef[field] = newval;
|
393 | update();
|
394 | }, true);
|
395 | });
|
396 | });
|
397 | update();
|
398 | scope.$on('$destroy', $uiRouter.stateRegistry.onStatesChanged(update));
|
399 | scope.$on('$destroy', $uiRouter.transitionService.onSuccess({}, update));
|
400 | if (!type.clickable)
|
401 | return;
|
402 | hookFn = clickHook(element, $state, $timeout, type, getDef);
|
403 | bindEvents(element, scope, hookFn, rawDef.uiStateOpts);
|
404 | },
|
405 | };
|
406 | },
|
407 | ];
|
408 | /**
|
409 | * `ui-sref-active` and `ui-sref-active-eq`: A directive that adds a CSS class when a `ui-sref` is active
|
410 | *
|
411 | * A directive working alongside [[uiSref]] and [[uiState]] to add classes to an element when the
|
412 | * related directive's state is active (and remove them when it is inactive).
|
413 | *
|
414 | * The primary use-case is to highlight the active link in navigation menus,
|
415 | * distinguishing it from the inactive menu items.
|
416 | *
|
417 | * ### Linking to a `ui-sref` or `ui-state`
|
418 | * `ui-sref-active` can live on the same element as `ui-sref`/`ui-state`, or it can be on a parent element.
|
419 | * If a `ui-sref-active` is a parent to more than one `ui-sref`/`ui-state`, it will apply the CSS class when **any of the links are active**.
|
420 | *
|
421 | * ### Matching
|
422 | *
|
423 | * The `ui-sref-active` directive applies the CSS class when the `ui-sref`/`ui-state`'s target state **or any child state is active**.
|
424 | * This is a "fuzzy match" which uses [[StateService.includes]].
|
425 | *
|
426 | * The `ui-sref-active-eq` directive applies the CSS class when the `ui-sref`/`ui-state`'s target state is directly active (not when child states are active).
|
427 | * This is an "exact match" which uses [[StateService.is]].
|
428 | *
|
429 | * ### Parameter values
|
430 | * If the `ui-sref`/`ui-state` includes parameter values, the current parameter values must match the link's values for the link to be highlighted.
|
431 | * This allows a list of links to the same state with different parameters to be rendered, and the correct one highlighted.
|
432 | *
|
433 | * #### Example:
|
434 | * ```html
|
435 | * <li ng-repeat="user in users" ui-sref-active="active">
|
436 | * <a ui-sref="user.details({ userId: user.id })">{{ user.lastName }}</a>
|
437 | * </li>
|
438 | * ```
|
439 | *
|
440 | * ### Examples
|
441 | *
|
442 | * Given the following template:
|
443 | * #### Example:
|
444 | * ```html
|
445 | * <ul>
|
446 | * <li ui-sref-active="active" class="item">
|
447 | * <a href ui-sref="app.user({user: 'bilbobaggins'})">@bilbobaggins</a>
|
448 | * </li>
|
449 | * </ul>
|
450 | * ```
|
451 | *
|
452 | * When the app state is `app.user` (or any child state),
|
453 | * and contains the state parameter "user" with value "bilbobaggins",
|
454 | * the resulting HTML will appear as (note the 'active' class):
|
455 | *
|
456 | * ```html
|
457 | * <ul>
|
458 | * <li ui-sref-active="active" class="item active">
|
459 | * <a ui-sref="app.user({user: 'bilbobaggins'})" href="/users/bilbobaggins">@bilbobaggins</a>
|
460 | * </li>
|
461 | * </ul>
|
462 | * ```
|
463 | *
|
464 | * ### Glob mode
|
465 | *
|
466 | * It is possible to pass `ui-sref-active` an expression that evaluates to an object.
|
467 | * The objects keys represent active class names and values represent the respective state names/globs.
|
468 | * `ui-sref-active` will match if the current active state **includes** any of
|
469 | * the specified state names/globs, even the abstract ones.
|
470 | *
|
471 | * #### Example:
|
472 | * Given the following template, with "admin" being an abstract state:
|
473 | * ```html
|
474 | * <div ui-sref-active="{'active': 'admin.**'}">
|
475 | * <a ui-sref-active="active" ui-sref="admin.roles">Roles</a>
|
476 | * </div>
|
477 | * ```
|
478 | *
|
479 | * Arrays are also supported as values in the `ngClass`-like interface.
|
480 | * This allows multiple states to add `active` class.
|
481 | *
|
482 | * #### Example:
|
483 | * Given the following template, with "admin.roles" being the current state, the class will be added too:
|
484 | * ```html
|
485 | * <div ui-sref-active="{'active': ['owner.**', 'admin.**']}">
|
486 | * <a ui-sref-active="active" ui-sref="admin.roles">Roles</a>
|
487 | * </div>
|
488 | * ```
|
489 | *
|
490 | * When the current state is "admin.roles" the "active" class will be applied to both the `<div>` and `<a>` elements.
|
491 | * It is important to note that the state names/globs passed to `ui-sref-active` override any state provided by a linked `ui-sref`.
|
492 | *
|
493 | * ### Notes:
|
494 | *
|
495 | * - The class name is interpolated **once** during the directives link time (any further changes to the
|
496 | * interpolated value are ignored).
|
497 | *
|
498 | * - Multiple classes may be specified in a space-separated format: `ui-sref-active='class1 class2 class3'`
|
499 | */
|
500 | var uiSrefActiveDirective;
|
501 | uiSrefActiveDirective = [
|
502 | '$state',
|
503 | '$stateParams',
|
504 | '$interpolate',
|
505 | '$uiRouter',
|
506 | function $StateRefActiveDirective($state, $stateParams, $interpolate, $uiRouter) {
|
507 | return {
|
508 | restrict: 'A',
|
509 | controller: [
|
510 | '$scope',
|
511 | '$element',
|
512 | '$attrs',
|
513 | function ($scope, $element, $attrs) {
|
514 | var states = [];
|
515 | var activeEqClass;
|
516 | var uiSrefActive;
|
517 | // There probably isn't much point in $observing this
|
518 | // uiSrefActive and uiSrefActiveEq share the same directive object with some
|
519 | // slight difference in logic routing
|
520 | activeEqClass = $interpolate($attrs.uiSrefActiveEq || '', false)($scope);
|
521 | try {
|
522 | uiSrefActive = $scope.$eval($attrs.uiSrefActive);
|
523 | }
|
524 | catch (e) {
|
525 | // Do nothing. uiSrefActive is not a valid expression.
|
526 | // Fall back to using $interpolate below
|
527 | }
|
528 | uiSrefActive = uiSrefActive || $interpolate($attrs.uiSrefActive || '', false)($scope);
|
529 | setStatesFromDefinitionObject(uiSrefActive);
|
530 | // Allow uiSref to communicate with uiSrefActive[Equals]
|
531 | this.$$addStateInfo = function (newState, newParams) {
|
532 | // we already got an explicit state provided by ui-sref-active, so we
|
533 | // shadow the one that comes from ui-sref
|
534 | if (isObject(uiSrefActive) && states.length > 0) {
|
535 | return;
|
536 | }
|
537 | var deregister = addState(newState, newParams, uiSrefActive);
|
538 | update();
|
539 | return deregister;
|
540 | };
|
541 | function updateAfterTransition(trans) {
|
542 | trans.promise.then(update, noop);
|
543 | }
|
544 | $scope.$on('$destroy', setupEventListeners());
|
545 | if ($uiRouter.globals.transition) {
|
546 | updateAfterTransition($uiRouter.globals.transition);
|
547 | }
|
548 | function setupEventListeners() {
|
549 | var deregisterStatesChangedListener = $uiRouter.stateRegistry.onStatesChanged(handleStatesChanged);
|
550 | var deregisterOnStartListener = $uiRouter.transitionService.onStart({}, updateAfterTransition);
|
551 | var deregisterStateChangeSuccessListener = $scope.$on('$stateChangeSuccess', update);
|
552 | return function cleanUp() {
|
553 | deregisterStatesChangedListener();
|
554 | deregisterOnStartListener();
|
555 | deregisterStateChangeSuccessListener();
|
556 | };
|
557 | }
|
558 | function handleStatesChanged() {
|
559 | setStatesFromDefinitionObject(uiSrefActive);
|
560 | }
|
561 | function setStatesFromDefinitionObject(statesDefinition) {
|
562 | if (isObject(statesDefinition)) {
|
563 | states = [];
|
564 | forEach(statesDefinition, function (stateOrName, activeClass) {
|
565 | // Helper function to abstract adding state.
|
566 | var addStateForClass = function (stateOrName, activeClass) {
|
567 | var ref = parseStateRef(stateOrName);
|
568 | addState(ref.state, $scope.$eval(ref.paramExpr), activeClass);
|
569 | };
|
570 | if (isString(stateOrName)) {
|
571 | // If state is string, just add it.
|
572 | addStateForClass(stateOrName, activeClass);
|
573 | }
|
574 | else if (isArray(stateOrName)) {
|
575 | // If state is an array, iterate over it and add each array item individually.
|
576 | forEach(stateOrName, function (stateOrName) {
|
577 | addStateForClass(stateOrName, activeClass);
|
578 | });
|
579 | }
|
580 | });
|
581 | }
|
582 | }
|
583 | function addState(stateName, stateParams, activeClass) {
|
584 | var state = $state.get(stateName, stateContext($element));
|
585 | var stateInfo = {
|
586 | state: state || { name: stateName },
|
587 | params: stateParams,
|
588 | activeClass: activeClass,
|
589 | };
|
590 | states.push(stateInfo);
|
591 | return function removeState() {
|
592 | removeFrom(states)(stateInfo);
|
593 | };
|
594 | }
|
595 | // Update route state
|
596 | function update() {
|
597 | var splitClasses = function (str) { return str.split(/\s/).filter(identity); };
|
598 | var getClasses = function (stateList) {
|
599 | return stateList
|
600 | .map(function (x) { return x.activeClass; })
|
601 | .map(splitClasses)
|
602 | .reduce(unnestR, []);
|
603 | };
|
604 | var allClasses = getClasses(states).concat(splitClasses(activeEqClass)).reduce(uniqR, []);
|
605 | var fuzzyClasses = getClasses(states.filter(function (x) { return $state.includes(x.state.name, x.params); }));
|
606 | var exactlyMatchesAny = !!states.filter(function (x) { return $state.is(x.state.name, x.params); }).length;
|
607 | var exactClasses = exactlyMatchesAny ? splitClasses(activeEqClass) : [];
|
608 | var addClasses = fuzzyClasses.concat(exactClasses).reduce(uniqR, []);
|
609 | var removeClasses = allClasses.filter(function (cls) { return !inArray(addClasses, cls); });
|
610 | $scope.$evalAsync(function () {
|
611 | addClasses.forEach(function (className) { return $element.addClass(className); });
|
612 | removeClasses.forEach(function (className) { return $element.removeClass(className); });
|
613 | });
|
614 | }
|
615 | update();
|
616 | },
|
617 | ],
|
618 | };
|
619 | },
|
620 | ];
|
621 | angular
|
622 | .module('ui.router.state')
|
623 | .directive('uiSref', uiSrefDirective)
|
624 | .directive('uiSrefActive', uiSrefActiveDirective)
|
625 | .directive('uiSrefActiveEq', uiSrefActiveDirective)
|
626 | .directive('uiState', uiStateDirective);
|
627 | //# sourceMappingURL=stateDirectives.js.map |
\ | No newline at end of file |