@angular-wave/angular.ts 0.0.1

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 (231) hide show
  1. package/.eslintignore +1 -0
  2. package/.eslintrc.cjs +29 -0
  3. package/.github/workflows/playwright.yml +27 -0
  4. package/CHANGELOG.md +17974 -0
  5. package/CODE_OF_CONDUCT.md +3 -0
  6. package/CONTRIBUTING.md +246 -0
  7. package/DEVELOPERS.md +488 -0
  8. package/LICENSE +22 -0
  9. package/Makefile +31 -0
  10. package/README.md +115 -0
  11. package/RELEASE.md +98 -0
  12. package/SECURITY.md +16 -0
  13. package/TRIAGING.md +135 -0
  14. package/css/angular.css +22 -0
  15. package/dist/angular-ts.cjs.js +36843 -0
  16. package/dist/angular-ts.esm.js +36841 -0
  17. package/dist/angular-ts.umd.js +36848 -0
  18. package/dist/build/angular-animate.js +4272 -0
  19. package/dist/build/angular-aria.js +426 -0
  20. package/dist/build/angular-message-format.js +1072 -0
  21. package/dist/build/angular-messages.js +829 -0
  22. package/dist/build/angular-mocks.js +3757 -0
  23. package/dist/build/angular-parse-ext.js +1275 -0
  24. package/dist/build/angular-resource.js +911 -0
  25. package/dist/build/angular-route.js +1266 -0
  26. package/dist/build/angular-sanitize.js +891 -0
  27. package/dist/build/angular-touch.js +368 -0
  28. package/dist/build/angular.js +36600 -0
  29. package/e2e/unit.spec.ts +15 -0
  30. package/images/android-chrome-192x192.png +0 -0
  31. package/images/android-chrome-512x512.png +0 -0
  32. package/images/apple-touch-icon.png +0 -0
  33. package/images/favicon-16x16.png +0 -0
  34. package/images/favicon-32x32.png +0 -0
  35. package/images/favicon.ico +0 -0
  36. package/images/site.webmanifest +1 -0
  37. package/index.html +104 -0
  38. package/package.json +47 -0
  39. package/playwright.config.ts +78 -0
  40. package/public/circle.html +1 -0
  41. package/public/my_child_directive.html +1 -0
  42. package/public/my_directive.html +1 -0
  43. package/public/my_other_directive.html +1 -0
  44. package/public/test.html +1 -0
  45. package/rollup.config.js +31 -0
  46. package/src/animations/animateCache.js +55 -0
  47. package/src/animations/animateChildrenDirective.js +105 -0
  48. package/src/animations/animateCss.js +1139 -0
  49. package/src/animations/animateCssDriver.js +291 -0
  50. package/src/animations/animateJs.js +367 -0
  51. package/src/animations/animateJsDriver.js +67 -0
  52. package/src/animations/animateQueue.js +851 -0
  53. package/src/animations/animation.js +506 -0
  54. package/src/animations/module.js +779 -0
  55. package/src/animations/ngAnimateSwap.js +119 -0
  56. package/src/animations/rafScheduler.js +50 -0
  57. package/src/animations/shared.js +378 -0
  58. package/src/constants.js +20 -0
  59. package/src/core/animate.js +845 -0
  60. package/src/core/animateCss.js +73 -0
  61. package/src/core/animateRunner.js +195 -0
  62. package/src/core/attributes.js +199 -0
  63. package/src/core/cache.js +45 -0
  64. package/src/core/compile.js +4727 -0
  65. package/src/core/controller.js +225 -0
  66. package/src/core/exceptionHandler.js +63 -0
  67. package/src/core/filter.js +146 -0
  68. package/src/core/interpolate.js +442 -0
  69. package/src/core/interval.js +188 -0
  70. package/src/core/intervalFactory.js +57 -0
  71. package/src/core/location.js +1086 -0
  72. package/src/core/parser/parse.js +2562 -0
  73. package/src/core/parser/parse.md +13 -0
  74. package/src/core/q.js +746 -0
  75. package/src/core/rootScope.js +1596 -0
  76. package/src/core/sanitizeUri.js +85 -0
  77. package/src/core/sce.js +1161 -0
  78. package/src/core/taskTrackerFactory.js +125 -0
  79. package/src/core/timeout.js +121 -0
  80. package/src/core/urlUtils.js +187 -0
  81. package/src/core/utils.js +1349 -0
  82. package/src/directive/a.js +37 -0
  83. package/src/directive/attrs.js +283 -0
  84. package/src/directive/bind.js +51 -0
  85. package/src/directive/bind.md +142 -0
  86. package/src/directive/change.js +12 -0
  87. package/src/directive/change.md +25 -0
  88. package/src/directive/cloak.js +12 -0
  89. package/src/directive/cloak.md +24 -0
  90. package/src/directive/events.js +75 -0
  91. package/src/directive/events.md +166 -0
  92. package/src/directive/form.js +725 -0
  93. package/src/directive/init.js +15 -0
  94. package/src/directive/init.md +41 -0
  95. package/src/directive/input.js +1783 -0
  96. package/src/directive/list.js +46 -0
  97. package/src/directive/list.md +22 -0
  98. package/src/directive/ngClass.js +249 -0
  99. package/src/directive/ngController.js +64 -0
  100. package/src/directive/ngCsp.js +82 -0
  101. package/src/directive/ngIf.js +134 -0
  102. package/src/directive/ngInclude.js +217 -0
  103. package/src/directive/ngModel.js +1356 -0
  104. package/src/directive/ngModelOptions.js +509 -0
  105. package/src/directive/ngOptions.js +670 -0
  106. package/src/directive/ngRef.js +90 -0
  107. package/src/directive/ngRepeat.js +650 -0
  108. package/src/directive/ngShowHide.js +255 -0
  109. package/src/directive/ngSwitch.js +178 -0
  110. package/src/directive/ngTransclude.js +98 -0
  111. package/src/directive/non-bindable.js +11 -0
  112. package/src/directive/non-bindable.md +17 -0
  113. package/src/directive/script.js +30 -0
  114. package/src/directive/select.js +624 -0
  115. package/src/directive/style.js +25 -0
  116. package/src/directive/style.md +23 -0
  117. package/src/directive/validators.js +329 -0
  118. package/src/exts/aria.js +544 -0
  119. package/src/exts/messages.js +852 -0
  120. package/src/filters/filter.js +207 -0
  121. package/src/filters/filter.md +69 -0
  122. package/src/filters/filters.js +239 -0
  123. package/src/filters/json.md +16 -0
  124. package/src/filters/limit-to.js +43 -0
  125. package/src/filters/limit-to.md +19 -0
  126. package/src/filters/order-by.js +183 -0
  127. package/src/filters/order-by.md +83 -0
  128. package/src/index.js +13 -0
  129. package/src/injector.js +1034 -0
  130. package/src/jqLite.js +1117 -0
  131. package/src/loader.js +1320 -0
  132. package/src/public.js +215 -0
  133. package/src/routeToRegExp.js +41 -0
  134. package/src/services/anchorScroll.js +135 -0
  135. package/src/services/browser.js +321 -0
  136. package/src/services/cacheFactory.js +398 -0
  137. package/src/services/cookieReader.js +72 -0
  138. package/src/services/document.js +64 -0
  139. package/src/services/http.js +1537 -0
  140. package/src/services/httpBackend.js +206 -0
  141. package/src/services/log.js +160 -0
  142. package/src/services/templateRequest.js +139 -0
  143. package/test/angular.spec.js +2153 -0
  144. package/test/aria/aria.spec.js +1245 -0
  145. package/test/binding.spec.js +504 -0
  146. package/test/build-test.html +14 -0
  147. package/test/injector.spec.js +2327 -0
  148. package/test/jasmine/jasmine-5.1.2/boot0.js +65 -0
  149. package/test/jasmine/jasmine-5.1.2/boot1.js +133 -0
  150. package/test/jasmine/jasmine-5.1.2/jasmine-html.js +963 -0
  151. package/test/jasmine/jasmine-5.1.2/jasmine.css +320 -0
  152. package/test/jasmine/jasmine-5.1.2/jasmine.js +10824 -0
  153. package/test/jasmine/jasmine-5.1.2/jasmine_favicon.png +0 -0
  154. package/test/jasmine/jasmine-browser.json +17 -0
  155. package/test/jasmine/jasmine.json +9 -0
  156. package/test/jqlite.spec.js +2133 -0
  157. package/test/loader.spec.js +219 -0
  158. package/test/messages/messages.spec.js +1146 -0
  159. package/test/min-err.spec.js +174 -0
  160. package/test/mock-test.html +13 -0
  161. package/test/module-test.html +15 -0
  162. package/test/ng/anomate.spec.js +606 -0
  163. package/test/ng/cache-factor.spec.js +334 -0
  164. package/test/ng/compile.spec.js +17956 -0
  165. package/test/ng/controller-provider.spec.js +227 -0
  166. package/test/ng/cookie-reader.spec.js +98 -0
  167. package/test/ng/directive/a.spec.js +192 -0
  168. package/test/ng/directive/bind.spec.js +334 -0
  169. package/test/ng/directive/boolean.spec.js +136 -0
  170. package/test/ng/directive/change.spec.js +71 -0
  171. package/test/ng/directive/class.spec.js +858 -0
  172. package/test/ng/directive/click.spec.js +38 -0
  173. package/test/ng/directive/cloak.spec.js +44 -0
  174. package/test/ng/directive/constoller.spec.js +194 -0
  175. package/test/ng/directive/element-style.spec.js +92 -0
  176. package/test/ng/directive/event.spec.js +282 -0
  177. package/test/ng/directive/form.spec.js +1518 -0
  178. package/test/ng/directive/href.spec.js +143 -0
  179. package/test/ng/directive/if.spec.js +402 -0
  180. package/test/ng/directive/include.spec.js +828 -0
  181. package/test/ng/directive/init.spec.js +68 -0
  182. package/test/ng/directive/input.spec.js +3810 -0
  183. package/test/ng/directive/list.spec.js +170 -0
  184. package/test/ng/directive/model-options.spec.js +1008 -0
  185. package/test/ng/directive/model.spec.js +1905 -0
  186. package/test/ng/directive/non-bindable.spec.js +55 -0
  187. package/test/ng/directive/options.spec.js +3583 -0
  188. package/test/ng/directive/ref.spec.js +575 -0
  189. package/test/ng/directive/repeat.spec.js +1675 -0
  190. package/test/ng/directive/script.spec.js +52 -0
  191. package/test/ng/directive/scrset.spec.js +67 -0
  192. package/test/ng/directive/select.spec.js +2541 -0
  193. package/test/ng/directive/show-hide.spec.js +253 -0
  194. package/test/ng/directive/src.spec.js +157 -0
  195. package/test/ng/directive/style.spec.js +178 -0
  196. package/test/ng/directive/switch.spec.js +647 -0
  197. package/test/ng/directive/validators.spec.js +717 -0
  198. package/test/ng/document.spec.js +52 -0
  199. package/test/ng/filter/filter.spec.js +714 -0
  200. package/test/ng/filter/filters.spec.js +35 -0
  201. package/test/ng/filter/limit-to.spec.js +251 -0
  202. package/test/ng/filter/order-by.spec.js +891 -0
  203. package/test/ng/filter.spec.js +149 -0
  204. package/test/ng/http-backend.spec.js +398 -0
  205. package/test/ng/http.spec.js +4071 -0
  206. package/test/ng/interpolate.spec.js +642 -0
  207. package/test/ng/interval.spec.js +343 -0
  208. package/test/ng/location.spec.js +3488 -0
  209. package/test/ng/on.spec.js +229 -0
  210. package/test/ng/parse.spec.js +4655 -0
  211. package/test/ng/prop.spec.js +805 -0
  212. package/test/ng/q.spec.js +2904 -0
  213. package/test/ng/root-element.spec.js +16 -0
  214. package/test/ng/sanitize-uri.spec.js +249 -0
  215. package/test/ng/sce.spec.js +660 -0
  216. package/test/ng/scope.spec.js +3442 -0
  217. package/test/ng/template-request.spec.js +236 -0
  218. package/test/ng/timeout.spec.js +351 -0
  219. package/test/ng/url-utils.spec.js +156 -0
  220. package/test/ng/utils.spec.js +144 -0
  221. package/test/original-test.html +21 -0
  222. package/test/public.spec.js +34 -0
  223. package/test/sanitize/bing-html.spec.js +36 -0
  224. package/test/server/express.js +158 -0
  225. package/test/test-utils.js +11 -0
  226. package/tsconfig.json +17 -0
  227. package/types/angular.d.ts +138 -0
  228. package/types/global.d.ts +9 -0
  229. package/types/index.d.ts +2357 -0
  230. package/types/jqlite.d.ts +558 -0
  231. package/vite.config.js +14 -0
@@ -0,0 +1,858 @@
1
+ import { dealoc, jqLite } from "../../../src/jqLite";
2
+ import { publishExternalAPI } from "../../../src/public";
3
+ import { createInjector } from "../../../src/injector";
4
+ import { valueFn } from "../../../src/core/utils";
5
+
6
+ describe("ngClass", () => {
7
+ let element;
8
+ let $compile;
9
+ let $rootScope;
10
+ let injector;
11
+
12
+ beforeEach(() => {
13
+ publishExternalAPI();
14
+ injector = createInjector(["ng"]);
15
+ $compile = injector.get("$compile");
16
+ $rootScope = injector.get("$rootScope");
17
+ });
18
+
19
+ afterEach(() => {
20
+ dealoc(element);
21
+ });
22
+
23
+ it("should add new and remove old classes dynamically", () => {
24
+ element = $compile('<div class="existing" ng-class="dynClass"></div>')(
25
+ $rootScope,
26
+ );
27
+ $rootScope.dynClass = "A";
28
+ $rootScope.$digest();
29
+ expect(element[0].classList.contains("existing")).toBe(true);
30
+ expect(element[0].classList.contains("A")).toBe(true);
31
+
32
+ $rootScope.dynClass = "B";
33
+ $rootScope.$digest();
34
+ expect(element[0].classList.contains("existing")).toBe(true);
35
+ expect(element[0].classList.contains("A")).toBe(false);
36
+ expect(element[0].classList.contains("B")).toBe(true);
37
+
38
+ delete $rootScope.dynClass;
39
+ $rootScope.$digest();
40
+ expect(element[0].classList.contains("existing")).toBe(true);
41
+ expect(element[0].classList.contains("A")).toBe(false);
42
+ expect(element[0].classList.contains("B")).toBe(false);
43
+ });
44
+
45
+ it("should add new and remove old classes with same names as Object.prototype properties dynamically", () => {
46
+ element = $compile('<div class="existing" ng-class="dynClass"></div>')(
47
+ $rootScope,
48
+ );
49
+ $rootScope.dynClass = {
50
+ watch: true,
51
+ hasOwnProperty: true,
52
+ isPrototypeOf: true,
53
+ };
54
+ $rootScope.$digest();
55
+ expect(element[0].classList.contains("existing")).toBe(true);
56
+ expect(element[0].classList.contains("watch")).toBe(true);
57
+ expect(element[0].classList.contains("hasOwnProperty")).toBe(true);
58
+ expect(element[0].classList.contains("isPrototypeOf")).toBe(true);
59
+
60
+ $rootScope.dynClass.watch = false;
61
+ $rootScope.$digest();
62
+ expect(element[0].classList.contains("existing")).toBe(true);
63
+ expect(element[0].classList.contains("watch")).toBe(false);
64
+ expect(element[0].classList.contains("hasOwnProperty")).toBe(true);
65
+ expect(element[0].classList.contains("isPrototypeOf")).toBe(true);
66
+
67
+ delete $rootScope.dynClass;
68
+ $rootScope.$digest();
69
+ expect(element[0].classList.contains("existing")).toBe(true);
70
+ expect(element[0].classList.contains("watch")).toBe(false);
71
+ expect(element[0].classList.contains("hasOwnProperty")).toBe(false);
72
+ expect(element[0].classList.contains("isPrototypeOf")).toBe(false);
73
+ });
74
+
75
+ it("should support adding multiple classes via an array", () => {
76
+ element = $compile(
77
+ "<div class=\"existing\" ng-class=\"['A', 'B']\"></div>",
78
+ )($rootScope);
79
+ $rootScope.$digest();
80
+ expect(element[0].classList.contains("existing")).toBeTruthy();
81
+ expect(element[0].classList.contains("A")).toBeTruthy();
82
+ expect(element[0].classList.contains("B")).toBeTruthy();
83
+ });
84
+
85
+ it(
86
+ "should support adding multiple classes conditionally via a map of class names to boolean " +
87
+ "expressions",
88
+ () => {
89
+ element = $compile(
90
+ '<div class="existing" ' +
91
+ 'ng-class="{A: conditionA, B: conditionB(), AnotB: conditionA&&!conditionB()}">' +
92
+ "</div>",
93
+ )($rootScope);
94
+ $rootScope.conditionA = true;
95
+ $rootScope.$digest();
96
+ expect(element[0].classList.contains("existing")).toBeTruthy();
97
+ expect(element[0].classList.contains("A")).toBeTruthy();
98
+ expect(element[0].classList.contains("B")).toBeFalsy();
99
+ expect(element[0].classList.contains("AnotB")).toBeTruthy();
100
+
101
+ $rootScope.conditionB = function () {
102
+ return true;
103
+ };
104
+ $rootScope.$digest();
105
+ expect(element[0].classList.contains("existing")).toBeTruthy();
106
+ expect(element[0].classList.contains("A")).toBeTruthy();
107
+ expect(element[0].classList.contains("B")).toBeTruthy();
108
+ expect(element[0].classList.contains("AnotB")).toBeFalsy();
109
+ },
110
+ );
111
+
112
+ it("should not break when passed non-string/array/object, truthy values", () => {
113
+ element = $compile('<div ng-class="42"></div>')($rootScope);
114
+ $rootScope.$digest();
115
+ expect(element[0].classList.contains("42")).toBeTruthy();
116
+ });
117
+
118
+ it("should support adding multiple classes via an array mixed with conditionally via a map", () => {
119
+ element = $compile(
120
+ "<div class=\"existing\" ng-class=\"['A', {'B': condition}]\"></div>",
121
+ )($rootScope);
122
+ $rootScope.$digest();
123
+ expect(element[0].classList.contains("existing")).toBeTruthy();
124
+ expect(element[0].classList.contains("A")).toBeTruthy();
125
+ expect(element[0].classList.contains("B")).toBeFalsy();
126
+ $rootScope.condition = true;
127
+ $rootScope.$digest();
128
+ expect(element[0].classList.contains("B")).toBeTruthy();
129
+ });
130
+
131
+ it("should remove classes when the referenced object is the same but its property is changed", () => {
132
+ element = $compile('<div ng-class="classes"></div>')($rootScope);
133
+ $rootScope.classes = { A: true, B: true };
134
+ $rootScope.$digest();
135
+ expect(element[0].classList.contains("A")).toBeTruthy();
136
+ expect(element[0].classList.contains("B")).toBeTruthy();
137
+ $rootScope.classes.A = false;
138
+ $rootScope.$digest();
139
+ expect(element[0].classList.contains("A")).toBeFalsy();
140
+ expect(element[0].classList.contains("B")).toBeTruthy();
141
+ });
142
+
143
+ it("should support adding multiple classes via a space delimited string", () => {
144
+ element = $compile('<div class="existing" ng-class="\'A B\'"></div>')(
145
+ $rootScope,
146
+ );
147
+ $rootScope.$digest();
148
+ expect(element[0].classList.contains("existing")).toBeTruthy();
149
+ expect(element[0].classList.contains("A")).toBeTruthy();
150
+ expect(element[0].classList.contains("B")).toBeTruthy();
151
+ });
152
+
153
+ it("should support adding multiple classes via a space delimited string inside an array", () => {
154
+ element = $compile(
155
+ "<div class=\"existing\" ng-class=\"['A B', 'C']\"></div>",
156
+ )($rootScope);
157
+ $rootScope.$digest();
158
+ expect(element[0].classList.contains("existing")).toBeTruthy();
159
+ expect(element[0].classList.contains("A")).toBeTruthy();
160
+ expect(element[0].classList.contains("B")).toBeTruthy();
161
+ expect(element[0].classList.contains("C")).toBeTruthy();
162
+ });
163
+
164
+ it("should preserve class added post compilation with pre-existing classes", () => {
165
+ element = $compile('<div class="existing" ng-class="dynClass"></div>')(
166
+ $rootScope,
167
+ );
168
+ $rootScope.dynClass = "A";
169
+ $rootScope.$digest();
170
+ expect(element[0].classList.contains("existing")).toBe(true);
171
+
172
+ // add extra class, change model and eval
173
+ element[0].classList.add("newClass");
174
+ $rootScope.dynClass = "B";
175
+ $rootScope.$digest();
176
+
177
+ expect(element[0].classList.contains("existing")).toBe(true);
178
+ expect(element[0].classList.contains("B")).toBe(true);
179
+ expect(element[0].classList.contains("newClass")).toBe(true);
180
+ });
181
+
182
+ it('should preserve class added post compilation without pre-existing classes"', () => {
183
+ element = $compile('<div ng-class="dynClass"></div>')($rootScope);
184
+ $rootScope.dynClass = "A";
185
+ $rootScope.$digest();
186
+ expect(element[0].classList.contains("A")).toBe(true);
187
+
188
+ // add extra class, change model and eval
189
+ element[0].classList.add("newClass");
190
+ $rootScope.dynClass = "B";
191
+ $rootScope.$digest();
192
+
193
+ expect(element[0].classList.contains("B")).toBe(true);
194
+ expect(element[0].classList.contains("newClass")).toBe(true);
195
+ });
196
+
197
+ it('should preserve other classes with similar name"', () => {
198
+ element = $compile(
199
+ '<div class="ui-panel ui-selected" ng-class="dynCls"></div>',
200
+ )($rootScope);
201
+ $rootScope.dynCls = "panel";
202
+ $rootScope.$digest();
203
+ $rootScope.dynCls = "foo";
204
+ $rootScope.$digest();
205
+ expect(element[0].className).toBe("ui-panel ui-selected foo");
206
+ });
207
+
208
+ it("should not add duplicate classes", () => {
209
+ element = $compile('<div class="panel bar" ng-class="dynCls"></div>')(
210
+ $rootScope,
211
+ );
212
+ $rootScope.dynCls = "panel";
213
+ $rootScope.$digest();
214
+ expect(element[0].className).toBe("panel bar");
215
+ });
216
+
217
+ it("should remove classes even if it was specified via class attribute", () => {
218
+ element = $compile('<div class="panel bar" ng-class="dynCls"></div>')(
219
+ $rootScope,
220
+ );
221
+ $rootScope.dynCls = "panel";
222
+ $rootScope.$digest();
223
+ $rootScope.dynCls = "window";
224
+ $rootScope.$digest();
225
+ expect(element[0].className).toBe("bar window");
226
+ });
227
+
228
+ it("should remove classes even if they were added by another code", () => {
229
+ element = $compile('<div ng-class="dynCls"></div>')($rootScope);
230
+ $rootScope.dynCls = "foo";
231
+ $rootScope.$digest();
232
+ element[0].classList.add("foo");
233
+ $rootScope.dynCls = "";
234
+ $rootScope.$digest();
235
+ });
236
+
237
+ it("should convert undefined and null values to an empty string", () => {
238
+ element = $compile('<div ng-class="dynCls"></div>')($rootScope);
239
+ $rootScope.dynCls = [undefined, null];
240
+ $rootScope.$digest();
241
+ });
242
+
243
+ it("should ngClass odd/even", () => {
244
+ element = $compile(
245
+ '<ul><li ng-repeat="i in [0,1]" class="existing" ng-class-odd="\'odd\'" ng-class-even="\'even\'"></li><ul>',
246
+ )($rootScope);
247
+ $rootScope.$digest();
248
+ const e1 = jqLite(element[0].childNodes[1]);
249
+ const e2 = jqLite(element[0].childNodes[3]);
250
+ expect(e1[0].classList.contains("existing")).toBeTruthy();
251
+ expect(e1[0].classList.contains("odd")).toBeTruthy();
252
+ expect(e2[0].classList.contains("existing")).toBeTruthy();
253
+ expect(e2[0].classList.contains("even")).toBeTruthy();
254
+ });
255
+
256
+ it("should allow both ngClass and ngClassOdd/Even on the same element", () => {
257
+ element = $compile(
258
+ "<ul>" +
259
+ '<li ng-repeat="i in [0,1]" ng-class="\'plainClass\'" ' +
260
+ "ng-class-odd=\"'odd'\" ng-class-even=\"'even'\"></li>" +
261
+ "<ul>",
262
+ )($rootScope);
263
+ $rootScope.$apply();
264
+ const e1 = jqLite(element[0].childNodes[1]);
265
+ const e2 = jqLite(element[0].childNodes[3]);
266
+
267
+ expect(e1[0].classList.contains("plainClass")).toBeTruthy();
268
+ expect(e1[0].classList.contains("odd")).toBeTruthy();
269
+ expect(e1[0].classList.contains("even")).toBeFalsy();
270
+ expect(e2[0].classList.contains("plainClass")).toBeTruthy();
271
+ expect(e2[0].classList.contains("even")).toBeTruthy();
272
+ expect(e2[0].classList.contains("odd")).toBeFalsy();
273
+ });
274
+
275
+ it("should allow ngClassOdd/Even on the same element with overlapping classes", () => {
276
+ element = $compile(
277
+ "<ul>" +
278
+ '<li ng-repeat="i in [0,1,2]" ' +
279
+ "ng-class-odd=\"'same odd'\" " +
280
+ "ng-class-even=\"'same even'\">" +
281
+ "</li>" +
282
+ "<ul>",
283
+ )($rootScope);
284
+ $rootScope.$digest();
285
+
286
+ const e1 = element.children().eq(0)[0];
287
+ const e2 = element.children().eq(1)[0];
288
+ const e3 = element.children().eq(2)[0];
289
+
290
+ expect(e1).toHaveClass("same");
291
+ expect(e1).toHaveClass("odd");
292
+ expect(e1).not.toHaveClass("even");
293
+ expect(e2).toHaveClass("same");
294
+ expect(e2).not.toHaveClass("odd");
295
+ expect(e2).toHaveClass("even");
296
+ expect(e3).toHaveClass("same");
297
+ expect(e3).toHaveClass("odd");
298
+ expect(e3).not.toHaveClass("even");
299
+ });
300
+
301
+ it("should allow ngClass with overlapping classes", () => {
302
+ element = $compile(
303
+ "<div ng-class=\"{'same yes': test, 'same no': !test}\"></div>",
304
+ )($rootScope)[0];
305
+ $rootScope.$digest();
306
+
307
+ expect(element).toHaveClass("same");
308
+ expect(element).not.toHaveClass("yes");
309
+ expect(element).toHaveClass("no");
310
+
311
+ $rootScope.$apply("test = true");
312
+
313
+ expect(element).toHaveClass("same");
314
+ expect(element).toHaveClass("yes");
315
+ expect(element).not.toHaveClass("no");
316
+ });
317
+
318
+ it("should allow both ngClass and ngClassOdd/Even with multiple classes", () => {
319
+ element = $compile(
320
+ "<ul>" +
321
+ "<li ng-repeat=\"i in [0,1]\" ng-class=\"['A', 'B']\" " +
322
+ "ng-class-odd=\"['C', 'D']\" ng-class-even=\"['E', 'F']\"></li>" +
323
+ "<ul>",
324
+ )($rootScope);
325
+ $rootScope.$apply();
326
+ const e1 = jqLite(element[0].childNodes[1]);
327
+ const e2 = jqLite(element[0].childNodes[3]);
328
+
329
+ expect(e1[0].classList.contains("A")).toBeTruthy();
330
+ expect(e1[0].classList.contains("B")).toBeTruthy();
331
+ expect(e1[0].classList.contains("C")).toBeTruthy();
332
+ expect(e1[0].classList.contains("D")).toBeTruthy();
333
+ expect(e1[0].classList.contains("E")).toBeFalsy();
334
+ expect(e1[0].classList.contains("F")).toBeFalsy();
335
+
336
+ expect(e2[0].classList.contains("A")).toBeTruthy();
337
+ expect(e2[0].classList.contains("B")).toBeTruthy();
338
+ expect(e2[0].classList.contains("E")).toBeTruthy();
339
+ expect(e2[0].classList.contains("F")).toBeTruthy();
340
+ expect(e2[0].classList.contains("C")).toBeFalsy();
341
+ expect(e2[0].classList.contains("D")).toBeFalsy();
342
+ });
343
+
344
+ it("should reapply ngClass when interpolated class attribute changes", () => {
345
+ element = $compile(
346
+ "<div>" +
347
+ '<div class="one {{two}} three" ng-class="{five: five}"></div>' +
348
+ '<div class="one {{two}} three {{four}}" ng-class="{five: five}"></div>' +
349
+ "</div>",
350
+ )($rootScope);
351
+ const e1 = element.children().eq(0)[0];
352
+ const e2 = element.children().eq(1)[0];
353
+
354
+ $rootScope.$apply('two = "two"; five = true');
355
+
356
+ expect(e1).toHaveClass("one");
357
+ expect(e1).toHaveClass("two");
358
+ expect(e1).toHaveClass("three");
359
+ expect(e1).not.toHaveClass("four");
360
+ expect(e1).toHaveClass("five");
361
+ expect(e2).toHaveClass("one");
362
+ expect(e2).toHaveClass("two");
363
+ expect(e2).toHaveClass("three");
364
+ expect(e2).not.toHaveClass("four");
365
+ expect(e2).toHaveClass("five");
366
+
367
+ $rootScope.$apply('two = "another-two"');
368
+
369
+ expect(e1).toHaveClass("one");
370
+ expect(e1).not.toHaveClass("two");
371
+ expect(e1).toHaveClass("another-two");
372
+ expect(e1).toHaveClass("three");
373
+ expect(e1).not.toHaveClass("four");
374
+ expect(e1).toHaveClass("five");
375
+ expect(e2).toHaveClass("one");
376
+ expect(e2).not.toHaveClass("two");
377
+ expect(e2).toHaveClass("another-two");
378
+ expect(e2).toHaveClass("three");
379
+ expect(e2).not.toHaveClass("four");
380
+ expect(e2).toHaveClass("five");
381
+
382
+ $rootScope.$apply('two = "two-more"; four = "four"');
383
+
384
+ expect(e1).toHaveClass("one");
385
+ expect(e1).not.toHaveClass("two");
386
+ expect(e1).not.toHaveClass("another-two");
387
+ expect(e1).toHaveClass("two-more");
388
+ expect(e1).toHaveClass("three");
389
+ expect(e1).not.toHaveClass("four");
390
+ expect(e1).toHaveClass("five");
391
+ expect(e2).toHaveClass("one");
392
+ expect(e2).not.toHaveClass("two");
393
+ expect(e2).not.toHaveClass("another-two");
394
+ expect(e2).toHaveClass("two-more");
395
+ expect(e2).toHaveClass("three");
396
+ expect(e2).toHaveClass("four");
397
+ expect(e2).toHaveClass("five");
398
+
399
+ $rootScope.$apply("five = false");
400
+
401
+ expect(e1).toHaveClass("one");
402
+ expect(e1).not.toHaveClass("two");
403
+ expect(e1).not.toHaveClass("another-two");
404
+ expect(e1).toHaveClass("two-more");
405
+ expect(e1).toHaveClass("three");
406
+ expect(e1).not.toHaveClass("four");
407
+ expect(e1).not.toHaveClass("five");
408
+ expect(e2).toHaveClass("one");
409
+ expect(e2).not.toHaveClass("two");
410
+ expect(e2).not.toHaveClass("another-two");
411
+ expect(e2).toHaveClass("two-more");
412
+ expect(e2).toHaveClass("three");
413
+ expect(e2).toHaveClass("four");
414
+ expect(e2).not.toHaveClass("five");
415
+ });
416
+
417
+ it("should not mess up class value due to observing an interpolated class attribute", () => {
418
+ $rootScope.foo = true;
419
+ $rootScope.$watch("anything", () => {
420
+ $rootScope.foo = false;
421
+ });
422
+ element = $compile('<div ng-class="{foo:foo}"></div>')($rootScope);
423
+ $rootScope.$digest();
424
+ expect(element[0].classList.contains("foo")).toBe(false);
425
+ });
426
+
427
+ it("should update ngClassOdd/Even when an item is added to the model", () => {
428
+ element = $compile(
429
+ "<ul>" +
430
+ '<li ng-repeat="i in items" ' +
431
+ "ng-class-odd=\"'odd'\" ng-class-even=\"'even'\">i</li>" +
432
+ "<ul>",
433
+ )($rootScope);
434
+ $rootScope.items = ["b", "c", "d"];
435
+ $rootScope.$digest();
436
+
437
+ $rootScope.items.unshift("a");
438
+ $rootScope.$digest();
439
+
440
+ const e1 = jqLite(element[0].childNodes[1]);
441
+ const e4 = jqLite(element[0].childNodes[7]);
442
+
443
+ expect(e1[0].classList.contains("odd")).toBeTruthy();
444
+ expect(e1[0].classList.contains("even")).toBeFalsy();
445
+
446
+ expect(e4[0].classList.contains("even")).toBeTruthy();
447
+ expect(e4[0].classList.contains("odd")).toBeFalsy();
448
+ });
449
+
450
+ it("should update ngClassOdd/Even when model is changed by filtering", () => {
451
+ element = $compile(
452
+ "<ul>" +
453
+ '<li ng-repeat="i in items track by $index" ' +
454
+ "ng-class-odd=\"'odd'\" ng-class-even=\"'even'\"></li>" +
455
+ "<ul>",
456
+ )($rootScope);
457
+ $rootScope.items = ["a", "b", "a"];
458
+ $rootScope.$digest();
459
+
460
+ $rootScope.items = ["a", "a"];
461
+ $rootScope.$digest();
462
+
463
+ const e1 = jqLite(element[0].childNodes[1]);
464
+ const e2 = jqLite(element[0].childNodes[3]);
465
+
466
+ expect(e1[0].classList.contains("odd")).toBeTruthy();
467
+ expect(e1[0].classList.contains("even")).toBeFalsy();
468
+
469
+ expect(e2[0].classList.contains("even")).toBeTruthy();
470
+ expect(e2[0].classList.contains("odd")).toBeFalsy();
471
+ });
472
+
473
+ it("should update ngClassOdd/Even when model is changed by sorting", () => {
474
+ element = $compile(
475
+ "<ul>" +
476
+ '<li ng-repeat="i in items" ' +
477
+ "ng-class-odd=\"'odd'\" ng-class-even=\"'even'\">i</li>" +
478
+ "<ul>",
479
+ )($rootScope);
480
+ $rootScope.items = ["a", "b"];
481
+ $rootScope.$digest();
482
+
483
+ $rootScope.items = ["b", "a"];
484
+ $rootScope.$digest();
485
+
486
+ const e1 = jqLite(element[0].childNodes[1]);
487
+ const e2 = jqLite(element[0].childNodes[3]);
488
+
489
+ expect(e1[0].classList.contains("odd")).toBeTruthy();
490
+ expect(e1[0].classList.contains("even")).toBeFalsy();
491
+
492
+ expect(e2[0].classList.contains("even")).toBeTruthy();
493
+ expect(e2[0].classList.contains("odd")).toBeFalsy();
494
+ });
495
+
496
+ it("should add/remove the correct classes when the expression and `$index` change simultaneously", () => {
497
+ element = $compile(
498
+ "<div>" +
499
+ '<div ng-class-odd="foo"></div>' +
500
+ '<div ng-class-even="foo"></div>' +
501
+ "</div>",
502
+ )($rootScope);
503
+ const odd = element.children().eq(0)[0];
504
+ const even = element.children().eq(1)[0];
505
+
506
+ $rootScope.$apply('$index = 0; foo = "class1"');
507
+
508
+ expect(odd).toHaveClass("class1");
509
+ expect(odd).not.toHaveClass("class2");
510
+ expect(even).not.toHaveClass("class1");
511
+ expect(even).not.toHaveClass("class2");
512
+
513
+ $rootScope.$apply('$index = 1; foo = "class2"');
514
+
515
+ expect(odd).not.toHaveClass("class1");
516
+ expect(odd).not.toHaveClass("class2");
517
+ expect(even).not.toHaveClass("class1");
518
+ expect(even).toHaveClass("class2");
519
+
520
+ $rootScope.$apply('foo = "class1"');
521
+
522
+ expect(odd).not.toHaveClass("class1");
523
+ expect(odd).not.toHaveClass("class2");
524
+ expect(even).toHaveClass("class1");
525
+ expect(even).not.toHaveClass("class2");
526
+
527
+ $rootScope.$apply("$index = 2");
528
+
529
+ expect(odd).toHaveClass("class1");
530
+ expect(odd).not.toHaveClass("class2");
531
+ expect(even).not.toHaveClass("class1");
532
+ expect(even).not.toHaveClass("class2");
533
+ });
534
+
535
+ it("should support mixed array/object variable with a mutating object", () => {
536
+ element = $compile('<div ng-class="classVar"></div>')($rootScope);
537
+
538
+ $rootScope.classVar = [{ orange: true }];
539
+ $rootScope.$digest();
540
+ expect(element[0]).toHaveClass("orange");
541
+
542
+ $rootScope.classVar[0].orange = false;
543
+ $rootScope.$digest();
544
+
545
+ expect(element[0]).not.toHaveClass("orange");
546
+ });
547
+
548
+ // // https://github.com/angular/angular.js/issues/15905
549
+ it("should support a mixed literal-array/object variable", () => {
550
+ element = $compile('<div ng-class="[classVar]"></div>')($rootScope);
551
+
552
+ $rootScope.classVar = { orange: true };
553
+ $rootScope.$digest();
554
+ expect(element[0]).toHaveClass("orange");
555
+
556
+ $rootScope.classVar.orange = false;
557
+ $rootScope.$digest();
558
+
559
+ expect(element[0]).not.toHaveClass("orange");
560
+ });
561
+
562
+ it("should support a one-time mixed literal-array/object variable", () => {
563
+ element = $compile('<div ng-class="::[classVar1, classVar2]"></div>')(
564
+ $rootScope,
565
+ );
566
+
567
+ $rootScope.classVar1 = { orange: true };
568
+ $rootScope.$digest();
569
+ expect(element[0]).toHaveClass("orange");
570
+
571
+ $rootScope.classVar1.orange = false;
572
+ $rootScope.$digest();
573
+
574
+ expect(element[0]).not.toHaveClass("orange");
575
+ });
576
+
577
+ it("should do value stabilization as expected when one-time binding", () => {
578
+ element = $compile('<div ng-class="::className"></div>')($rootScope);
579
+
580
+ $rootScope.$apply('className = "foo"');
581
+ expect(element[0]).toHaveClass("foo");
582
+
583
+ $rootScope.$apply('className = "bar"');
584
+ expect(element[0]).toHaveClass("foo");
585
+ });
586
+
587
+ it("should remove the watcher when static array one-time binding", () => {
588
+ element = $compile('<div ng-class="::[className]"></div>')($rootScope);
589
+
590
+ $rootScope.$apply('className = "foo"');
591
+ expect(element[0]).toHaveClass("foo");
592
+
593
+ $rootScope.$apply('className = "bar"');
594
+ expect(element[0]).toHaveClass("foo");
595
+ expect(element[0]).not.toHaveClass("bar");
596
+ });
597
+
598
+ it("should remove the watcher when static map one-time binding", () => {
599
+ element = $compile('<div ng-class="::{foo: fooPresent}"></div>')(
600
+ $rootScope,
601
+ );
602
+
603
+ $rootScope.$apply("fooPresent = true");
604
+ expect(element[0]).toHaveClass("foo");
605
+
606
+ $rootScope.$apply("fooPresent = false");
607
+ expect(element[0]).toHaveClass("foo");
608
+ });
609
+
610
+ it("should track changes of mutating object inside an array", () => {
611
+ $rootScope.classVar = [{ orange: true }];
612
+ element = $compile('<div ng-class="classVar"></div>')($rootScope);
613
+
614
+ $rootScope.$digest();
615
+ expect(element[0]).toHaveClass("orange");
616
+
617
+ $rootScope.$apply("classVar[0].orange = false");
618
+ expect(element[0]).not.toHaveClass("orange");
619
+ });
620
+
621
+ // https://github.com/angular/angular.js/issues/15960#issuecomment-299109412
622
+ it("should always reevaluate filters with non-primitive inputs within literals", () => {
623
+ injector = createInjector([
624
+ "ng",
625
+ ($filterProvider) => {
626
+ $filterProvider.register(
627
+ "foo",
628
+ valueFn((o) => o.a || o.b),
629
+ );
630
+ },
631
+ ]);
632
+
633
+ injector.invoke(($rootScope, $compile) => {
634
+ $rootScope.testObj = {};
635
+ element = $compile('<div ng-class="{x: (testObj | foo)}">')(
636
+ $rootScope,
637
+ )[0];
638
+
639
+ $rootScope.$apply();
640
+ expect(element).not.toHaveClass("x");
641
+
642
+ $rootScope.$apply("testObj.a = true");
643
+ expect(element).toHaveClass("x");
644
+ });
645
+ });
646
+
647
+ describe("large objects", () => {
648
+ let getProp;
649
+ let veryLargeObj;
650
+
651
+ beforeEach(() => {
652
+ getProp = jasmine.createSpy("getProp");
653
+ veryLargeObj = {};
654
+
655
+ Object.defineProperty(veryLargeObj, "prop", {
656
+ get: getProp,
657
+ enumerable: true,
658
+ });
659
+ });
660
+
661
+ it("should not be copied when using an expression", () => {
662
+ element = $compile('<div ng-class="fooClass"></div>')($rootScope)[0];
663
+ $rootScope.fooClass = { foo: veryLargeObj };
664
+ $rootScope.$digest();
665
+
666
+ expect(element).toHaveClass("foo");
667
+ expect(getProp).not.toHaveBeenCalled();
668
+ });
669
+
670
+ it("should not be copied when using a literal", () => {
671
+ element = $compile('<div ng-class="{foo: veryLargeObj}"></div>')(
672
+ $rootScope,
673
+ )[0];
674
+ $rootScope.veryLargeObj = veryLargeObj;
675
+ $rootScope.$digest();
676
+
677
+ expect(element).toHaveClass("foo");
678
+ expect(getProp).not.toHaveBeenCalled();
679
+ });
680
+
681
+ it("should not be copied when inside an array", () => {
682
+ element = $compile('<div ng-class="[{foo: veryLargeObj}]"></div>')(
683
+ $rootScope,
684
+ )[0];
685
+ $rootScope.veryLargeObj = veryLargeObj;
686
+ $rootScope.$digest();
687
+
688
+ expect(element).toHaveClass("foo");
689
+ expect(getProp).not.toHaveBeenCalled();
690
+ });
691
+
692
+ it("should not be copied when using one-time binding", () => {
693
+ element = $compile(
694
+ '<div ng-class="::{foo: veryLargeObj, bar: bar}"></div>',
695
+ )($rootScope)[0];
696
+ $rootScope.veryLargeObj = veryLargeObj;
697
+ $rootScope.$digest();
698
+
699
+ expect(element).toHaveClass("foo");
700
+ expect(element).not.toHaveClass("bar");
701
+ expect(getProp).not.toHaveBeenCalled();
702
+
703
+ $rootScope.$apply('veryLargeObj.bar = "bar"');
704
+
705
+ expect(element).toHaveClass("foo");
706
+ expect(element).not.toHaveClass("bar");
707
+ expect(getProp).not.toHaveBeenCalled();
708
+
709
+ $rootScope.$apply('bar = "bar"');
710
+
711
+ expect(element).toHaveClass("foo");
712
+ expect(element).toHaveClass("bar");
713
+ expect(getProp).not.toHaveBeenCalled();
714
+
715
+ $rootScope.$apply('veryLargeObj.bar = "qux"');
716
+
717
+ expect(element).toHaveClass("foo");
718
+ expect(element).toHaveClass("bar");
719
+ expect(getProp).not.toHaveBeenCalled();
720
+ });
721
+ });
722
+ });
723
+
724
+ // describe("ngClass animations", () => {
725
+ // let body;
726
+ // let element;
727
+ // let $rootElement;
728
+
729
+ // afterEach(() => {
730
+ // dealoc(element);
731
+ // });
732
+
733
+ // it("should avoid calling addClass accidentally when removeClass is going on", () => {
734
+ // module("ngAnimateMock");
735
+ // inject(($compile, $rootScope, $animate, $timeout) => {
736
+ // element = angular.element('<div ng-class="val"></div>');
737
+ // const body = jqLite(window.document.body);
738
+ // body.append(element);
739
+ // $compile(element)($rootScope);
740
+
741
+ // expect($animate.queue.length).toBe(0);
742
+
743
+ // $rootScope.val = "one";
744
+ // $rootScope.$digest();
745
+ // expect($animate.queue.shift().event).toBe("addClass");
746
+ // expect($animate.queue.length).toBe(0);
747
+
748
+ // $rootScope.val = "";
749
+ // $rootScope.$digest();
750
+ // expect($animate.queue.shift().event).toBe("removeClass"); // only removeClass is called
751
+ // expect($animate.queue.length).toBe(0);
752
+
753
+ // $rootScope.val = "one";
754
+ // $rootScope.$digest();
755
+ // expect($animate.queue.shift().event).toBe("addClass");
756
+ // expect($animate.queue.length).toBe(0);
757
+
758
+ // $rootScope.val = "two";
759
+ // $rootScope.$digest();
760
+ // expect($animate.queue.shift().event).toBe("addClass");
761
+ // expect($animate.queue.shift().event).toBe("removeClass");
762
+ // expect($animate.queue.length).toBe(0);
763
+ // });
764
+ // });
765
+
766
+ // it("should combine the ngClass evaluation with the enter animation", () => {
767
+ // // mocks are not used since the enter delegation method is called before addClass and
768
+ // // it makes it impossible to test to see that addClass is called first
769
+ // module("ngAnimate");
770
+ // module("ngAnimateMock");
771
+
772
+ // module(($animateProvider) => {
773
+ // $animateProvider.register(".crazy", () => ({
774
+ // enter(element, done) {
775
+ // element.data("state", "crazy-enter");
776
+ // done();
777
+ // },
778
+ // }));
779
+ // });
780
+ // inject(
781
+ // ($compile, $rootScope, $browser, $rootElement, $animate, $document) => {
782
+ // $animate.enabled(true);
783
+
784
+ // $rootScope.val = "crazy";
785
+ // element = angular.element('<div ng-class="val"></div>');
786
+ // jqLite($document[0].body).append($rootElement);
787
+
788
+ // $compile(element)($rootScope);
789
+
790
+ // let enterComplete = false;
791
+ // $animate.enter(element, $rootElement, null).then(() => {
792
+ // enterComplete = true;
793
+ // });
794
+
795
+ // // jquery doesn't compare both elements properly so let's use the nodes
796
+ // expect(element.parent()[0]).toEqual($rootElement[0]);
797
+ // expect(element[0].classList.contains("crazy")).toBe(false);
798
+ // expect(enterComplete).toBe(false);
799
+
800
+ // $rootScope.$digest();
801
+ // $animate.flush();
802
+ // $rootScope.$digest();
803
+
804
+ // expect(element[0].classList.contains("crazy")).toBe(true);
805
+ // expect(enterComplete).toBe(true);
806
+ // expect(element.data("state")).toBe("crazy-enter");
807
+ // },
808
+ // );
809
+ // });
810
+
811
+ // it("should not remove classes if they're going to be added back right after", () => {
812
+ // module("ngAnimateMock");
813
+
814
+ // inject(($rootScope, $compile, $animate) => {
815
+ // let className;
816
+
817
+ // $rootScope.one = true;
818
+ // $rootScope.two = true;
819
+ // $rootScope.three = true;
820
+
821
+ // element = angular.element(
822
+ // '<div ng-class="{one:one, two:two, three:three}"></div>',
823
+ // );
824
+ // $compile(element)($rootScope);
825
+ // $rootScope.$digest();
826
+
827
+ // // this fires twice due to the class observer firing
828
+ // let item = $animate.queue.shift();
829
+ // expect(item.event).toBe("addClass");
830
+ // expect(item.args[1]).toBe("one two three");
831
+
832
+ // expect($animate.queue.length).toBe(0);
833
+
834
+ // $rootScope.three = false;
835
+ // $rootScope.$digest();
836
+
837
+ // item = $animate.queue.shift();
838
+ // expect(item.event).toBe("removeClass");
839
+ // expect(item.args[1]).toBe("three");
840
+
841
+ // expect($animate.queue.length).toBe(0);
842
+
843
+ // $rootScope.two = false;
844
+ // $rootScope.three = true;
845
+ // $rootScope.$digest();
846
+
847
+ // item = $animate.queue.shift();
848
+ // expect(item.event).toBe("addClass");
849
+ // expect(item.args[1]).toBe("three");
850
+
851
+ // item = $animate.queue.shift();
852
+ // expect(item.event).toBe("removeClass");
853
+ // expect(item.args[1]).toBe("two");
854
+
855
+ // expect($animate.queue.length).toBe(0);
856
+ // });
857
+ // });
858
+ // });