@angular-wave/angular.ts 0.0.21 → 0.0.23

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.
Files changed (134) hide show
  1. package/Makefile +1 -1
  2. package/TODO.md +14 -0
  3. package/dist/angular-ts.esm.js +1 -1
  4. package/dist/angular-ts.umd.js +1 -1
  5. package/index.html +8 -2
  6. package/package.json +1 -1
  7. package/src/animations/animate-css-driver.js +2 -2
  8. package/src/animations/animate-css.js +15 -6
  9. package/src/animations/animate-js.js +1 -1
  10. package/src/animations/animate-queue.js +1 -1
  11. package/src/animations/shared.js +0 -14
  12. package/src/core/compile.js +6 -3
  13. package/src/directive/if.js +0 -79
  14. package/src/directive/if.md +80 -0
  15. package/src/directive/include.js +0 -82
  16. package/src/directive/include.md +86 -0
  17. package/src/directive/repeat.js +0 -1
  18. package/src/filters/order-by.js +8 -8
  19. package/src/loader.js +0 -1
  20. package/src/router/common/trace.js +1 -1
  21. package/src/router/directives/stateDirectives.js +16 -14
  22. package/src/router/directives/viewDirective.js +5 -13
  23. package/src/router/hooks/resolve.js +3 -4
  24. package/src/router/hooks/views.js +3 -2
  25. package/src/router/state/stateService.js +1 -2
  26. package/src/router/stateProvider.js +8 -0
  27. package/src/router/templateFactory.js +13 -7
  28. package/src/router/transition/interface.js +14 -14
  29. package/src/router/transition/rejectFactory.js +29 -20
  30. package/src/router/transition/transition.js +5 -1
  31. package/src/router/transition/transitionHook.js +5 -5
  32. package/src/router/url/urlMatcher.js +1 -2
  33. package/src/router/url/urlRule.js +10 -2
  34. package/src/router/url/urlRules.js +1 -1
  35. package/src/services/browser.js +3 -18
  36. package/src/shared/common.js +0 -1
  37. package/test/module-test.html +44 -12
  38. package/test/router/ng-state-builder.spec.js +81 -0
  39. package/test/router/services.spec.js +70 -0
  40. package/test/router/state-directives.spec.js +1182 -0
  41. package/test/router/template-factory.spec.js +146 -0
  42. package/test/router/url-matcher-factory.spec.js +1313 -0
  43. package/test/router/view-directive.spec.js +2013 -0
  44. package/test/router/view-hook.spec.js +217 -0
  45. package/test/router/view-scroll.spec.js +77 -0
  46. package/test/router/view.spec.js +117 -0
  47. package/types/angular.d.ts +132 -124
  48. package/types/index.d.ts +2350 -2187
  49. package/types/jqlite.d.ts +463 -418
  50. package/types/router/core/common/common.d.ts +70 -24
  51. package/types/router/core/common/coreservices.d.ts +30 -32
  52. package/types/router/core/common/glob.d.ts +9 -9
  53. package/types/router/core/common/hof.d.ts +12 -4
  54. package/types/router/core/common/index.d.ts +8 -8
  55. package/types/router/core/common/predicates.d.ts +1 -1
  56. package/types/router/core/common/queue.d.ts +13 -13
  57. package/types/router/core/common/safeConsole.d.ts +3 -3
  58. package/types/router/core/common/strings.d.ts +4 -2
  59. package/types/router/core/common/trace.d.ts +94 -82
  60. package/types/router/core/globals.d.ts +37 -37
  61. package/types/router/core/hooks/coreResolvables.d.ts +5 -3
  62. package/types/router/core/hooks/ignoredTransition.d.ts +4 -2
  63. package/types/router/core/hooks/invalidTransition.d.ts +4 -2
  64. package/types/router/core/hooks/lazyLoad.d.ts +10 -5
  65. package/types/router/core/hooks/onEnterExitRetain.d.ts +10 -4
  66. package/types/router/core/hooks/redirectTo.d.ts +4 -2
  67. package/types/router/core/hooks/resolve.d.ts +10 -4
  68. package/types/router/core/hooks/updateGlobals.d.ts +4 -2
  69. package/types/router/core/hooks/url.d.ts +4 -2
  70. package/types/router/core/hooks/views.d.ts +7 -3
  71. package/types/router/core/index.d.ts +11 -12
  72. package/types/router/core/interface.d.ts +83 -81
  73. package/types/router/core/params/index.d.ts +5 -5
  74. package/types/router/core/params/interface.d.ts +439 -439
  75. package/types/router/core/params/param.d.ts +72 -60
  76. package/types/router/core/params/paramType.d.ts +40 -40
  77. package/types/router/core/params/paramTypes.d.ts +169 -165
  78. package/types/router/core/params/stateParams.d.ts +13 -13
  79. package/types/router/core/path/index.d.ts +2 -2
  80. package/types/router/core/path/pathNode.d.ts +49 -49
  81. package/types/router/core/path/pathUtils.d.ts +100 -74
  82. package/types/router/core/resolve/index.d.ts +3 -3
  83. package/types/router/core/resolve/interface.d.ts +137 -137
  84. package/types/router/core/resolve/resolvable.d.ts +60 -54
  85. package/types/router/core/resolve/resolveContext.d.ts +84 -79
  86. package/types/router/core/router.d.ts +95 -86
  87. package/types/router/core/state/index.d.ts +8 -8
  88. package/types/router/core/state/interface.d.ts +667 -643
  89. package/types/router/core/state/stateBuilder.d.ts +41 -38
  90. package/types/router/core/state/stateMatcher.d.ts +11 -9
  91. package/types/router/core/state/stateObject.d.ts +154 -139
  92. package/types/router/core/state/stateQueueManager.d.ts +26 -21
  93. package/types/router/core/state/stateRegistry.d.ts +124 -121
  94. package/types/router/core/state/stateService.d.ts +380 -343
  95. package/types/router/core/state/targetState.d.ts +74 -69
  96. package/types/router/core/transition/hookBuilder.d.ts +34 -30
  97. package/types/router/core/transition/hookRegistry.d.ts +96 -74
  98. package/types/router/core/transition/index.d.ts +8 -8
  99. package/types/router/core/transition/interface.d.ts +652 -609
  100. package/types/router/core/transition/rejectFactory.d.ts +97 -97
  101. package/types/router/core/transition/transition.d.ts +565 -517
  102. package/types/router/core/transition/transitionEventType.d.ts +20 -11
  103. package/types/router/core/transition/transitionHook.d.ts +90 -82
  104. package/types/router/core/transition/transitionService.d.ts +228 -161
  105. package/types/router/core/url/index.d.ts +8 -8
  106. package/types/router/core/url/interface.d.ts +100 -87
  107. package/types/router/core/url/urlConfig.d.ts +130 -126
  108. package/types/router/core/url/urlMatcher.d.ts +132 -127
  109. package/types/router/core/url/urlMatcherFactory.d.ts +46 -42
  110. package/types/router/core/url/urlRouter.d.ts +91 -75
  111. package/types/router/core/url/urlRule.d.ts +123 -100
  112. package/types/router/core/url/urlRules.d.ts +240 -232
  113. package/types/router/core/url/urlService.d.ts +201 -201
  114. package/types/router/core/view/index.d.ts +2 -2
  115. package/types/router/core/view/interface.d.ts +26 -26
  116. package/types/router/core/view/view.d.ts +152 -143
  117. package/types/router/directives/viewDirective.d.ts +12 -11
  118. package/types/router/index.d.ts +11 -12
  119. package/types/router/interface.d.ts +361 -351
  120. package/types/router/legacy/resolveService.d.ts +44 -40
  121. package/types/router/legacy/stateEvents.d.ts +1 -1
  122. package/types/router/locationServices.d.ts +45 -37
  123. package/types/router/services.d.ts +9 -9
  124. package/types/router/stateFilters.d.ts +3 -3
  125. package/types/router/stateProvider.d.ts +240 -235
  126. package/types/router/statebuilders/onEnterExitRetain.d.ts +4 -2
  127. package/types/router/statebuilders/views.d.ts +35 -22
  128. package/types/router/templateFactory.d.ts +99 -79
  129. package/types/router/viewScroll.d.ts +7 -7
  130. package/src/directive/a.js +0 -37
  131. package/types/router/angular.d.ts +0 -1
  132. package/types/router/core/vanilla.d.ts +0 -1
  133. package/types/router/directives/stateDirectives.d.ts +0 -3
  134. package/types/router/injectables.d.ts +0 -1
@@ -0,0 +1,1182 @@
1
+ import { jqLite } from "../../src/jqLite";
2
+ import { Angular } from "../../src/loader";
3
+ import { publishExternalAPI } from "../../src/public";
4
+ import { browserTrigger, wait } from "../test-utils";
5
+
6
+ describe("uiStateRef", () => {
7
+ window.location.hash = "#!";
8
+ let el,
9
+ el2,
10
+ template,
11
+ scope,
12
+ _locationProvider,
13
+ $rootScope,
14
+ $compile,
15
+ $q,
16
+ $injector,
17
+ $timeout,
18
+ $state,
19
+ $stateParams;
20
+
21
+ beforeEach(() => {
22
+ window.angular = new Angular();
23
+ publishExternalAPI();
24
+ let module = window.angular.module("defaultModule", ["ui.router"]);
25
+ module.config(($stateProvider, $locationProvider) => {
26
+ _locationProvider = $locationProvider;
27
+ $locationProvider.hashPrefix("");
28
+ $stateProvider
29
+ .state({ name: "top", url: "" })
30
+ .state({ name: "other", url: "/other/:id", template: "other" })
31
+ .state({ name: "other.detail", url: "/detail", template: "detail" })
32
+ .state({
33
+ name: "contacts",
34
+ url: "/contacts",
35
+ template:
36
+ '<a ui-sref=".item({ id: 5 })" class="item">Person</a> <ui-view></ui-view>',
37
+ })
38
+ .state({
39
+ name: "contacts.item",
40
+ url: "/{id:int}",
41
+ template:
42
+ '<a ui-sref=".detail" class="item-detail">Detail</a> | <a ui-sref="^" class="item-parent">Parent</a> | <ui-view></ui-view>',
43
+ })
44
+ .state({
45
+ name: "contacts.item.detail",
46
+ template:
47
+ '<div class="title">Detail</div> | <a ui-sref="^" class="item-parent2">Item</a>',
48
+ });
49
+ });
50
+ $injector = window.angular.bootstrap(document.getElementById("dummy"), [
51
+ "defaultModule",
52
+ ]);
53
+ $q = $injector.get("$q");
54
+ $rootScope = $injector.get("$rootScope");
55
+ $compile = $injector.get("$compile");
56
+ $timeout = $injector.get("$timeout");
57
+ $state = $injector.get("$state");
58
+ $stateParams = $injector.get("$stateParams");
59
+ });
60
+
61
+ afterEach(() => (window.location.hash = "#!"));
62
+
63
+ describe("links with promises", () => {
64
+ it("should update the href when promises on parameters change before scope is applied", async () => {
65
+ const defer = $q.defer();
66
+ el = jqLite(
67
+ '<a ui-sref="contacts.item.detail({ id: contact.id })">Details</a>',
68
+ );
69
+ defer.promise.then((val) => {
70
+ $rootScope.contact = val;
71
+ });
72
+ defer.resolve({ id: 6 });
73
+ el = $compile(el)($rootScope);
74
+
75
+ $rootScope.$digest();
76
+ expect(el.attr("href")).toBe("#/contacts/6");
77
+ });
78
+ });
79
+
80
+ function buildDOM() {
81
+ window.location.hash = "#";
82
+ el = jqLite(
83
+ '<a ui-sref="contacts.item.detail({ id: contact.id })">Details</a>',
84
+ );
85
+ el2 = jqLite('<a ui-sref="top">Top</a>');
86
+ scope = $rootScope;
87
+ scope.contact = { id: 5 };
88
+ scope.$apply();
89
+
90
+ $compile(el)(scope);
91
+ $compile(el2)(scope);
92
+ scope.$digest();
93
+ }
94
+
95
+ describe("links", () => {
96
+ beforeEach(() => buildDOM());
97
+ afterEach(() => (window.location.hash = ""));
98
+
99
+ it("should generate the correct href", () => {
100
+ expect(el.attr("href")).toBe("#/contacts/5");
101
+ expect(el2.attr("href")).toBe("#");
102
+ });
103
+
104
+ it("should update the href when parameters change", () => {
105
+ expect(el.attr("href")).toBe("#/contacts/5");
106
+ scope.contact.id = 6;
107
+ scope.$apply();
108
+ expect(el.attr("href")).toBe("#/contacts/6");
109
+ });
110
+
111
+ it("should allow multi-line attribute values", async () => {
112
+ el = jqLite(
113
+ '<a ui-sref="contacts.item.detail({\n\tid: $index\n})">Details</a>',
114
+ );
115
+ $rootScope.$index = 3;
116
+ $rootScope.$apply();
117
+
118
+ $compile(el)($rootScope);
119
+ $rootScope.$digest();
120
+ expect(el.attr("href")).toBe("#/contacts/3");
121
+ });
122
+
123
+ it("should transition states when left-clicked", async () => {
124
+ browserTrigger(el, "click");
125
+ await wait(100);
126
+ expect($state.current.name).toEqual("contacts.item.detail");
127
+ expect($stateParams.id).toEqual(5);
128
+ });
129
+
130
+ it("should not transition states when ctrl-clicked", async () => {
131
+ jqLite(el)[0].dispatchEvent(
132
+ new MouseEvent("click", {
133
+ ctrlKey: true,
134
+ bubbles: true,
135
+ cancelable: true,
136
+ }),
137
+ );
138
+ await wait(100);
139
+ expect($state.current.name).toEqual("top");
140
+ expect($stateParams.id).toBeUndefined();
141
+ });
142
+
143
+ // TODO investigate further why this fails
144
+ xit("should not transition states when meta-clicked", async () => {
145
+ jqLite(el)[0].dispatchEvent(new MouseEvent("click", { metaKey: true }));
146
+ expect($state.current.name).toEqual("");
147
+ expect($stateParams.id).toBeUndefined();
148
+ });
149
+
150
+ it("should not transition states when shift-clicked", async () => {
151
+ jqLite(el)[0].dispatchEvent(new MouseEvent("click", { shiftKey: true }));
152
+ expect($state.current.name).toEqual("top");
153
+ expect($stateParams.id).toBeUndefined();
154
+ });
155
+
156
+ // TODO investigate further why this fails
157
+ xit("should not transition states when alt-clicked", async () => {
158
+ expect($state.current.name).toEqual("");
159
+
160
+ jqLite(el)[0].dispatchEvent(new MouseEvent("click", { altKey: true }));
161
+ expect($state.current.name).toEqual("top");
162
+ expect($stateParams.id).toBeUndefined();
163
+ });
164
+
165
+ it("should not transition states when alt-clicked", async () => {
166
+ expect($state.current.name).toEqual("top");
167
+
168
+ jqLite(el)[0].dispatchEvent(new MouseEvent("click", { button: 1 }));
169
+ expect($state.current.name).toEqual("top");
170
+ expect($stateParams.id).toBeUndefined();
171
+ });
172
+
173
+ it("should not transition states when element has target specified", async () => {
174
+ el.attr("target", "_blank");
175
+ browserTrigger(el, "click");
176
+ await wait(100);
177
+ expect($state.current.name).toEqual("top");
178
+ expect($stateParams.id).toBeUndefined();
179
+ });
180
+
181
+ it("should not transition states if preventDefault() is called in click handler", async () => {
182
+ expect($stateParams.id).toBeUndefined();
183
+ el[0].onclick = (e) => e.preventDefault();
184
+
185
+ browserTrigger(el, "click");
186
+ await wait(100);
187
+ expect($state.current.name).toEqual("top");
188
+ expect($stateParams.id).toBeUndefined();
189
+ });
190
+
191
+ // // Test for #1031
192
+ it("should allow passing params to current state", async () => {
193
+ $state.go("other", { id: "abc" });
194
+ $rootScope.$index = "def";
195
+ $rootScope.$digest();
196
+
197
+ el = jqLite('<a ui-sref="{id: $index}">Details</a>');
198
+ $compile(el)($rootScope);
199
+ $rootScope.$digest();
200
+
201
+ expect($state.current.name).toBe("other");
202
+ expect($state.params.id).toEqual("abc");
203
+ expect(el.attr("href")).toBe("#/other/def");
204
+
205
+ browserTrigger(el, "click");
206
+ await wait(100);
207
+ expect($state.current.name).toBe("other");
208
+ expect($state.params.id).toEqual("def");
209
+
210
+ $rootScope.$index = "ghi";
211
+ $state.go("other.detail");
212
+ $rootScope.$digest();
213
+
214
+ expect($state.current.name).toBe("other.detail");
215
+ expect($state.params.id).toEqual("def");
216
+
217
+ expect(el.attr("href")).toBe("#/other/ghi/detail");
218
+
219
+ browserTrigger(el, "click");
220
+ await wait(100);
221
+ expect($state.current.name).toBe("other.detail");
222
+ expect($state.params.id).toEqual("ghi");
223
+ });
224
+
225
+ it("should allow multi-line attribute values when passing params to current state", async () => {
226
+ $state.go("contacts.item.detail", { id: "123" });
227
+ $rootScope.$digest();
228
+
229
+ el = jqLite('<a ui-sref="{\n\tid: $index\n}">Details</a>');
230
+ $rootScope.$index = 3;
231
+ $rootScope.$apply();
232
+
233
+ $compile(el)($rootScope);
234
+ $rootScope.$digest();
235
+ expect(el.attr("href")).toBe("#/contacts/3");
236
+ });
237
+
238
+ it("should take an object as a parameter and update properly on digest churns", async () => {
239
+ el = jqLite(
240
+ '<div><a ui-sref="contacts.item.detail(urlParams)">Contacts</a></div>',
241
+ );
242
+ template = $compile(el)($rootScope);
243
+
244
+ $rootScope.urlParams = { id: 1 };
245
+ $rootScope.$digest();
246
+ expect(jqLite(template[0].querySelector("a")).attr("href")).toBe(
247
+ "#/contacts/1",
248
+ );
249
+
250
+ $rootScope.urlParams.id = 2;
251
+ $rootScope.$digest();
252
+ expect(jqLite(template[0].querySelector("a")).attr("href")).toBe(
253
+ "#/contacts/2",
254
+ );
255
+ });
256
+ });
257
+
258
+ // TODO: Since this is HTML5 mode, we would want to test this with actual backend
259
+ // describe('links in html5 mode', () => {
260
+ // beforeEach(() => {
261
+ // _locationProvider.html5Mode(true);
262
+ // });
263
+
264
+ // beforeEach(inject(buildDOM));
265
+
266
+ // it('should generate the correct href', () => {
267
+ // expect(el.attr('href')).toBe('/contacts/5');
268
+ // expect(el2.attr('href')).toBe('');
269
+ // });
270
+
271
+ // it('should update the href when parameters change', () => {
272
+ // expect(el.attr('href')).toBe('/contacts/5');
273
+ // scope.contact.id = 6;
274
+ // scope.$apply();
275
+ // expect(el.attr('href')).toBe('/contacts/6');
276
+ // });
277
+
278
+ // it('should transition states when the url is empty', async () => {
279
+ // // Odd, in html5Mode, the initial state isn't matching on empty url, but does match if top.url is "/".
280
+ // // expect($state.$current.name).toEqual('top');
281
+
282
+ // triggerClick(el2);
283
+ // timeoutFlush();
284
+ // await wait(10);
285
+
286
+ // expect($state.current.name).toEqual('top');
287
+ // expect(obj($stateParams)).toEqual({});
288
+ // });
289
+ // });
290
+
291
+ describe("links with dynamic state definitions", () => {
292
+ let template;
293
+
294
+ beforeEach(() => {
295
+ el = jqLite(
296
+ '<a ui-sref-active="active" ui-sref-active-eq="activeeq" ui-state="state" ui-state-params="params">state</a>',
297
+ );
298
+ scope = $rootScope;
299
+ Object.assign(scope, { state: "contacts", params: {} });
300
+ template = $compile(el)(scope);
301
+ scope.$digest();
302
+ });
303
+
304
+ it("sets the correct initial href", () => {
305
+ expect(jqLite(template[0]).attr("href")).toBe("#/contacts");
306
+ });
307
+
308
+ it("updates to the new href", () => {
309
+ expect(jqLite(template[0]).attr("href")).toBe("#/contacts");
310
+
311
+ scope.state = "contacts.item";
312
+ scope.params = { id: 5 };
313
+ scope.$digest();
314
+ expect(jqLite(template[0]).attr("href")).toBe("#/contacts/5");
315
+
316
+ scope.params.id = 25;
317
+ scope.$digest();
318
+ expect(jqLite(template[0]).attr("href")).toBe("#/contacts/25");
319
+ });
320
+
321
+ it("updates a linked ui-sref-active", async () => {
322
+ expect(template[0].className).not.toContain("active");
323
+ expect(template[0].className).not.toContain("activeeq");
324
+
325
+ $state.go("contacts");
326
+ scope.$digest();
327
+ await wait(10);
328
+ expect(template[0].className).toContain("active activeeq");
329
+
330
+ scope.state = "contacts.item";
331
+ scope.params = { id: 5 };
332
+ scope.$digest();
333
+ await wait(10);
334
+ expect(template[0].className).not.toContain("active");
335
+ expect(template[0].className).not.toContain("activeeq");
336
+
337
+ $state.go("contacts.item", { id: -5 });
338
+ scope.$digest();
339
+ await wait(10);
340
+ expect(template[0].className).not.toContain("active");
341
+ expect(template[0].className).not.toContain("activeeq");
342
+
343
+ $state.go("contacts.item", { id: 5 });
344
+ scope.$digest();
345
+ await wait(10);
346
+ expect(template[0].className).toContain("active activeeq");
347
+
348
+ scope.state = "contacts";
349
+ scope.params = {};
350
+ scope.$digest();
351
+ await wait(10);
352
+ expect(template[0].className).toContain("active");
353
+ expect(template[0].className).not.toContain("activeeq");
354
+ });
355
+
356
+ it("updates to a new href when it points to a new state", () => {
357
+ expect(jqLite(template[0]).attr("href")).toBe("#/contacts");
358
+ scope.state = "other";
359
+ scope.params = { id: "123" };
360
+ scope.$digest();
361
+ expect(jqLite(template[0]).attr("href")).toBe("#/other/123");
362
+ });
363
+
364
+ it("should allow passing params to current state using empty ui-state", async () => {
365
+ $state.go("other", { id: "abc" });
366
+ $rootScope.$index = "def";
367
+ $rootScope.$digest();
368
+
369
+ el = jqLite('<a ui-state="" ui-state-params="{id: $index}">Details</a>');
370
+ $compile(el)($rootScope);
371
+ $rootScope.$digest();
372
+
373
+ expect($state.current.name).toBe("other");
374
+ expect($state.params.id).toEqual("abc");
375
+ expect(el.attr("href")).toBe("#/other/def");
376
+
377
+ browserTrigger(el, "click");
378
+ await wait(10);
379
+
380
+ expect($state.current.name).toBe("other");
381
+ expect($state.params.id).toEqual("def");
382
+
383
+ $rootScope.$index = "ghi";
384
+ $state.go("other.detail");
385
+ $rootScope.$digest();
386
+
387
+ expect($state.current.name).toBe("other.detail");
388
+ expect($state.params.id).toEqual("def");
389
+
390
+ expect(el.attr("href")).toBe("#/other/ghi/detail");
391
+
392
+ browserTrigger(el, "click");
393
+ await wait(10);
394
+
395
+ expect($state.current.name).toBe("other.detail");
396
+ expect($state.params.id).toEqual("ghi");
397
+ });
398
+
399
+ it("retains the old href if the new points to a non-state", () => {
400
+ expect(jqLite(template[0]).attr("href")).toBe("#/contacts");
401
+ scope.state = "nostate";
402
+ scope.$digest();
403
+ expect(jqLite(template[0]).attr("href")).toBe("#/contacts");
404
+ });
405
+
406
+ it("accepts param overrides", () => {
407
+ scope.state = "contacts.item";
408
+ scope.params = { id: 10 };
409
+ scope.$digest();
410
+ expect(jqLite(template[0]).attr("href")).toBe("#/contacts/10");
411
+ });
412
+
413
+ it("accepts param overrides", () => {
414
+ scope.state = "contacts.item";
415
+ scope.params = { id: 10 };
416
+ scope.$digest();
417
+ expect(jqLite(template[0]).attr("href")).toBe("#/contacts/10");
418
+
419
+ scope.params.id = 22;
420
+ scope.$digest();
421
+ expect(jqLite(template[0]).attr("href")).toBe("#/contacts/22");
422
+ });
423
+
424
+ it("watches attributes", () => {
425
+ el = jqLite(
426
+ '<a ui-state="{{exprvar}}" ui-state-params="params">state</a>',
427
+ );
428
+ template = $compile(el)(scope);
429
+
430
+ scope.exprvar = "state1";
431
+ scope.state1 = "contacts.item";
432
+ scope.state2 = "other";
433
+ scope.params = { id: 10 };
434
+ scope.$digest();
435
+ expect(jqLite(template[0]).attr("href")).toBe("#/contacts/10");
436
+
437
+ scope.exprvar = "state2";
438
+ scope.$digest();
439
+ expect(jqLite(template[0]).attr("href")).toBe("#/other/10");
440
+ });
441
+
442
+ it("allows one-time-binding on ng1.3+", () => {
443
+ el = jqLite('<a ui-state="::state" ui-state-params="::params">state</a>');
444
+
445
+ scope.state = "contacts.item";
446
+ scope.params = { id: 10 };
447
+ template = $compile(el)(scope);
448
+ scope.$digest();
449
+ expect(jqLite(template[0]).attr("href")).toBe("#/contacts/10");
450
+
451
+ scope.state = "other";
452
+ scope.params = { id: 22 };
453
+
454
+ scope.$digest();
455
+ expect(jqLite(template[0]).attr("href")).toBe("#/contacts/10");
456
+ });
457
+
458
+ it("accepts option overrides", async () => {
459
+ let transitionOptions;
460
+
461
+ el = jqLite('<a ui-state="state" ui-state-opts="opts">state</a>');
462
+ scope.state = "contacts";
463
+ scope.opts = { reload: true };
464
+ template = $compile(el)(scope);
465
+ scope.$digest();
466
+
467
+ spyOn($state, "go").and.callFake(function (state, params, options) {
468
+ transitionOptions = options;
469
+ });
470
+
471
+ browserTrigger(template, "click");
472
+ await wait(10);
473
+
474
+ expect(transitionOptions.reload).toEqual(true);
475
+ expect(transitionOptions.absolute).toBeUndefined();
476
+ });
477
+
478
+ describe("option event", () => {
479
+ beforeEach(() => (window.location.hash = ""));
480
+ it("should bind click event by default", async () => {
481
+ expect($state.current.name).toBe("top");
482
+
483
+ el = jqLite('<a ui-state="state"></a>');
484
+
485
+ scope.state = "contacts";
486
+ $compile(el)(scope);
487
+ scope.$digest();
488
+
489
+ browserTrigger(el, "click");
490
+ await wait(10);
491
+
492
+ expect($state.current.name).toBe("contacts");
493
+ });
494
+
495
+ it("should bind single HTML events", async () => {
496
+ expect($state.current.name).toEqual("top");
497
+
498
+ el = jqLite(
499
+ '<input type="text" ui-state="state" ui-state-opts="{ events: [\'change\'] }">',
500
+ );
501
+
502
+ scope.state = "contacts";
503
+ $compile(el)(scope);
504
+ scope.$digest();
505
+
506
+ browserTrigger(el, "change");
507
+ await wait(10);
508
+
509
+ expect($state.current.name).toEqual("contacts");
510
+ });
511
+
512
+ it("should bind multiple HTML events", async () => {
513
+ expect($state.current.name).toEqual("top");
514
+
515
+ el = jqLite(
516
+ '<input type="text" ui-state="state" ui-state-opts="{ events: [\'change\', \'blur\'] }">',
517
+ );
518
+
519
+ scope.state = "contacts";
520
+ $compile(el)(scope);
521
+ scope.$digest();
522
+
523
+ browserTrigger(el, "change");
524
+ await wait(10);
525
+ expect($state.current.name).toEqual("contacts");
526
+
527
+ $state.go("top");
528
+ scope.$digest();
529
+
530
+ expect($state.current.name).toEqual("top");
531
+
532
+ browserTrigger(el, "blur");
533
+ await wait(10);
534
+
535
+ expect($state.current.name).toEqual("contacts");
536
+ });
537
+
538
+ it("should bind multiple Mouse events", async () => {
539
+ expect($state.current.name).toEqual("top");
540
+
541
+ el = jqLite(
542
+ "<a ui-state=\"state\" ui-state-opts=\"{ events: ['mouseover', 'mousedown'] }\">",
543
+ );
544
+
545
+ scope.state = "contacts";
546
+ $compile(el)(scope);
547
+ scope.$digest();
548
+
549
+ browserTrigger(el, "mouseover");
550
+ await wait(10);
551
+ expect($state.current.name).toEqual("contacts");
552
+
553
+ $state.go("top");
554
+ scope.$digest();
555
+
556
+ expect($state.current.name).toEqual("top");
557
+
558
+ browserTrigger(el, "mousedown");
559
+ await wait(10);
560
+ expect($state.current.name).toEqual("contacts");
561
+ });
562
+ });
563
+ });
564
+
565
+ describe("forms", () => {
566
+ let el, scope;
567
+
568
+ beforeEach(() => {
569
+ el = jqLite(
570
+ '<form ui-sref="contacts.item.detail({ id: contact.id })"></form>',
571
+ );
572
+ scope = $rootScope;
573
+ scope.contact = { id: 5 };
574
+ scope.$apply();
575
+
576
+ $compile(el)(scope);
577
+ scope.$digest();
578
+ });
579
+
580
+ it("should generate the correct action", () => {
581
+ expect(el.attr("action")).toBe("#/contacts/5");
582
+ });
583
+ });
584
+
585
+ describe("relative transitions", () => {
586
+ beforeEach(() => {
587
+ $state.transitionTo("contacts.item", { id: 5 });
588
+ el = jqLite('<a ui-sref=".detail">Details</a>');
589
+ scope = $rootScope;
590
+ scope.$apply();
591
+
592
+ $compile(el)(scope);
593
+ template = $compile(jqLite("<div><ui-view></ui-view><div>"))(scope);
594
+ scope.$digest();
595
+ });
596
+
597
+ it("should work", async () => {
598
+ browserTrigger(el, "click");
599
+ await wait(10);
600
+
601
+ expect($state.$current.name).toBe("contacts.item.detail");
602
+ expect($state.params.id).toEqual(5);
603
+ });
604
+
605
+ it("should resolve states from parent uiView", async () => {
606
+ $state.transitionTo("contacts");
607
+
608
+ const parentToChild = jqLite(template[0].querySelector("a.item"));
609
+ browserTrigger(parentToChild, "click");
610
+ await wait(10);
611
+
612
+ expect($state.$current.name).toBe("contacts.item");
613
+
614
+ const childToGrandchild = jqLite(
615
+ template[0].querySelector("a.item-detail"),
616
+ );
617
+ const childToParent = jqLite(template[0].querySelector("a.item-parent"));
618
+
619
+ browserTrigger(childToGrandchild, "click");
620
+ await wait(10);
621
+
622
+ const grandchildToParent = jqLite(
623
+ template[0].querySelector("a.item-parent2"),
624
+ );
625
+ expect($state.$current.name).toBe("contacts.item.detail");
626
+
627
+ browserTrigger(grandchildToParent, "click");
628
+ await wait(10);
629
+
630
+ expect($state.$current.name).toBe("contacts.item");
631
+
632
+ $state.transitionTo("contacts.item.detail", { id: 3 });
633
+ browserTrigger(childToParent, "click");
634
+ await wait(10);
635
+ expect($state.$current.name).toBe("contacts");
636
+ });
637
+ });
638
+
639
+ describe("option event", () => {
640
+ beforeEach(() => (window.location.hash = ""));
641
+ it("should bind click event by default", async () => {
642
+ el = jqLite('<a ui-sref="contacts"></a>');
643
+ $compile(el)($rootScope);
644
+ $rootScope.$digest();
645
+
646
+ expect($state.current.name).toEqual("top");
647
+
648
+ browserTrigger(el, "click");
649
+ await wait(10);
650
+
651
+ expect($state.current.name).toEqual("contacts");
652
+ });
653
+
654
+ it("should bind single HTML events", async () => {
655
+ el = jqLite(
656
+ '<input type="text" ui-sref="contacts" ui-sref-opts="{ events: [\'change\'] }">',
657
+ );
658
+ $compile(el)($rootScope);
659
+ $rootScope.$digest();
660
+
661
+ expect($state.current.name).toEqual("top");
662
+
663
+ browserTrigger(el, "change");
664
+ await wait(10);
665
+
666
+ expect($state.current.name).toEqual("contacts");
667
+ });
668
+
669
+ it("should bind multiple HTML events", async () => {
670
+ el = jqLite(
671
+ '<input type="text" ui-sref="contacts" ui-sref-opts="{ events: [\'change\', \'blur\'] }">',
672
+ );
673
+ $compile(el)($rootScope);
674
+ $rootScope.$digest();
675
+
676
+ expect($state.current.name).toEqual("top");
677
+
678
+ browserTrigger(el, "change");
679
+ await wait(10);
680
+ expect($state.current.name).toEqual("contacts");
681
+
682
+ $state.go("top");
683
+ $rootScope.$digest();
684
+
685
+ expect($state.current.name).toEqual("top");
686
+
687
+ browserTrigger(el, "blur");
688
+ await wait(10);
689
+ expect($state.current.name).toEqual("contacts");
690
+ });
691
+
692
+ it("should bind multiple Mouse events", async () => {
693
+ el = jqLite(
694
+ "<a ui-sref=\"contacts\" ui-sref-opts=\"{ events: ['mouseover', 'mousedown'] }\">",
695
+ );
696
+ $compile(el)($rootScope);
697
+ $rootScope.$digest();
698
+
699
+ expect($state.current.name).toEqual("top");
700
+
701
+ browserTrigger(el, "mouseover");
702
+ await wait(10);
703
+ expect($state.current.name).toEqual("contacts");
704
+
705
+ $state.go("top");
706
+ $rootScope.$digest();
707
+
708
+ expect($state.current.name).toEqual("top");
709
+
710
+ browserTrigger(el, "mousedown");
711
+ await wait(10);
712
+ expect($state.current.name).toEqual("contacts");
713
+ });
714
+ });
715
+ });
716
+
717
+ describe("uiSrefActive", () => {
718
+ window.location.hash = "#!";
719
+ let el,
720
+ el2,
721
+ template,
722
+ scope,
723
+ _locationProvider,
724
+ $rootScope,
725
+ $compile,
726
+ $q,
727
+ $injector,
728
+ $timeout,
729
+ $state,
730
+ $stateParams,
731
+ _stateProvider;
732
+
733
+ beforeEach(() => {
734
+ window.location.hash = "#!";
735
+ window.angular = new Angular();
736
+ publishExternalAPI();
737
+ let module = window.angular.module("defaultModule", ["ui.router"]);
738
+ module.config(function ($stateProvider) {
739
+ _stateProvider = $stateProvider;
740
+ $stateProvider
741
+ .state({ name: "top", url: "" })
742
+ .state({
743
+ name: "contacts",
744
+ url: "/contacts",
745
+ views: {
746
+ $default: {
747
+ template:
748
+ '<a ui-sref=".item({ id: 6 })" ui-sref-active="active">Contacts</a>',
749
+ },
750
+ },
751
+ })
752
+ .state({ name: "contacts.item", url: "/:id" })
753
+ .state({ name: "contacts.item.detail", url: "/detail/:foo" })
754
+ .state({ name: "contacts.item.edit", url: "/edit" })
755
+ .state({
756
+ name: "admin",
757
+ url: "/admin",
758
+ abstract: true,
759
+ template: "<ui-view/>",
760
+ })
761
+ .state({ name: "admin.roles", url: "/roles?page" })
762
+ .state({
763
+ name: "arrayparam",
764
+ url: "/arrayparam?{foo:int}&bar",
765
+ template: "<div></div>",
766
+ });
767
+ });
768
+ $injector = window.angular.bootstrap(document.getElementById("dummy"), [
769
+ "defaultModule",
770
+ ]);
771
+ $q = $injector.get("$q");
772
+ $rootScope = $injector.get("$rootScope");
773
+ $compile = $injector.get("$compile");
774
+ $timeout = $injector.get("$timeout");
775
+ $state = $injector.get("$state");
776
+ $stateParams = $injector.get("$stateParams");
777
+ });
778
+
779
+ it("should update class for sibling uiSref", async () => {
780
+ el = jqLite(
781
+ '<div><a ui-sref="contacts.item({ id: 1 })" ui-sref-active="active">Contacts</a><a ui-sref="contacts.item({ id: 2 })" ui-sref-active="active">Contacts</a></div>',
782
+ );
783
+ template = $compile(el)($rootScope);
784
+ $rootScope.$digest();
785
+
786
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBeFalsy();
787
+ $state.transitionTo("contacts.item", { id: 1 });
788
+ await wait(10);
789
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBe("active");
790
+
791
+ $state.transitionTo("contacts.item", { id: 2 });
792
+ await wait(10);
793
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBeFalsy();
794
+ });
795
+
796
+ it("should match state's parameters", async () => {
797
+ el = jqLite(
798
+ '<div><a ui-sref="contacts.item.detail({ foo: \'bar\' })" ui-sref-active="active">Contacts</a></div>',
799
+ );
800
+ template = $compile(el)($rootScope);
801
+ $rootScope.$digest();
802
+
803
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBeFalsy();
804
+ $state.transitionTo("contacts.item.detail", { id: 5, foo: "bar" });
805
+ await wait(10);
806
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBe("active");
807
+
808
+ $state.transitionTo("contacts.item.detail", { id: 5, foo: "baz" });
809
+ await wait(10);
810
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBeFalsy();
811
+ });
812
+
813
+ // Test for #2696
814
+ it("should compare using typed parameters", async () => {
815
+ el = jqLite(
816
+ '<div><a ui-sref="arrayparam({ foo: [1,2,3] })" ui-sref-active="active">foo 123</a></div>',
817
+ );
818
+ template = $compile(el)($rootScope);
819
+ $rootScope.$digest();
820
+
821
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBeFalsy();
822
+
823
+ $state.transitionTo("arrayparam", { foo: [1, 2, 3] });
824
+ await wait(10);
825
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBe("active");
826
+
827
+ $state.transitionTo("arrayparam", { foo: [1, 2, 3], bar: "asdf" });
828
+ await wait(10);
829
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBe("active");
830
+
831
+ $state.transitionTo("arrayparam", { foo: [1, 2] });
832
+ await wait(10);
833
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBeFalsy();
834
+ });
835
+
836
+ // Test for #3154
837
+ it("should compare ui-sref-active-eq using typed parameters", async () => {
838
+ el = jqLite(
839
+ '<div><a ui-sref="arrayparam({ foo: [1,2,3] })" ui-sref-active-eq="active">foo 123</a></div>',
840
+ );
841
+ template = $compile(el)($rootScope);
842
+ $rootScope.$digest();
843
+
844
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBeFalsy();
845
+
846
+ $state.transitionTo("arrayparam", { foo: [1, 2, 3] });
847
+ await wait(10);
848
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBe("active");
849
+
850
+ $state.transitionTo("arrayparam", { foo: [1, 2, 3], bar: "asdf" });
851
+ await wait(10);
852
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBe("active");
853
+
854
+ $state.transitionTo("arrayparam", { foo: [1, 2] });
855
+ await wait(10);
856
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBeFalsy();
857
+ });
858
+
859
+ it("should update in response to ui-sref param expression changes", async () => {
860
+ el = jqLite(
861
+ '<div><a ui-sref="contacts.item.detail({ foo: fooId })" ui-sref-active="active">Contacts</a></div>',
862
+ );
863
+ template = $compile(el)($rootScope);
864
+ $rootScope.fooId = "bar";
865
+ $rootScope.$digest();
866
+
867
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBeFalsy();
868
+ $state.transitionTo("contacts.item.detail", { id: 5, foo: "bar" });
869
+ await wait(10);
870
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBe("active");
871
+
872
+ $rootScope.fooId = "baz";
873
+ $rootScope.$digest();
874
+ await wait(10);
875
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBeFalsy();
876
+ });
877
+
878
+ it("should match on child states", async () => {
879
+ template = $compile(
880
+ '<div><a ui-sref="contacts.item({ id: 1 })" ui-sref-active="active">Contacts</a></div>',
881
+ )($rootScope);
882
+ $rootScope.$digest();
883
+ const a = jqLite(template[0].getElementsByTagName("a")[0]);
884
+
885
+ $state.transitionTo("contacts.item.edit", { id: 1 });
886
+ await wait(10);
887
+ expect($state.params.id).toBe("1");
888
+ expect(a.attr("class")).toMatch(/active/);
889
+
890
+ $state.transitionTo("contacts.item.edit", { id: 4 });
891
+ await wait(10);
892
+ expect($state.params.id).toBe("4");
893
+ expect(a.attr("class")).not.toMatch(/active/);
894
+ });
895
+
896
+ it("should NOT match on child states when active-equals is used", async () => {
897
+ template = $compile(
898
+ '<div><a ui-sref="contacts.item({ id: 1 })" ui-sref-active-eq="active">Contacts</a></div>',
899
+ )($rootScope);
900
+ $rootScope.$digest();
901
+ const a = jqLite(template[0].getElementsByTagName("a")[0]);
902
+
903
+ $state.transitionTo("contacts.item", { id: 1 });
904
+ await wait(10);
905
+ expect(a.attr("class")).toMatch(/active/);
906
+
907
+ $state.transitionTo("contacts.item.edit", { id: 1 });
908
+ await wait(10);
909
+ expect(a.attr("class")).not.toMatch(/active/);
910
+ });
911
+
912
+ it("should match on child states when active-equals and active-equals-eq is used", async () => {
913
+ template = $compile(
914
+ '<div><a ui-sref="contacts.item({ id: 1 })" ui-sref-active="active" ui-sref-active-eq="active-eq">Contacts</a></div>',
915
+ )($rootScope);
916
+ $rootScope.$digest();
917
+ const a = jqLite(template[0].getElementsByTagName("a")[0]);
918
+
919
+ $state.transitionTo("contacts.item", { id: 1 });
920
+ await wait(10);
921
+ expect(a.attr("class")).toMatch(/active/);
922
+ expect(a.attr("class")).toMatch(/active-eq/);
923
+
924
+ $state.transitionTo("contacts.item.edit", { id: 1 });
925
+ await wait(10);
926
+ expect(a.attr("class")).toMatch(/active/);
927
+ expect(a.attr("class")).not.toMatch(/active-eq/);
928
+ });
929
+
930
+ it("should resolve relative state refs", async () => {
931
+ el = jqLite("<section><div ui-view></div></section>");
932
+ template = $compile(el)($rootScope);
933
+ $rootScope.$digest();
934
+
935
+ $state.transitionTo("contacts");
936
+ await wait(10);
937
+ expect(
938
+ jqLite(template[0].querySelector("a")).attr("class"),
939
+ ).toBeUndefined();
940
+
941
+ $state.transitionTo("contacts.item", { id: 6 });
942
+ await wait(10);
943
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBe("active");
944
+
945
+ $state.transitionTo("contacts.item", { id: 5 });
946
+ await wait(10);
947
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBe("");
948
+ });
949
+
950
+ it("should match on any child state refs", async () => {
951
+ el = jqLite(
952
+ '<div ui-sref-active="active"><a ui-sref="contacts.item({ id: 1 })">Contacts</a><a ui-sref="contacts.item({ id: 2 })">Contacts</a></div>',
953
+ );
954
+ template = $compile(el)($rootScope);
955
+ $rootScope.$digest();
956
+
957
+ expect(jqLite(template[0]).attr("class")).toBeUndefined();
958
+
959
+ $state.transitionTo("contacts.item", { id: 1 });
960
+ await wait(10);
961
+ expect(jqLite(template[0]).attr("class")).toBe("active");
962
+
963
+ $state.transitionTo("contacts.item", { id: 2 });
964
+ await wait(10);
965
+ expect(jqLite(template[0]).attr("class")).toBe("active");
966
+ });
967
+
968
+ it("should match fuzzy on lazy loaded states", async () => {
969
+ el = jqLite(
970
+ '<div><a ui-sref="contacts.lazy" ui-sref-active="active">Lazy Contact</a></div>',
971
+ );
972
+ template = $compile(el)($rootScope);
973
+ await wait(10);
974
+
975
+ _stateProvider.onInvalid(function ($to$) {
976
+ if ($to$.name() === "contacts.lazy") {
977
+ _stateProvider.state({ name: "contacts.lazy" });
978
+ return $to$;
979
+ }
980
+ });
981
+
982
+ $state.transitionTo("contacts.item", { id: 1 });
983
+ await wait(10);
984
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBeFalsy();
985
+
986
+ $state.transitionTo("contacts.lazy");
987
+ await wait(10);
988
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBe("active");
989
+ });
990
+
991
+ it("should match exactly on lazy loaded states", async () => {
992
+ el = jqLite(
993
+ '<div><a ui-sref="contacts.lazy" ui-sref-active-eq="active">Lazy Contact</a></div>',
994
+ );
995
+ template = $compile(el)($rootScope);
996
+ await wait(10);
997
+
998
+ _stateProvider.onInvalid(function ($to$) {
999
+ if ($to$.name() === "contacts.lazy") {
1000
+ _stateProvider.state({ name: "contacts.lazy" });
1001
+ return $to$;
1002
+ }
1003
+ });
1004
+
1005
+ $state.transitionTo("contacts.item", { id: 1 });
1006
+ await wait(10);
1007
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBeFalsy();
1008
+
1009
+ $state.transitionTo("contacts.lazy");
1010
+ await wait(10);
1011
+ expect(jqLite(template[0].querySelector("a")).attr("class")).toBe("active");
1012
+ });
1013
+
1014
+ it("should allow multiple classes to be supplied", async () => {
1015
+ template = $compile(
1016
+ '<div><a ui-sref="contacts.item({ id: 1 })" ui-sref-active="active also-active">Contacts</a></div>',
1017
+ )($rootScope);
1018
+ $rootScope.$digest();
1019
+ const a = jqLite(template[0].getElementsByTagName("a")[0]);
1020
+
1021
+ $state.transitionTo("contacts.item.edit", { id: 1 });
1022
+ await wait(10);
1023
+ expect(a.attr("class")).toMatch(/active also-active/);
1024
+ });
1025
+
1026
+ // TODO does not work
1027
+ xit("should not match fuzzy on lazy loaded future states", async () => {
1028
+ _stateProvider.state({
1029
+ name: "contacts.lazy.**",
1030
+ url: "/lazy",
1031
+ lazyLoad: () => {
1032
+ return $q.when().then(() => {
1033
+ _stateProvider
1034
+ .state({ name: "contacts.lazy", abstract: true, url: "/lazy" })
1035
+ .state({ name: "contacts.lazy.s1", url: "/s1" })
1036
+ .state({ name: "contacts.lazy.s2", url: "/s2" });
1037
+ });
1038
+ },
1039
+ });
1040
+ template = $compile(
1041
+ '<div ui-sref-active="active"><a ui-sref="contacts.lazy.s1">Lazy</a></div><div ui-sref-active="active"><a ui-sref="contacts.lazy.s2"></a></div>',
1042
+ )($rootScope);
1043
+ $rootScope.$digest();
1044
+ $state.transitionTo("contacts.lazy.s1");
1045
+ await wait(10);
1046
+
1047
+ expect(template.eq(0)[0].hasClass("active")).toBeTruthy();
1048
+ //expect(template.eq(1).hasClass("active")).toBeFalsy();
1049
+ });
1050
+
1051
+ // TODO investigate why transitions error out
1052
+ xdescribe("ng-{class,style} interface", () => {
1053
+ it("should match on abstract states that are included by the current state", async () => {
1054
+ el = $compile(
1055
+ '<div ui-sref-active="{active: \'admin.*\'}"><a ui-sref-active="active" ui-sref="admin.roles">Roles</a></div>',
1056
+ )($rootScope);
1057
+ $state.transitionTo("admin.roles");
1058
+ await wait(10);
1059
+ const abstractParent = el[0];
1060
+ expect(abstractParent.className).toMatch(/active/);
1061
+ const child = el[0].querySelector("a");
1062
+ expect(child.className).toMatch(/active/);
1063
+ });
1064
+
1065
+ it("should match on state parameters", async () => {
1066
+ el = $compile(
1067
+ "<div ui-sref-active=\"{active: 'admin.roles({page: 1})'}\"></div>",
1068
+ )($rootScope);
1069
+ $state.transitionTo("admin.roles", { page: 1 });
1070
+ await wait(10);
1071
+ expect(el[0].className).toMatch(/active/);
1072
+ });
1073
+
1074
+ it("should shadow the state provided by ui-sref", async () => {
1075
+ el = $compile(
1076
+ '<div ui-sref-active="{active: \'admin.roles({page: 1})\'}"><a ui-sref="admin.roles"></a></div>',
1077
+ )($rootScope);
1078
+ $state.transitionTo("admin.roles");
1079
+ await wait(10);
1080
+ expect(el[0].className).not.toMatch(/active/);
1081
+ $state.transitionTo("admin.roles", { page: 1 });
1082
+ await wait(10);
1083
+ expect(el[0].className).toMatch(/active/);
1084
+ });
1085
+
1086
+ it("should support multiple <className, stateOrName> pairs", async () => {
1087
+ el = $compile(
1088
+ "<div ui-sref-active=\"{contacts: 'contacts.**', admin: 'admin.roles({page: 1})'}\"></div>",
1089
+ )($rootScope);
1090
+ $state.transitionTo("contacts");
1091
+ await wait(10);
1092
+ expect(el[0].className).toMatch(/contacts/);
1093
+ expect(el[0].className).not.toMatch(/admin/);
1094
+ $state.transitionTo("admin.roles", { page: 1 });
1095
+ await wait(10);
1096
+ expect(el[0].className).toMatch(/admin/);
1097
+ expect(el[0].className).not.toMatch(/contacts/);
1098
+ });
1099
+
1100
+ it("should update the active classes when compiled", async () => {
1101
+ $state.transitionTo("admin.roles");
1102
+ await wait(10);
1103
+ el = $compile("<div ui-sref-active=\"{active: 'admin.roles'}\"/>")(
1104
+ $rootScope,
1105
+ );
1106
+ $rootScope.$digest();
1107
+ timeoutFlush();
1108
+ expect(el.hasClass("active")).toBeTruthy();
1109
+ });
1110
+
1111
+ it("should not match fuzzy on lazy loaded future states", async () => {
1112
+ _stateProvider.state({
1113
+ name: "contacts.lazy.**",
1114
+ url: "/lazy",
1115
+ lazyLoad: () => {
1116
+ return $q.when().then(() => {
1117
+ _stateProvider
1118
+ .state({ name: "contacts.lazy", abstract: true, url: "/lazy" })
1119
+ .state({ name: "contacts.lazy.s1", url: "/s1" })
1120
+ .state({ name: "contacts.lazy.s2", url: "/s2" });
1121
+ });
1122
+ },
1123
+ });
1124
+ template = $compile(
1125
+ '<div ui-sref-active="{ active: \'contacts.lazy.s1\' }"><a ui-sref="contacts.lazy.s1">Lazy</a></div><div ui-sref-active="{ active: \'contacts.lazy.s2\' }"></div>',
1126
+ )($rootScope);
1127
+ $rootScope.$digest();
1128
+ $state.transitionTo("contacts.lazy.s1");
1129
+ await wait(10);
1130
+ expect(template.eq(0).hasClass("active")).toBeTruthy();
1131
+ expect(template.eq(1).hasClass("active")).toBeFalsy();
1132
+ });
1133
+ });
1134
+
1135
+ xdescribe("ng-{class,style} interface, and handle values as arrays", () => {
1136
+ it("should match on abstract states that are included by the current state", async () => {
1137
+ el = $compile(
1138
+ '<div ui-sref-active="{active: [\'randomState.**\', \'admin.roles\']}"><a ui-sref-active="active" ui-sref="admin.roles">Roles</a></div>',
1139
+ )($rootScope);
1140
+ $state.transitionTo("admin.roles");
1141
+ await wait(10);
1142
+ const abstractParent = el[0];
1143
+ expect(abstractParent.className).toMatch(/active/);
1144
+ const child = el[0].querySelector("a");
1145
+ expect(child.className).toMatch(/active/);
1146
+ });
1147
+
1148
+ it("should match on state parameters", async () => {
1149
+ el = $compile(
1150
+ "<div ui-sref-active=\"{active: ['admin.roles({page: 1})']}\"></div>",
1151
+ )($rootScope);
1152
+ $state.transitionTo("admin.roles", { page: 1 });
1153
+ await wait(10);
1154
+ expect(el[0].className).toMatch(/active/);
1155
+ });
1156
+
1157
+ it("should support multiple <className, stateOrName> pairs", async () => {
1158
+ el = $compile(
1159
+ "<div ui-sref-active=\"{contacts: ['contacts.item', 'contacts.item.detail'], admin: 'admin.roles({page: 1})'}\"></div>",
1160
+ )($rootScope);
1161
+ $state.transitionTo("contacts.item.detail", { id: 1, foo: "bar" });
1162
+ await wait(10);
1163
+ expect(el[0].className).toMatch(/contacts/);
1164
+ expect(el[0].className).not.toMatch(/admin/);
1165
+ $state.transitionTo("admin.roles", { page: 1 });
1166
+ await wait(10);
1167
+ expect(el[0].className).toMatch(/admin/);
1168
+ expect(el[0].className).not.toMatch(/contacts/);
1169
+ });
1170
+
1171
+ it("should update the active classes when compiled", async () => {
1172
+ $state.transitionTo("admin.roles");
1173
+ await wait(10);
1174
+ el = $compile(
1175
+ "<div ui-sref-active=\"{active: ['admin.roles', 'admin.someOtherState']}\"/>",
1176
+ )($rootScope);
1177
+ $rootScope.$digest();
1178
+ timeoutFlush();
1179
+ expect(el.hasClass("active")).toBeTruthy();
1180
+ });
1181
+ });
1182
+ });