@angular-wave/angular.ts 0.7.5 → 0.7.8

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 (174) hide show
  1. package/@types/animations/raf-scheduler.d.ts +2 -2
  2. package/@types/animations/shared.d.ts +0 -1
  3. package/@types/core/compile/attributes.d.ts +3 -3
  4. package/@types/core/compile/compile.d.ts +1 -1
  5. package/@types/core/di/injector.d.ts +0 -1
  6. package/@types/core/di/internal-injector.d.ts +1 -0
  7. package/@types/core/di/ng-module.d.ts +5 -0
  8. package/@types/core/filter/filter.d.ts +11 -13
  9. package/@types/core/sanitize/sanitize-uri.d.ts +3 -6
  10. package/@types/core/scope/scope.d.ts +1 -3
  11. package/@types/directive/attrs/attrs.d.ts +7 -1
  12. package/@types/directive/events/events.d.ts +9 -3
  13. package/@types/directive/http/http.d.ts +6 -2
  14. package/@types/directive/include/include.d.ts +2 -2
  15. package/@types/directive/input/input.d.ts +2 -12
  16. package/@types/directive/messages/messages.d.ts +9 -48
  17. package/@types/directive/model/model.d.ts +3 -3
  18. package/@types/directive/options/options.d.ts +13 -20
  19. package/@types/directive/setter/setter.d.ts +2 -2
  20. package/@types/directive/switch/switch.d.ts +1 -0
  21. package/@types/directive/transclude/transclude.d.ts +10 -6
  22. package/@types/interface.d.ts +54 -18
  23. package/@types/router/common/glob.d.ts +5 -1
  24. package/@types/router/directives/view-directive.d.ts +2 -19
  25. package/@types/router/globals.d.ts +1 -2
  26. package/@types/router/state/state-registry.d.ts +1 -2
  27. package/@types/router/url/url-service.d.ts +7 -9
  28. package/@types/services/anchor-scroll.d.ts +1 -1
  29. package/@types/{core → services/exception}/exception-handler.d.ts +4 -4
  30. package/@types/{core/error-handler.d.ts → services/exception/interface.d.ts} +1 -1
  31. package/@types/services/http/http.d.ts +0 -2
  32. package/@types/services/http/interface.d.ts +2 -2
  33. package/@types/services/http-backend/http-backend.d.ts +13 -21
  34. package/@types/services/location/interface.d.ts +8 -0
  35. package/@types/{core → services}/location/location.d.ts +52 -12
  36. package/@types/{core → services}/sce/sce.d.ts +1 -1
  37. package/@types/services/template-cache/interface.d.ts +8 -2
  38. package/@types/services/template-cache/template-cache.d.ts +1 -1
  39. package/@types/services/template-request.d.ts +1 -1
  40. package/@types/shared/cache.d.ts +0 -2
  41. package/@types/shared/dom.d.ts +6 -0
  42. package/@types/shared/test-utils.d.ts +1 -0
  43. package/@types/shared/url-utils/interface.d.ts +47 -0
  44. package/@types/{core → shared}/url-utils/url-utils.d.ts +26 -13
  45. package/@types/shared/utils.d.ts +23 -0
  46. package/Makefile +3 -2
  47. package/dist/angular-ts.esm.js +1188 -1364
  48. package/dist/angular-ts.umd.js +1188 -1364
  49. package/dist/angular-ts.umd.min.js +1 -1
  50. package/docs/assets/scss/index.scss +12 -0
  51. package/docs/content/_index.md +15 -4
  52. package/docs/content/docs/directive/bind.md +72 -0
  53. package/docs/content/docs/directive/click.md +3 -0
  54. package/docs/content/docs/directive/dblclick.md +3 -0
  55. package/docs/content/docs/directive/get.md +203 -0
  56. package/docs/content/docs/directive/keydown.md +38 -0
  57. package/docs/content/docs/directive/keyup.md +38 -0
  58. package/docs/content/docs/directive/load.md +43 -0
  59. package/docs/content/docs/provider/templateCacheProvider.md +66 -1
  60. package/docs/content/docs/service/templateCache.md +2 -2
  61. package/docs/layouts/partials/hooks/head-end.html +1 -1
  62. package/docs/layouts/shortcodes/showcss.html +2 -0
  63. package/docs/static/examples/ng-bind/ng-bind.html +9 -0
  64. package/docs/static/examples/ng-keydown/ng-keydown.html +9 -0
  65. package/docs/static/examples/ng-keyup/ng-keyup.html +9 -0
  66. package/docs/static/examples/ng-load/ng-load.html +8 -0
  67. package/docs/static/typedoc/assets/hierarchy.js +1 -1
  68. package/docs/static/typedoc/assets/navigation.js +1 -1
  69. package/docs/static/typedoc/assets/search.js +1 -1
  70. package/docs/static/typedoc/classes/NgModule.html +32 -0
  71. package/docs/static/typedoc/classes/TemplateCacheProvider.html +1 -1
  72. package/docs/static/typedoc/hierarchy.html +1 -1
  73. package/docs/static/typedoc/index.html +1 -1
  74. package/docs/static/typedoc/interfaces/Directive.html +5 -4
  75. package/docs/static/typedoc/interfaces/HttpProviderDefaults.html +1 -1
  76. package/docs/static/typedoc/interfaces/HttpResponse.html +2 -3
  77. package/docs/static/typedoc/interfaces/Provider.html +15 -10
  78. package/docs/static/typedoc/interfaces/RequestConfig.html +1 -1
  79. package/docs/static/typedoc/interfaces/RequestShortcutConfig.html +1 -1
  80. package/docs/static/typedoc/interfaces/TemplateCache.html +7 -0
  81. package/docs/static/typedoc/types/AnnotatedDirectiveFactory.html +1 -0
  82. package/docs/static/typedoc/types/DirectiveFactory.html +1 -2
  83. package/docs/static/typedoc/types/DirectiveFactoryFn.html +1 -0
  84. package/docs/static/typedoc/types/HttpResponseStatus.html +1 -0
  85. package/docs/static/typedoc/types/{TemplateCache.html → SwapModeType.html} +1 -1
  86. package/docs/static/typedoc/variables/SwapMode.html +11 -0
  87. package/legacy.d.ts +0 -14
  88. package/package.json +1 -3
  89. package/src/animations/animate-children-directive.js +2 -2
  90. package/src/animations/raf-scheduler.js +1 -1
  91. package/src/animations/shared.js +0 -9
  92. package/src/core/compile/attributes.js +1 -1
  93. package/src/core/compile/compile.js +3 -3
  94. package/src/core/di/injector.js +4 -17
  95. package/src/core/di/internal-injector.js +4 -1
  96. package/src/core/di/ng-module.js +12 -27
  97. package/src/core/filter/filter.js +28 -28
  98. package/src/core/parse/interpreter.js +32 -38
  99. package/src/core/sanitize/sanitize-uri.js +3 -3
  100. package/src/core/scope/scope.js +2 -7
  101. package/src/directive/attrs/attrs.js +7 -4
  102. package/src/directive/bind/bind.js +16 -4
  103. package/src/directive/bind/bind.spec.js +13 -0
  104. package/src/directive/events/events.js +7 -3
  105. package/src/directive/events/events.md +0 -41
  106. package/src/directive/http/delete.spec.js +2 -0
  107. package/src/directive/http/get.spec.js +280 -3
  108. package/src/directive/http/http.js +100 -12
  109. package/src/directive/http/http.test.js +2 -2
  110. package/src/directive/http/post.spec.js +2 -0
  111. package/src/directive/http/put.spec.js +2 -0
  112. package/src/directive/include/include.js +7 -7
  113. package/src/directive/input/input.js +6 -28
  114. package/src/directive/messages/messages.js +5 -1
  115. package/src/directive/model/model.js +1 -1
  116. package/src/directive/options/options.js +454 -464
  117. package/src/directive/repeat/repeat.js +175 -153
  118. package/src/directive/setter/setter.js +13 -15
  119. package/src/directive/setter/setter.spec.js +39 -16
  120. package/src/directive/switch/switch.js +1 -0
  121. package/src/directive/switch/switch.spec.js +1 -1
  122. package/src/directive/transclude/transclude.js +87 -89
  123. package/src/injection-tokens.js +1 -1
  124. package/src/interface.ts +68 -19
  125. package/src/loader.js +4 -9
  126. package/src/public.js +9 -15
  127. package/src/router/common/glob.js +5 -0
  128. package/src/router/directives/state-directives.js +4 -6
  129. package/src/router/directives/state-directives.spec.js +1 -1
  130. package/src/router/directives/view-directive.js +9 -1
  131. package/src/router/globals.js +0 -1
  132. package/src/router/state/state-registry.js +0 -1
  133. package/src/router/state-filters.js +2 -2
  134. package/src/router/url/url-service.js +5 -9
  135. package/src/services/anchor-scroll.html +0 -7
  136. package/src/services/anchor-scroll.js +2 -2
  137. package/src/{core → services/exception}/exception-handler.js +2 -2
  138. package/src/{core/error-handler.ts → services/exception/interface.ts} +1 -1
  139. package/src/services/http/http.js +2 -13
  140. package/src/services/http/interface.ts +2 -2
  141. package/src/services/http-backend/http-backend.js +4 -14
  142. package/src/services/http-backend/http-backend.spec.js +1 -4
  143. package/src/services/location/interface.ts +8 -0
  144. package/src/{core → services}/location/location.html +4 -1
  145. package/src/{core → services}/location/location.js +129 -27
  146. package/src/{core → services}/location/location.spec.js +2 -2
  147. package/src/{core → services}/location/location.test.js +1 -1
  148. package/src/{core → services}/sce/sce.html +1 -1
  149. package/src/{core → services}/sce/sce.js +9 -3
  150. package/src/{core → services}/sce/sce.spec.js +2 -3
  151. package/src/{core → services}/sce/sce.test.js +1 -1
  152. package/src/services/template-cache/interface.ts +8 -2
  153. package/src/services/template-cache/template-cache.js +3 -1
  154. package/src/services/template-cache/template-cache.spec.js +72 -0
  155. package/src/services/template-request.js +2 -1
  156. package/src/shared/cache.js +0 -2
  157. package/src/shared/dom.js +10 -0
  158. package/src/shared/test-utils.js +1 -0
  159. package/src/shared/url-utils/interface.ts +56 -0
  160. package/src/{core → shared}/url-utils/url-utils.html +4 -1
  161. package/src/{core → shared}/url-utils/url-utils.js +26 -23
  162. package/src/{core → shared}/url-utils/url-utils.spec.js +0 -8
  163. package/src/{core → shared}/url-utils/url-utils.test.js +1 -1
  164. package/src/shared/utils.js +47 -1
  165. package/utils/express.js +9 -1
  166. package/@types/core/task-tracker-factory.d.ts +0 -76
  167. package/@types/services/browser.d.ts +0 -101
  168. package/docs/static/typedoc/types/SwapInsertPosition.html +0 -2
  169. package/jsdoc.json +0 -22
  170. package/src/core/task-tracker-factory.js +0 -145
  171. package/src/services/browser.js +0 -212
  172. /package/src/{core → services}/location/location.md +0 -0
  173. /package/src/{core → services}/sce/sce.md +0 -0
  174. /package/src/{core → shared}/url-utils/url-utils.md +0 -0
@@ -1,14 +1,32 @@
1
1
  import { Angular } from "../../loader.js";
2
2
  import { browserTrigger, wait } from "../../shared/test-utils.js";
3
+ import { dealoc } from "../../shared/dom.js";
3
4
 
4
- describe("ngGet", () => {
5
+ describe("ng-get", () => {
5
6
  let $compile, $rootScope, $log, el;
6
7
 
7
8
  beforeEach(() => {
8
9
  el = document.getElementById("app");
10
+ dealoc(el);
9
11
  el.innerHTML = "";
10
12
  let angular = new Angular();
11
- angular.module("default", []);
13
+ angular.module("default", []).config([
14
+ "$stateProvider",
15
+ "$locationProvider",
16
+ ($stateProvider) => {
17
+ $stateProvider
18
+ .state({
19
+ name: "success",
20
+ url: "/success",
21
+ template: `success`,
22
+ })
23
+ .state({
24
+ name: "error",
25
+ url: "/error",
26
+ template: `error`,
27
+ });
28
+ },
29
+ ]);
12
30
  angular
13
31
  .bootstrap(el, ["default"])
14
32
  .invoke((_$compile_, _$rootScope_, _$log_) => {
@@ -37,6 +55,16 @@ describe("ngGet", () => {
37
55
  expect(el.firstChild.innerHTML).toBe("<div>Hello</div>");
38
56
  });
39
57
 
58
+ it("should compile innerHTML", async () => {
59
+ const scope = $rootScope.$new();
60
+ el.innerHTML = '<button ng-get="/mock/divexpr">Load</button>';
61
+ scope.expr = "World";
62
+ $compile(el)(scope);
63
+ browserTrigger(el.querySelector("button"), "click");
64
+ await wait(100);
65
+ expect(el.innerText).toBe("World");
66
+ });
67
+
40
68
  it("should replace innerHTML on error", async () => {
41
69
  const scope = $rootScope.$new();
42
70
  el.innerHTML = '<button ng-get="/mock/422">Load</button>';
@@ -55,7 +83,7 @@ describe("ngGet", () => {
55
83
  expect(el.innerText).toBe("Load");
56
84
  });
57
85
 
58
- it("should replace innerHTML on statuc error without a body", async () => {
86
+ it("should replace innerHTML on status error without a body", async () => {
59
87
  const scope = $rootScope.$new();
60
88
  el.innerHTML = '<button ng-get="/mock/401">Load</button>';
61
89
  $compile(el)(scope);
@@ -64,6 +92,111 @@ describe("ngGet", () => {
64
92
  expect(el.innerText).toBe("Unauthorized");
65
93
  });
66
94
 
95
+ describe("data-trigger", () => {
96
+ it("should not trigger request on click if element has trigger attribute", async () => {
97
+ el.innerHTML =
98
+ '<button ng-get="/mock/hello" data-trigger="mouseover">Load</button>';
99
+ const scope = $rootScope.$new();
100
+ $compile(el)(scope);
101
+ browserTrigger(el.querySelector("button"), "click");
102
+ await wait(100);
103
+ expect(el.innerText).toBe("Load");
104
+ });
105
+
106
+ it("should trigger request on new event name if element has trigger attribute", async () => {
107
+ el.innerHTML =
108
+ '<button ng-get="/mock/hello" data-trigger="mouseover">Load</button>';
109
+ const scope = $rootScope.$new();
110
+ $compile(el)(scope);
111
+ browserTrigger(el.querySelector("button"), "mouseover");
112
+ await wait(100);
113
+ expect(el.innerText).toBe("Hello");
114
+ });
115
+ });
116
+
117
+ describe("data-latch", () => {
118
+ it("should trigger request on latch change", async () => {
119
+ el.innerHTML =
120
+ '<button ng-get="/mock/now" data-latch="{{ latch }}">Load</button>';
121
+ const scope = $rootScope.$new();
122
+ $compile(el)(scope);
123
+ await wait(100);
124
+ expect(el.innerText).toBe("Load");
125
+ scope.latch = true;
126
+ await wait(100);
127
+ expect(el.innerText).not.toBe("Load");
128
+ const firstRes = parseInt(el.innerText);
129
+ expect(firstRes).toBeLessThan(Date.now());
130
+
131
+ scope.latch = !scope.latch;
132
+ await wait(100);
133
+ const secondRes = parseInt(el.innerText);
134
+ expect(secondRes).toBeGreaterThan(firstRes);
135
+
136
+ scope.latch = !scope.latch;
137
+ await wait(100);
138
+ const thirdRes = parseInt(el.innerText);
139
+ expect(thirdRes).toBeGreaterThan(secondRes);
140
+ });
141
+
142
+ it("should still work with events with latch change", async () => {
143
+ el.innerHTML =
144
+ '<button ng-get="/mock/now" data-latch="{{ latch }}">Load</button>';
145
+ const scope = $rootScope.$new();
146
+ $compile(el)(scope);
147
+ await wait(100);
148
+ expect(el.innerText).toBe("Load");
149
+ scope.latch = true;
150
+ await wait(100);
151
+ expect(el.innerText).not.toBe("Load");
152
+ const firstRes = parseInt(el.innerText);
153
+ expect(firstRes).toBeLessThan(Date.now());
154
+
155
+ browserTrigger(el.querySelector("button"), "click");
156
+ await wait(100);
157
+ const secondRes = parseInt(el.innerText);
158
+ expect(secondRes).toBeGreaterThan(firstRes);
159
+ });
160
+
161
+ it("should still work with custom events with latch change", async () => {
162
+ el.innerHTML =
163
+ '<button ng-get="/mock/now" data-latch="{{ latch }}" data-trigger="mouseover">Load</button>';
164
+ const scope = $rootScope.$new();
165
+ $compile(el)(scope);
166
+ await wait(100);
167
+ expect(el.innerText).toBe("Load");
168
+ scope.latch = true;
169
+ await wait(100);
170
+ expect(el.innerText).not.toBe("Load");
171
+ const firstRes = parseInt(el.innerText);
172
+ expect(firstRes).toBeLessThan(Date.now());
173
+
174
+ browserTrigger(el.querySelector("button"), "mouseover");
175
+ await wait(100);
176
+ const secondRes = parseInt(el.innerText);
177
+ expect(secondRes).toBeGreaterThan(firstRes);
178
+ });
179
+
180
+ it("should still work with ng-event directives with latch change", async () => {
181
+ el.innerHTML =
182
+ '<button ng-get="/mock/now" data-latch="{{ latch }}" ng-mouseover="latch = !latch">Load</button>';
183
+ const scope = $rootScope.$new();
184
+ $compile(el)(scope);
185
+ await wait(100);
186
+ expect(el.innerText).toBe("Load");
187
+ browserTrigger(el.querySelector("button"), "mouseover");
188
+ await wait(100);
189
+ expect(el.innerText).not.toBe("Load");
190
+ const firstRes = parseInt(el.innerText);
191
+ expect(firstRes).toBeLessThan(Date.now());
192
+
193
+ browserTrigger(el.querySelector("button"), "mouseover");
194
+ await wait(100);
195
+ const secondRes = parseInt(el.innerText);
196
+ expect(secondRes).toBeGreaterThan(firstRes);
197
+ });
198
+ });
199
+
67
200
  describe("data-swap", () => {
68
201
  it("should not change anything if swap is 'none'", async () => {
69
202
  const scope = $rootScope.$new();
@@ -208,4 +341,148 @@ describe("ngGet", () => {
208
341
  expect(el.lastChild.textContent).toBe("Hello");
209
342
  });
210
343
  });
344
+
345
+ describe("data-delay", () => {
346
+ it("should accept delay as a data attribute", async () => {
347
+ const scope = $rootScope.$new();
348
+ el.innerHTML =
349
+ '<button ng-get="/mock/hello" data-delay="1000">Load</button>';
350
+ $compile(el)(scope);
351
+ browserTrigger(el.querySelector("button"), "click");
352
+ await wait(100);
353
+ expect(el.innerText).toBe("Load");
354
+
355
+ await wait(1000);
356
+ expect(el.innerText).toBe("Hello");
357
+ });
358
+ });
359
+
360
+ describe("data-throttle", () => {
361
+ it("should accept throttle as a data attribute", async () => {
362
+ const scope = $rootScope.$new();
363
+ el.innerHTML =
364
+ '<button ng-get="/mock/now" data-throttle="1000">Load</button>';
365
+ $compile(el)(scope);
366
+ browserTrigger(el.querySelector("button"), "click");
367
+ await wait(100);
368
+ const firstRes = parseInt(el.innerText);
369
+ expect(firstRes).toBeLessThan(Date.now());
370
+ browserTrigger(el.querySelector("button"), "click");
371
+ await wait(100);
372
+ const secondRes = parseInt(el.innerText);
373
+ expect(secondRes).toBe(firstRes);
374
+
375
+ await wait(900);
376
+ // should release the throttle
377
+ browserTrigger(el.querySelector("button"), "click");
378
+ await wait(100);
379
+ const thirdRes = parseInt(el.innerText);
380
+ expect(thirdRes).toBeGreaterThan(firstRes);
381
+ });
382
+ });
383
+
384
+ describe("data-interval", () => {
385
+ it("should accept delay as a data attribute and should stop on $destroy", async () => {
386
+ const scope = $rootScope.$new();
387
+ el.innerHTML =
388
+ '<button ng-get="/mock/now" data-interval="100">Load</button>';
389
+ $compile(el)(scope);
390
+
391
+ await wait(200);
392
+ await wait(200);
393
+ const firstRes = parseInt(el.innerText);
394
+ expect(firstRes).toBeLessThan(Date.now());
395
+ await wait(200);
396
+ await wait(200);
397
+ const secondRes = parseInt(el.innerText);
398
+ expect(secondRes).toBeGreaterThan(firstRes);
399
+ await wait(200);
400
+ await wait(200);
401
+ const thirdRes = parseInt(el.innerText);
402
+ expect(thirdRes).toBeGreaterThan(secondRes);
403
+
404
+ scope.$broadcast("$destroy");
405
+
406
+ await wait(200);
407
+ await wait(200);
408
+ const finalRes = parseInt(el.innerText);
409
+
410
+ await wait(1000);
411
+ await wait(200);
412
+ expect(parseInt(el.innerText)).toEqual(finalRes);
413
+ });
414
+ });
415
+
416
+ describe("data-loading", () => {
417
+ it("should update loading data attribute", async () => {
418
+ const scope = $rootScope.$new();
419
+ el.innerHTML = '<button ng-get="/mock/now" data-loading>Load</button>';
420
+ $compile(el)(scope);
421
+ browserTrigger(el.querySelector("button"), "click");
422
+ expect(el.querySelector("button").dataset.loading).toEqual("true");
423
+ await wait(200);
424
+ expect(el.querySelector("button").dataset.loading).toEqual("false");
425
+ });
426
+ });
427
+
428
+ describe("data-loading-class", () => {
429
+ it("should update class from data-loading-class attribute", async () => {
430
+ const scope = $rootScope.$new();
431
+ el.innerHTML =
432
+ '<button ng-get="/mock/now" data-loading-class="red">Load</button>';
433
+ $compile(el)(scope);
434
+ browserTrigger(el.querySelector("button"), "click");
435
+ expect(el.querySelector("button").classList.contains("red")).toBeTrue();
436
+ await wait(200);
437
+ expect(el.querySelector("button").classList.contains("red")).toBeFalse();
438
+ });
439
+ });
440
+
441
+ describe("data-success", () => {
442
+ it("should evaluate expression passing result", async () => {
443
+ const scope = $rootScope.$new();
444
+ el.innerHTML =
445
+ '<button ng-get="/mock/hello" data-success="res = $res">Load</button>';
446
+ $compile(el)(scope);
447
+ browserTrigger(el.querySelector("button"), "click");
448
+ await wait(200);
449
+ expect(scope.res).toEqual("Hello");
450
+ });
451
+ });
452
+
453
+ describe("data-state-success", () => {
454
+ it("should call stateService with success state", async () => {
455
+ const scope = $rootScope.$new();
456
+ el.innerHTML =
457
+ '<button ng-get="/mock/hello" data-state-success="success">Load</button><ng-view id="view"></ng-view>';
458
+ $compile(el)(scope);
459
+ browserTrigger(el.querySelector("button"), "click");
460
+ await wait(200);
461
+ expect(document.getElementById("view").innerHTML).toEqual("success");
462
+ });
463
+ });
464
+
465
+ describe("data-state-error", () => {
466
+ it("should call stateService with success state", async () => {
467
+ const scope = $rootScope.$new();
468
+ el.innerHTML =
469
+ '<button ng-get="/mock/422" data-state-success="success" data-state-error="error">Load</button><ng-view id="view"></ng-view>';
470
+ $compile(el)(scope);
471
+ browserTrigger(el.querySelector("button"), "click");
472
+ await wait(200);
473
+ expect(document.getElementById("view").innerHTML).toEqual("error");
474
+ });
475
+ });
476
+
477
+ describe("data-error", () => {
478
+ it("should evaluate expression passing result", async () => {
479
+ const scope = $rootScope.$new();
480
+ el.innerHTML =
481
+ '<button ng-get="/mock/422" data-error="res = $res">Load</button>';
482
+ $compile(el)(scope);
483
+ browserTrigger(el.querySelector("button"), "click");
484
+ await wait(200);
485
+ expect(scope.res).toEqual("Invalid data");
486
+ });
487
+ });
211
488
  });
@@ -1,4 +1,10 @@
1
- import { isObject } from "../../shared/utils.js";
1
+ import { $injectTokens as $ } from "../../injection-tokens.js";
2
+ import {
3
+ callBackAfterFirst,
4
+ isDefined,
5
+ isObject,
6
+ wait,
7
+ } from "../../shared/utils.js";
2
8
 
3
9
  /**
4
10
  * @param {"get" | "delete" | "post" | "put"} method
@@ -7,13 +13,20 @@ import { isObject } from "../../shared/utils.js";
7
13
  function defineDirective(method) {
8
14
  const attrName = "ng" + method.charAt(0).toUpperCase() + method.slice(1);
9
15
  const directive = createHttpDirective(method, attrName);
10
- directive["$inject"] = ["$http", "$compile", "$log"];
16
+ directive["$inject"] = [$.$http, $.$compile, $.$log, $.$parse, $.$state];
11
17
  return directive;
12
18
  }
13
19
 
20
+ /** @type {import('../../interface.ts').DirectiveFactory} */
14
21
  export const ngGetDirective = defineDirective("get");
22
+
23
+ /** @type {import('../../interface.ts').DirectiveFactory} */
15
24
  export const ngDeleteDirective = defineDirective("delete");
25
+
26
+ /** @type {import('../../interface.ts').DirectiveFactory} */
16
27
  export const ngPostDirective = defineDirective("post");
28
+
29
+ /** @type {import('../../interface.ts').DirectiveFactory} */
17
30
  export const ngPutDirective = defineDirective("put");
18
31
 
19
32
  /**
@@ -40,7 +53,7 @@ export function getEventNameForElement(element) {
40
53
  * Handles DOM manipulation based on a swap strategy and server-rendered HTML.
41
54
  *
42
55
  * @param {string} html - The HTML string returned from the server.
43
- * @param {import("../../interface.ts").SwapInsertPosition} swap
56
+ * @param {import("../../interface.ts").SwapModeType} swap
44
57
  * @param {Element} target - The target DOM element to apply the swap to.
45
58
  * @param {import('../../core/scope/scope.js').Scope} scope
46
59
  * @param {import('../../core/compile/compile.js').CompileFn} $compile
@@ -131,9 +144,11 @@ export function createHttpDirective(method, attrName) {
131
144
  * @param {import("interface.ts").HttpService} $http
132
145
  * @param {import("../../core/compile/compile.js").CompileFn} $compile
133
146
  * @param {import("../../services/log/interface.ts").LogService} $log
147
+ * @param {import("../../core/parse/interface.ts").ParseService} $parse
148
+ * @param {import("../../router/state/state-service.js").StateProvider} $state
134
149
  * @returns {import('../../interface.ts').Directive}
135
150
  */
136
- return function ($http, $compile, $log) {
151
+ return function ($http, $compile, $log, $parse, $state) {
137
152
  /**
138
153
  * Collects form data from the element or its associated form.
139
154
  *
@@ -194,16 +209,38 @@ export function createHttpDirective(method, attrName) {
194
209
  restrict: "A",
195
210
  terminal: true,
196
211
  link(scope, element, attrs) {
197
- /** @type {EventType} */
198
- const eventName = getEventNameForElement(element);
212
+ const eventName =
213
+ attrs["trigger"] ||
214
+ /** @type {EventType} */ getEventNameForElement(element);
215
+
199
216
  const tag = element.tagName.toLowerCase();
200
217
 
201
- element.addEventListener(eventName, (event) => {
218
+ if (isDefined(attrs["latch"])) {
219
+ attrs.$observe(
220
+ "latch",
221
+ callBackAfterFirst(() =>
222
+ element.dispatchEvent(new Event(eventName)),
223
+ ),
224
+ );
225
+ }
226
+
227
+ let throttled = false;
228
+ let intervalId;
229
+
230
+ if (isDefined(attrs["interval"])) {
231
+ element.dispatchEvent(new Event(eventName));
232
+ intervalId = setInterval(
233
+ () => element.dispatchEvent(new Event(eventName)),
234
+ parseInt(attrs["interval"]) || 1000,
235
+ );
236
+ }
237
+
238
+ element.addEventListener(eventName, async (event) => {
202
239
  if (/** @type {HTMLButtonElement} */ (element).disabled) return;
203
240
  if (tag === "form") event.preventDefault();
204
241
 
205
- const swap = element.dataset.swap || "innerHTML";
206
- const targetSelector = element.dataset.target;
242
+ const swap = attrs["swap"] || "innerHTML";
243
+ const targetSelector = attrs["target"];
207
244
  const target = targetSelector
208
245
  ? document.querySelector(targetSelector)
209
246
  : element;
@@ -220,18 +257,67 @@ export function createHttpDirective(method, attrName) {
220
257
  }
221
258
 
222
259
  const handler = (res) => {
260
+ if (isDefined(attrs["loading"])) {
261
+ attrs.$set("loading", false);
262
+ }
263
+
264
+ if (isDefined(attrs["loadingClass"])) {
265
+ attrs.$removeClass(attrs["loadingClass"]);
266
+ }
267
+
223
268
  const html = res.data;
269
+ if (200 <= res.status && res.status <= 299) {
270
+ if (isDefined(attrs["success"])) {
271
+ $parse(attrs["success"])(scope, { $res: html });
272
+ }
273
+
274
+ if (isDefined(attrs["stateSuccess"])) {
275
+ $state.go(attrs["stateSuccess"]);
276
+ }
277
+ } else if (400 <= res.status && res.status <= 599) {
278
+ if (isDefined(attrs["error"])) {
279
+ $parse(attrs["error"])(scope, { $res: html });
280
+ }
281
+
282
+ if (isDefined(attrs["stateError"])) {
283
+ $state.go(attrs["stateError"]);
284
+ }
285
+ }
286
+
224
287
  handleSwapResponse(
225
288
  html,
226
- /** @type {import("../../interface.ts").SwapInsertPosition} */ (
227
- swap
228
- ),
289
+ /** @type {import("../../interface.ts").SwapModeType} */ (swap),
229
290
  target,
230
291
  scope,
231
292
  $compile,
232
293
  );
233
294
  };
234
295
 
296
+ if (isDefined(attrs["delay"])) {
297
+ await wait(parseInt(attrs["delay"]) | 0);
298
+ }
299
+
300
+ if (throttled) {
301
+ return;
302
+ }
303
+
304
+ if (isDefined(attrs["throttle"])) {
305
+ throttled = true;
306
+ attrs.$set("throttled", true);
307
+ setTimeout(() => {
308
+ attrs.$set("throttled", false);
309
+ throttled = false;
310
+ }, parseInt(attrs["throttle"]));
311
+ }
312
+
313
+ if (isDefined(attrs["loading"])) {
314
+ attrs.$set("loading", true);
315
+ }
316
+
317
+ if (isDefined(attrs["loadingClass"])) {
318
+ attrs.$addClass(attrs["loadingClass"]);
319
+ }
320
+
235
321
  if (method === "post" || method === "put") {
236
322
  const data = collectFormData(element);
237
323
  $http[method](url, data).then(handler).catch(handler);
@@ -239,6 +325,8 @@ export function createHttpDirective(method, attrName) {
239
325
  $http[method](url).then(handler).catch(handler);
240
326
  }
241
327
  });
328
+
329
+ scope.$on("$destroy", () => clearInterval(intervalId));
242
330
  },
243
331
  };
244
332
  };
@@ -1,11 +1,11 @@
1
1
  import { test, expect } from "@playwright/test";
2
2
 
3
- const TEST_URL = "src/directive/http/http.html";
3
+ const TEST_URL = "src/directive/http/http.html?random=false";
4
4
 
5
5
  test("unit tests contain no errors", async ({ page }) => {
6
6
  await page.goto(TEST_URL);
7
7
  await page.content();
8
- await page.waitForTimeout(3000);
8
+ await page.waitForTimeout(10000);
9
9
  await expect(page.locator(".jasmine-overall-result")).toHaveText(
10
10
  /0 failures/,
11
11
  );
@@ -1,4 +1,5 @@
1
1
  import { Angular } from "../../loader.js";
2
+ import { dealoc } from "../../shared/dom.js";
2
3
  // import { browserTrigger, wait } from "../../shared/test-utils.js";
3
4
 
4
5
  describe("ngPost", () => {
@@ -6,6 +7,7 @@ describe("ngPost", () => {
6
7
 
7
8
  beforeEach(() => {
8
9
  el = document.getElementById("app");
10
+ dealoc(el);
9
11
  el.innerHTML = "";
10
12
  let angular = new Angular();
11
13
  angular.module("default", []);
@@ -1,4 +1,5 @@
1
1
  import { Angular } from "../../loader.js";
2
+ import { dealoc } from "../../shared/dom.js";
2
3
  // import { browserTrigger, wait } from "../../shared/test-utils.js";
3
4
 
4
5
  describe("ngPut", () => {
@@ -6,6 +7,7 @@ describe("ngPut", () => {
6
7
 
7
8
  beforeEach(() => {
8
9
  el = document.getElementById("app");
10
+ dealoc(el);
9
11
  el.innerHTML = "";
10
12
  let angular = new Angular();
11
13
  angular.module("default", []);
@@ -1,12 +1,12 @@
1
1
  import { isDefined } from "../../shared/utils.js";
2
2
  import { hasAnimate } from "../../shared/utils.js";
3
- import { $injectTokens } from "../../injection-tokens.js";
3
+ import { $injectTokens as $t } from "../../injection-tokens.js";
4
4
 
5
5
  ngIncludeDirective.$inject = [
6
- $injectTokens.$templateRequest,
7
- $injectTokens.$anchorScroll,
8
- $injectTokens.$animate,
9
- $injectTokens.$exceptionHandler,
6
+ $t.$templateRequest,
7
+ $t.$anchorScroll,
8
+ $t.$animate,
9
+ $t.$exceptionHandler,
10
10
  ];
11
11
 
12
12
  /**
@@ -14,7 +14,7 @@ ngIncludeDirective.$inject = [
14
14
  * @param {*} $templateRequest
15
15
  * @param {import("../../services/anchor-scroll.js").AnchorScrollFunction} $anchorScroll
16
16
  * @param {*} $animate
17
- * @param {import('../../core/error-handler.js').ErrorHandler} $exceptionHandler
17
+ * @param {import('../../services/exception/interface.ts').Interface} $exceptionHandler
18
18
  * @returns {import('../../interface.js').Directive}
19
19
  */
20
20
  export function ngIncludeDirective(
@@ -133,7 +133,7 @@ export function ngIncludeDirective(
133
133
  // We need this directive so that the element content is already filled when
134
134
  // the link function of another directive on the same element as ngInclude
135
135
  // is called.
136
- ngIncludeFillContentDirective.$inject = ["$compile"];
136
+ ngIncludeFillContentDirective.$inject = [$t.$compile];
137
137
 
138
138
  /**
139
139
  * @param {import("../../core/compile/compile.js").CompileFn} $compile
@@ -323,7 +323,6 @@ export function createDateInputType(type, regexp, parseDate) {
323
323
  element,
324
324
  attr,
325
325
  ctrl,
326
- $browser,
327
326
  $filter,
328
327
  $parse,
329
328
  ) {
@@ -610,15 +609,7 @@ export function isValidForStep(viewValue, stepBase, step) {
610
609
  return (value - stepBase) % step === 0;
611
610
  }
612
611
 
613
- export function numberInputType(
614
- scope,
615
- element,
616
- attr,
617
- ctrl,
618
- $browser,
619
- $filter,
620
- $parse,
621
- ) {
612
+ export function numberInputType(scope, element, attr, ctrl, $filter, $parse) {
622
613
  badInputChecker(scope, element, attr, ctrl, "number");
623
614
  numberFormatterParser(ctrl);
624
615
  baseInputType(scope, element, attr, ctrl);
@@ -934,15 +925,7 @@ function parseConstantExpr($parse, context, name, expression, fallback) {
934
925
  return fallback;
935
926
  }
936
927
 
937
- function checkboxInputType(
938
- scope,
939
- element,
940
- attr,
941
- ctrl,
942
- $browser,
943
- $filter,
944
- $parse,
945
- ) {
928
+ function checkboxInputType(scope, element, attr, ctrl, $filter, $parse) {
946
929
  const trueValue = parseConstantExpr(
947
930
  $parse,
948
931
  scope,
@@ -980,30 +963,25 @@ function checkboxInputType(
980
963
  ctrl.$parsers.push((value) => (value ? trueValue : falseValue));
981
964
  }
982
965
 
983
- /**
984
- * @returns {import('../../interface.ts').Directive}
985
- */
986
- inputDirective.$inject = ["$browser", "$filter", "$parse"];
966
+ inputDirective.$inject = ["$filter", "$parse"];
987
967
 
988
968
  /**
989
- * @param {import('../../services/browser').Browser} $browser
990
969
  * @param {*} $filter
991
970
  * @param {*} $parse
992
- * @returns
971
+ * @returns {import('../../interface.ts').Directive}
993
972
  */
994
- export function inputDirective($browser, $filter, $parse) {
973
+ export function inputDirective($filter, $parse) {
995
974
  return {
996
975
  restrict: "E",
997
976
  require: ["?ngModel"],
998
977
  link: {
999
978
  pre(scope, element, attr, ctrls) {
1000
979
  if (ctrls[0]) {
1001
- (inputType[lowercase(attr.type)] || inputType.text)(
980
+ (inputType[lowercase(attr["type"])] || inputType.text)(
1002
981
  scope,
1003
982
  element,
1004
983
  attr,
1005
984
  ctrls[0],
1006
- $browser,
1007
985
  $filter,
1008
986
  $parse,
1009
987
  );
@@ -103,7 +103,7 @@ class NgMessageCtrl {
103
103
  reRender() {
104
104
  if (!this.renderLater) {
105
105
  this.renderLater = true;
106
- this.$scope.$evalAsync(() => {
106
+ Promise.resolve().then(() => {
107
107
  if (this.renderLater && this.cachedCollection) {
108
108
  this.render(this.cachedCollection);
109
109
  }
@@ -238,6 +238,10 @@ export const ngMessageDirective = ngMessageDirectiveFactory(false);
238
238
  export const ngMessageExpDirective = ngMessageDirectiveFactory(false);
239
239
  export const ngMessageDefaultDirective = ngMessageDirectiveFactory(true);
240
240
 
241
+ /**
242
+ * @param {boolean} isDefault
243
+ * @returns {(any) => import("../../interface.js").Directive}
244
+ */
241
245
  function ngMessageDirectiveFactory(isDefault) {
242
246
  ngMessageDirective.$inject = ["$animate"];
243
247
  function ngMessageDirective($animate) {
@@ -78,7 +78,7 @@ export class NgModelController {
78
78
 
79
79
  /**
80
80
  * @param {import('../../core/scope/scope.js').Scope} $scope
81
- * @param {import('../../core/exception-handler.js').ErrorHandler} $exceptionHandler
81
+ * @param {import('../../services/exception/exception-handler.js').ErrorHandler} $exceptionHandler
82
82
  * @param {import('../../core/compile/attributes.js').Attributes} $attr
83
83
  * @param {Element} $element
84
84
  * @param {import("../../core/parse/interface.ts").ParseService} $parse