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