@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,851 @@
1
+ import { jqLite } from "../jqLite";
2
+ import {
3
+ isUndefined,
4
+ forEach,
5
+ isObject,
6
+ isArray,
7
+ isString,
8
+ isElement,
9
+ isDefined,
10
+ extend,
11
+ } from "../core/utils";
12
+ import {
13
+ NG_ANIMATE_CHILDREN_DATA,
14
+ applyAnimationClassesFactory,
15
+ applyAnimationStyles,
16
+ applyGeneratedPreparationClasses,
17
+ assertArg,
18
+ clearGeneratedClasses,
19
+ extractElementNode,
20
+ getDomNode,
21
+ mergeAnimationDetails,
22
+ prepareAnimationOptions,
23
+ stripCommentsFromElement,
24
+ } from "./shared";
25
+
26
+ const NG_ANIMATE_ATTR_NAME = "data-ng-animate";
27
+ const NG_ANIMATE_PIN_DATA = "$ngAnimatePin";
28
+ export const $$AnimateQueueProvider = [
29
+ "$animateProvider",
30
+ function ($animateProvider) {
31
+ const PRE_DIGEST_STATE = 1;
32
+ const RUNNING_STATE = 2;
33
+ const ONE_SPACE = " ";
34
+
35
+ const rules = (this.rules = {
36
+ skip: [],
37
+ cancel: [],
38
+ join: [],
39
+ });
40
+
41
+ function getEventData(options) {
42
+ return {
43
+ addClass: options.addClass,
44
+ removeClass: options.removeClass,
45
+ from: options.from,
46
+ to: options.to,
47
+ };
48
+ }
49
+
50
+ function makeTruthyCssClassMap(classString) {
51
+ if (!classString) {
52
+ return null;
53
+ }
54
+
55
+ const keys = classString.split(ONE_SPACE);
56
+ const map = Object.create(null);
57
+
58
+ forEach(keys, (key) => {
59
+ map[key] = true;
60
+ });
61
+ return map;
62
+ }
63
+
64
+ function hasMatchingClasses(newClassString, currentClassString) {
65
+ if (newClassString && currentClassString) {
66
+ const currentClassMap = makeTruthyCssClassMap(currentClassString);
67
+ return newClassString
68
+ .split(ONE_SPACE)
69
+ .some((className) => currentClassMap[className]);
70
+ }
71
+ }
72
+
73
+ function isAllowed(ruleType, currentAnimation, previousAnimation) {
74
+ return rules[ruleType].some((fn) =>
75
+ fn(currentAnimation, previousAnimation),
76
+ );
77
+ }
78
+
79
+ function hasAnimationClasses(animation, and) {
80
+ const a = (animation.addClass || "").length > 0;
81
+ const b = (animation.removeClass || "").length > 0;
82
+ return and ? a && b : a || b;
83
+ }
84
+
85
+ rules.join.push(
86
+ (newAnimation) =>
87
+ // if the new animation is class-based then we can just tack that on
88
+ !newAnimation.structural && hasAnimationClasses(newAnimation),
89
+ );
90
+
91
+ rules.skip.push(
92
+ (newAnimation) =>
93
+ // there is no need to animate anything if no classes are being added and
94
+ // there is no structural animation that will be triggered
95
+ !newAnimation.structural && !hasAnimationClasses(newAnimation),
96
+ );
97
+
98
+ rules.skip.push(
99
+ (newAnimation, currentAnimation) =>
100
+ // why should we trigger a new structural animation if the element will
101
+ // be removed from the DOM anyway?
102
+ currentAnimation.event === "leave" && newAnimation.structural,
103
+ );
104
+
105
+ rules.skip.push(
106
+ (newAnimation, currentAnimation) =>
107
+ // if there is an ongoing current animation then don't even bother running the class-based animation
108
+ currentAnimation.structural &&
109
+ currentAnimation.state === RUNNING_STATE &&
110
+ !newAnimation.structural,
111
+ );
112
+
113
+ rules.cancel.push(
114
+ (newAnimation, currentAnimation) =>
115
+ // there can never be two structural animations running at the same time
116
+ currentAnimation.structural && newAnimation.structural,
117
+ );
118
+
119
+ rules.cancel.push(
120
+ (newAnimation, currentAnimation) =>
121
+ // if the previous animation is already running, but the new animation will
122
+ // be triggered, but the new animation is structural
123
+ currentAnimation.state === RUNNING_STATE && newAnimation.structural,
124
+ );
125
+
126
+ rules.cancel.push((newAnimation, currentAnimation) => {
127
+ // cancel the animation if classes added / removed in both animation cancel each other out,
128
+ // but only if the current animation isn't structural
129
+
130
+ if (currentAnimation.structural) return false;
131
+
132
+ const nA = newAnimation.addClass;
133
+ const nR = newAnimation.removeClass;
134
+ const cA = currentAnimation.addClass;
135
+ const cR = currentAnimation.removeClass;
136
+
137
+ // early detection to save the global CPU shortage :)
138
+ if (
139
+ (isUndefined(nA) && isUndefined(nR)) ||
140
+ (isUndefined(cA) && isUndefined(cR))
141
+ ) {
142
+ return false;
143
+ }
144
+
145
+ return hasMatchingClasses(nA, cR) || hasMatchingClasses(nR, cA);
146
+ });
147
+
148
+ this.$get = [
149
+ "$rootScope",
150
+ "$rootElement",
151
+ "$document",
152
+ "$$animation",
153
+ "$$AnimateRunner",
154
+ "$templateRequest",
155
+ "$$isDocumentHidden",
156
+ function (
157
+ $rootScope,
158
+ $rootElement,
159
+ $document,
160
+ $$animation,
161
+ $$AnimateRunner,
162
+ $templateRequest,
163
+ $$isDocumentHidden,
164
+ ) {
165
+ const activeAnimationsLookup = new Map();
166
+ const disabledElementsLookup = new Map();
167
+ let animationsEnabled = null;
168
+
169
+ function removeFromDisabledElementsLookup(evt) {
170
+ disabledElementsLookup.delete(evt.target);
171
+ }
172
+
173
+ function postDigestTaskFactory() {
174
+ let postDigestCalled = false;
175
+ return function (fn) {
176
+ // we only issue a call to postDigest before
177
+ // it has first passed. This prevents any callbacks
178
+ // from not firing once the animation has completed
179
+ // since it will be out of the digest cycle.
180
+ if (postDigestCalled) {
181
+ fn();
182
+ } else {
183
+ $rootScope.$$postDigest(() => {
184
+ postDigestCalled = true;
185
+ fn();
186
+ });
187
+ }
188
+ };
189
+ }
190
+
191
+ // Wait until all directive and route-related templates are downloaded and
192
+ // compiled. The $templateRequest.totalPendingRequests variable keeps track of
193
+ // all of the remote templates being currently downloaded. If there are no
194
+ // templates currently downloading then the watcher will still fire anyway.
195
+ const deregisterWatch = $rootScope.$watch(
196
+ () => $templateRequest.totalPendingRequests === 0,
197
+ (isEmpty) => {
198
+ if (!isEmpty) return;
199
+ deregisterWatch();
200
+
201
+ // Now that all templates have been downloaded, $animate will wait until
202
+ // the post digest queue is empty before enabling animations. By having two
203
+ // calls to $postDigest calls we can ensure that the flag is enabled at the
204
+ // very end of the post digest queue. Since all of the animations in $animate
205
+ // use $postDigest, it's important that the code below executes at the end.
206
+ // This basically means that the page is fully downloaded and compiled before
207
+ // any animations are triggered.
208
+ $rootScope.$$postDigest(() => {
209
+ $rootScope.$$postDigest(() => {
210
+ // we check for null directly in the event that the application already called
211
+ // .enabled() with whatever arguments that it provided it with
212
+ if (animationsEnabled === null) {
213
+ animationsEnabled = true;
214
+ }
215
+ });
216
+ });
217
+ },
218
+ );
219
+
220
+ const callbackRegistry = Object.create(null);
221
+
222
+ // remember that the `customFilter`/`classNameFilter` are set during the
223
+ // provider/config stage therefore we can optimize here and setup helper functions
224
+ const customFilter = $animateProvider.customFilter();
225
+ const classNameFilter = $animateProvider.classNameFilter();
226
+ const returnTrue = function () {
227
+ return true;
228
+ };
229
+
230
+ const isAnimatableByFilter = customFilter || returnTrue;
231
+ const isAnimatableClassName = !classNameFilter
232
+ ? returnTrue
233
+ : function (node, options) {
234
+ const className = [
235
+ node.getAttribute("class"),
236
+ options.addClass,
237
+ options.removeClass,
238
+ ].join(" ");
239
+ return classNameFilter.test(className);
240
+ };
241
+
242
+ const applyAnimationClasses = applyAnimationClassesFactory();
243
+
244
+ function normalizeAnimationDetails(element, animation) {
245
+ return mergeAnimationDetails(element, animation, {});
246
+ }
247
+
248
+ // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
249
+ const contains =
250
+ window.Node.prototype.contains ||
251
+ function (arg) {
252
+ // eslint-disable-next-line no-bitwise
253
+ return this === arg || !!(this.compareDocumentPosition(arg) & 16);
254
+ };
255
+
256
+ function findCallbacks(targetParentNode, targetNode, event) {
257
+ const matches = [];
258
+ const entries = callbackRegistry[event];
259
+ if (entries) {
260
+ forEach(entries, (entry) => {
261
+ if (contains.call(entry.node, targetNode)) {
262
+ matches.push(entry.callback);
263
+ } else if (
264
+ event === "leave" &&
265
+ contains.call(entry.node, targetParentNode)
266
+ ) {
267
+ matches.push(entry.callback);
268
+ }
269
+ });
270
+ }
271
+
272
+ return matches;
273
+ }
274
+
275
+ function filterFromRegistry(list, matchContainer, matchCallback) {
276
+ const containerNode = extractElementNode(matchContainer);
277
+ return list.filter((entry) => {
278
+ const isMatch =
279
+ entry.node === containerNode &&
280
+ (!matchCallback || entry.callback === matchCallback);
281
+ return !isMatch;
282
+ });
283
+ }
284
+
285
+ function cleanupEventListeners(phase, node) {
286
+ if (phase === "close" && !node.parentNode) {
287
+ // If the element is not attached to a parentNode, it has been removed by
288
+ // the domOperation, and we can safely remove the event callbacks
289
+ $animate.off(node);
290
+ }
291
+ }
292
+
293
+ let $animate = {
294
+ on(event, container, callback) {
295
+ const node = extractElementNode(container);
296
+ callbackRegistry[event] = callbackRegistry[event] || [];
297
+ callbackRegistry[event].push({
298
+ node,
299
+ callback,
300
+ });
301
+
302
+ // Remove the callback when the element is removed from the DOM
303
+ jqLite(container).on("$destroy", () => {
304
+ const animationDetails = activeAnimationsLookup.get(node);
305
+
306
+ if (!animationDetails) {
307
+ // If there's an animation ongoing, the callback calling code will remove
308
+ // the event listeners. If we'd remove here, the callbacks would be removed
309
+ // before the animation ends
310
+ $animate.off(event, container, callback);
311
+ }
312
+ });
313
+ },
314
+
315
+ off(event, container, callback) {
316
+ if (arguments.length === 1 && !isString(arguments[0])) {
317
+ container = arguments[0];
318
+ for (const eventType in callbackRegistry) {
319
+ callbackRegistry[eventType] = filterFromRegistry(
320
+ callbackRegistry[eventType],
321
+ container,
322
+ );
323
+ }
324
+
325
+ return;
326
+ }
327
+
328
+ const entries = callbackRegistry[event];
329
+ if (!entries) return;
330
+
331
+ callbackRegistry[event] =
332
+ arguments.length === 1
333
+ ? null
334
+ : filterFromRegistry(entries, container, callback);
335
+ },
336
+
337
+ pin(element, parentElement) {
338
+ assertArg(isElement(element), "element", "not an element");
339
+ assertArg(
340
+ isElement(parentElement),
341
+ "parentElement",
342
+ "not an element",
343
+ );
344
+ element.data(NG_ANIMATE_PIN_DATA, parentElement);
345
+ },
346
+
347
+ push(element, event, options, domOperation) {
348
+ options = options || {};
349
+ options.domOperation = domOperation;
350
+ return queueAnimation(element, event, options);
351
+ },
352
+
353
+ // this method has four signatures:
354
+ // () - global getter
355
+ // (bool) - global setter
356
+ // (element) - element getter
357
+ // (element, bool) - element setter<F37>
358
+ enabled(element, bool) {
359
+ const argCount = arguments.length;
360
+
361
+ if (argCount === 0) {
362
+ // () - Global getter
363
+ bool = !!animationsEnabled;
364
+ } else {
365
+ const hasElement = isElement(element);
366
+
367
+ if (!hasElement) {
368
+ // (bool) - Global setter
369
+ bool = animationsEnabled = !!element;
370
+ } else {
371
+ const node = getDomNode(element);
372
+
373
+ if (argCount === 1) {
374
+ // (element) - Element getter
375
+ bool = !disabledElementsLookup.get(node);
376
+ } else {
377
+ // (element, bool) - Element setter
378
+ if (!disabledElementsLookup.has(node)) {
379
+ // The element is added to the map for the first time.
380
+ // Create a listener to remove it on `$destroy` (to avoid memory leak).
381
+ jqLite(element).on(
382
+ "$destroy",
383
+ removeFromDisabledElementsLookup,
384
+ );
385
+ }
386
+ disabledElementsLookup.set(node, !bool);
387
+ }
388
+ }
389
+ }
390
+
391
+ return bool;
392
+ },
393
+ };
394
+
395
+ return $animate;
396
+
397
+ function queueAnimation(originalElement, event, initialOptions) {
398
+ // we always make a copy of the options since
399
+ // there should never be any side effects on
400
+ // the input data when running `$animateCss`.
401
+ let options = structuredClone(initialOptions);
402
+
403
+ let element = stripCommentsFromElement(originalElement);
404
+ const node = getDomNode(element);
405
+ const parentNode = node && node.parentNode;
406
+
407
+ options = prepareAnimationOptions(options);
408
+
409
+ // we create a fake runner with a working promise.
410
+ // These methods will become available after the digest has passed
411
+ const runner = new $$AnimateRunner();
412
+
413
+ // this is used to trigger callbacks in postDigest mode
414
+ const runInNextPostDigestOrNow = postDigestTaskFactory();
415
+
416
+ if (isArray(options.addClass)) {
417
+ options.addClass = options.addClass.join(" ");
418
+ }
419
+
420
+ if (options.addClass && !isString(options.addClass)) {
421
+ options.addClass = null;
422
+ }
423
+
424
+ if (isArray(options.removeClass)) {
425
+ options.removeClass = options.removeClass.join(" ");
426
+ }
427
+
428
+ if (options.removeClass && !isString(options.removeClass)) {
429
+ options.removeClass = null;
430
+ }
431
+
432
+ if (options.from && !isObject(options.from)) {
433
+ options.from = null;
434
+ }
435
+
436
+ if (options.to && !isObject(options.to)) {
437
+ options.to = null;
438
+ }
439
+
440
+ // If animations are hard-disabled for the whole application there is no need to continue.
441
+ // There are also situations where a directive issues an animation for a jqLite wrapper that
442
+ // contains only comment nodes. In this case, there is no way we can perform an animation.
443
+ if (
444
+ !animationsEnabled ||
445
+ !node ||
446
+ !isAnimatableByFilter(node, event, initialOptions) ||
447
+ !isAnimatableClassName(node, options)
448
+ ) {
449
+ close();
450
+ return runner;
451
+ }
452
+
453
+ const isStructural = ["enter", "move", "leave"].indexOf(event) >= 0;
454
+
455
+ const documentHidden = $$isDocumentHidden();
456
+
457
+ // This is a hard disable of all animations the element itself, therefore there is no need to
458
+ // continue further past this point if not enabled
459
+ // Animations are also disabled if the document is currently hidden (page is not visible
460
+ // to the user), because browsers slow down or do not flush calls to requestAnimationFrame
461
+ let skipAnimations =
462
+ documentHidden || disabledElementsLookup.get(node);
463
+ const existingAnimation =
464
+ (!skipAnimations && activeAnimationsLookup.get(node)) || {};
465
+ const hasExistingAnimation = !!existingAnimation.state;
466
+
467
+ // there is no point in traversing the same collection of parent ancestors if a followup
468
+ // animation will be run on the same element that already did all that checking work
469
+ if (
470
+ !skipAnimations &&
471
+ (!hasExistingAnimation ||
472
+ existingAnimation.state !== PRE_DIGEST_STATE)
473
+ ) {
474
+ skipAnimations = !areAnimationsAllowed(node, parentNode, event);
475
+ }
476
+
477
+ if (skipAnimations) {
478
+ // Callbacks should fire even if the document is hidden (regression fix for issue #14120)
479
+ if (documentHidden)
480
+ notifyProgress(runner, event, "start", getEventData(options));
481
+ close();
482
+ if (documentHidden)
483
+ notifyProgress(runner, event, "close", getEventData(options));
484
+ return runner;
485
+ }
486
+
487
+ if (isStructural) {
488
+ closeChildAnimations(node);
489
+ }
490
+
491
+ const newAnimation = {
492
+ structural: isStructural,
493
+ element,
494
+ event,
495
+ addClass: options.addClass,
496
+ removeClass: options.removeClass,
497
+ close,
498
+ options,
499
+ runner,
500
+ };
501
+
502
+ if (hasExistingAnimation) {
503
+ const skipAnimationFlag = isAllowed(
504
+ "skip",
505
+ newAnimation,
506
+ existingAnimation,
507
+ );
508
+ if (skipAnimationFlag) {
509
+ if (existingAnimation.state === RUNNING_STATE) {
510
+ close();
511
+ return runner;
512
+ }
513
+ mergeAnimationDetails(element, existingAnimation, newAnimation);
514
+ return existingAnimation.runner;
515
+ }
516
+ const cancelAnimationFlag = isAllowed(
517
+ "cancel",
518
+ newAnimation,
519
+ existingAnimation,
520
+ );
521
+ if (cancelAnimationFlag) {
522
+ if (existingAnimation.state === RUNNING_STATE) {
523
+ // this will end the animation right away and it is safe
524
+ // to do so since the animation is already running and the
525
+ // runner callback code will run in async
526
+ existingAnimation.runner.end();
527
+ } else if (existingAnimation.structural) {
528
+ // this means that the animation is queued into a digest, but
529
+ // hasn't started yet. Therefore it is safe to run the close
530
+ // method which will call the runner methods in async.
531
+ existingAnimation.close();
532
+ } else {
533
+ // this will merge the new animation options into existing animation options
534
+ mergeAnimationDetails(element, existingAnimation, newAnimation);
535
+
536
+ return existingAnimation.runner;
537
+ }
538
+ } else {
539
+ // a joined animation means that this animation will take over the existing one
540
+ // so an example would involve a leave animation taking over an enter. Then when
541
+ // the postDigest kicks in the enter will be ignored.
542
+ const joinAnimationFlag = isAllowed(
543
+ "join",
544
+ newAnimation,
545
+ existingAnimation,
546
+ );
547
+ if (joinAnimationFlag) {
548
+ if (existingAnimation.state === RUNNING_STATE) {
549
+ normalizeAnimationDetails(element, newAnimation);
550
+ } else {
551
+ applyGeneratedPreparationClasses(
552
+ element,
553
+ isStructural ? event : null,
554
+ options,
555
+ );
556
+
557
+ event = newAnimation.event = existingAnimation.event;
558
+ options = mergeAnimationDetails(
559
+ element,
560
+ existingAnimation,
561
+ newAnimation,
562
+ );
563
+
564
+ // we return the same runner since only the option values of this animation will
565
+ // be fed into the `existingAnimation`.
566
+ return existingAnimation.runner;
567
+ }
568
+ }
569
+ }
570
+ } else {
571
+ // normalization in this case means that it removes redundant CSS classes that
572
+ // already exist (addClass) or do not exist (removeClass) on the element
573
+ normalizeAnimationDetails(element, newAnimation);
574
+ }
575
+
576
+ // when the options are merged and cleaned up we may end up not having to do
577
+ // an animation at all, therefore we should check this before issuing a post
578
+ // digest callback. Structural animations will always run no matter what.
579
+ let isValidAnimation = newAnimation.structural;
580
+ if (!isValidAnimation) {
581
+ // animate (from/to) can be quickly checked first, otherwise we check if any classes are present
582
+ isValidAnimation =
583
+ (newAnimation.event === "animate" &&
584
+ Object.keys(newAnimation.options.to || {}).length > 0) ||
585
+ hasAnimationClasses(newAnimation);
586
+ }
587
+
588
+ if (!isValidAnimation) {
589
+ close();
590
+ clearElementAnimationState(node);
591
+ return runner;
592
+ }
593
+
594
+ // the counter keeps track of cancelled animations
595
+ const counter = (existingAnimation.counter || 0) + 1;
596
+ newAnimation.counter = counter;
597
+
598
+ markElementAnimationState(node, PRE_DIGEST_STATE, newAnimation);
599
+
600
+ $rootScope.$$postDigest(() => {
601
+ // It is possible that the DOM nodes inside `originalElement` have been replaced. This can
602
+ // happen if the animated element is a transcluded clone and also has a `templateUrl`
603
+ // directive on it. Therefore, we must recreate `element` in order to interact with the
604
+ // actual DOM nodes.
605
+ // Note: We still need to use the old `node` for certain things, such as looking up in
606
+ // HashMaps where it was used as the key.
607
+
608
+ element = stripCommentsFromElement(originalElement);
609
+
610
+ let animationDetails = activeAnimationsLookup.get(node);
611
+ const animationCancelled = !animationDetails;
612
+ animationDetails = animationDetails || {};
613
+
614
+ // if addClass/removeClass is called before something like enter then the
615
+ // registered parent element may not be present. The code below will ensure
616
+ // that a final value for parent element is obtained
617
+ const parentElement = element.parent() || [];
618
+
619
+ // animate/structural/class-based animations all have requirements. Otherwise there
620
+ // is no point in performing an animation. The parent node must also be set.
621
+ const isValidAnimation =
622
+ parentElement.length > 0 &&
623
+ (animationDetails.event === "animate" ||
624
+ animationDetails.structural ||
625
+ hasAnimationClasses(animationDetails));
626
+
627
+ // this means that the previous animation was cancelled
628
+ // even if the follow-up animation is the same event
629
+ if (
630
+ animationCancelled ||
631
+ animationDetails.counter !== counter ||
632
+ !isValidAnimation
633
+ ) {
634
+ // if another animation did not take over then we need
635
+ // to make sure that the domOperation and options are
636
+ // handled accordingly
637
+ if (animationCancelled) {
638
+ applyAnimationClasses(element, options);
639
+ applyAnimationStyles(element, options);
640
+ }
641
+
642
+ // if the event changed from something like enter to leave then we do
643
+ // it, otherwise if it's the same then the end result will be the same too
644
+ if (
645
+ animationCancelled ||
646
+ (isStructural && animationDetails.event !== event)
647
+ ) {
648
+ options.domOperation();
649
+ runner.end();
650
+ }
651
+
652
+ // in the event that the element animation was not cancelled or a follow-up animation
653
+ // isn't allowed to animate from here then we need to clear the state of the element
654
+ // so that any future animations won't read the expired animation data.
655
+ if (!isValidAnimation) {
656
+ clearElementAnimationState(node);
657
+ }
658
+
659
+ return;
660
+ }
661
+
662
+ // this combined multiple class to addClass / removeClass into a setClass event
663
+ // so long as a structural event did not take over the animation
664
+ event =
665
+ !animationDetails.structural &&
666
+ hasAnimationClasses(animationDetails, true)
667
+ ? "setClass"
668
+ : animationDetails.event;
669
+
670
+ markElementAnimationState(node, RUNNING_STATE);
671
+ const realRunner = $$animation(
672
+ element,
673
+ event,
674
+ animationDetails.options,
675
+ );
676
+
677
+ // this will update the runner's flow-control events based on
678
+ // the `realRunner` object.
679
+ runner.setHost(realRunner);
680
+ notifyProgress(runner, event, "start", getEventData(options));
681
+
682
+ realRunner.done((status) => {
683
+ close(!status);
684
+ const animationDetails = activeAnimationsLookup.get(node);
685
+ if (animationDetails && animationDetails.counter === counter) {
686
+ clearElementAnimationState(node);
687
+ }
688
+ notifyProgress(runner, event, "close", getEventData(options));
689
+ });
690
+ });
691
+
692
+ return runner;
693
+
694
+ function notifyProgress(runner, event, phase, data) {
695
+ runInNextPostDigestOrNow(() => {
696
+ const callbacks = findCallbacks(parentNode, node, event);
697
+ if (callbacks.length) {
698
+ forEach(callbacks, (callback) => {
699
+ callback(element, phase, data);
700
+ });
701
+ cleanupEventListeners(phase, node);
702
+ } else {
703
+ cleanupEventListeners(phase, node);
704
+ }
705
+ });
706
+ runner.progress(event, phase, data);
707
+ }
708
+
709
+ function close(reject) {
710
+ clearGeneratedClasses(element, options);
711
+ applyAnimationClasses(element, options);
712
+ applyAnimationStyles(element, options);
713
+ options.domOperation();
714
+ runner.complete(!reject);
715
+ }
716
+ }
717
+
718
+ function closeChildAnimations(node) {
719
+ const children = node.querySelectorAll(`[${NG_ANIMATE_ATTR_NAME}]`);
720
+ forEach(children, (child) => {
721
+ const state = parseInt(
722
+ child.getAttribute(NG_ANIMATE_ATTR_NAME),
723
+ 10,
724
+ );
725
+ const animationDetails = activeAnimationsLookup.get(child);
726
+ if (animationDetails) {
727
+ switch (state) {
728
+ case RUNNING_STATE:
729
+ animationDetails.runner.end();
730
+ /* falls through */
731
+ case PRE_DIGEST_STATE:
732
+ activeAnimationsLookup.delete(child);
733
+ break;
734
+ }
735
+ }
736
+ });
737
+ }
738
+
739
+ function clearElementAnimationState(node) {
740
+ node.removeAttribute(NG_ANIMATE_ATTR_NAME);
741
+ activeAnimationsLookup.delete(node);
742
+ }
743
+
744
+ /**
745
+ * This fn returns false if any of the following is true:
746
+ * a) animations on any parent element are disabled, and animations on the element aren't explicitly allowed
747
+ * b) a parent element has an ongoing structural animation, and animateChildren is false
748
+ * c) the element is not a child of the body
749
+ * d) the element is not a child of the $rootElement
750
+ */
751
+ function areAnimationsAllowed(node, parentNode) {
752
+ const bodyNode = $document[0].body;
753
+ const rootNode = getDomNode($rootElement);
754
+
755
+ let bodyNodeDetected = node === bodyNode || node.nodeName === "HTML";
756
+ let rootNodeDetected = node === rootNode;
757
+ let parentAnimationDetected = false;
758
+ let elementDisabled = disabledElementsLookup.get(node);
759
+ let animateChildren;
760
+
761
+ let parentHost = jqLite.data(node, NG_ANIMATE_PIN_DATA);
762
+ if (parentHost) {
763
+ parentNode = getDomNode(parentHost);
764
+ }
765
+
766
+ while (parentNode) {
767
+ if (!rootNodeDetected) {
768
+ // AngularJS doesn't want to attempt to animate elements outside of the application
769
+ // therefore we need to ensure that the rootElement is an ancestor of the current element
770
+ rootNodeDetected = parentNode === rootNode;
771
+ }
772
+
773
+ if (parentNode.nodeType !== Node.ELEMENT_NODE) {
774
+ // no point in inspecting the #document element
775
+ break;
776
+ }
777
+
778
+ const details = activeAnimationsLookup.get(parentNode) || {};
779
+ // either an enter, leave or move animation will commence
780
+ // therefore we can't allow any animations to take place
781
+ // but if a parent animation is class-based then that's ok
782
+ if (!parentAnimationDetected) {
783
+ const parentNodeDisabled = disabledElementsLookup.get(parentNode);
784
+
785
+ if (parentNodeDisabled === true && elementDisabled !== false) {
786
+ // disable animations if the user hasn't explicitly enabled animations on the
787
+ // current element
788
+ elementDisabled = true;
789
+ // element is disabled via parent element, no need to check anything else
790
+ break;
791
+ } else if (parentNodeDisabled === false) {
792
+ elementDisabled = false;
793
+ }
794
+ parentAnimationDetected = details.structural;
795
+ }
796
+
797
+ if (isUndefined(animateChildren) || animateChildren === true) {
798
+ const value = jqLite.data(parentNode, NG_ANIMATE_CHILDREN_DATA);
799
+ if (isDefined(value)) {
800
+ animateChildren = value;
801
+ }
802
+ }
803
+
804
+ // there is no need to continue traversing at this point
805
+ if (parentAnimationDetected && animateChildren === false) break;
806
+
807
+ if (!bodyNodeDetected) {
808
+ // we also need to ensure that the element is or will be a part of the body element
809
+ // otherwise it is pointless to even issue an animation to be rendered
810
+ bodyNodeDetected = parentNode === bodyNode;
811
+ }
812
+
813
+ if (bodyNodeDetected && rootNodeDetected) {
814
+ // If both body and root have been found, any other checks are pointless,
815
+ // as no animation data should live outside the application
816
+ break;
817
+ }
818
+
819
+ if (!rootNodeDetected) {
820
+ // If `rootNode` is not detected, check if `parentNode` is pinned to another element
821
+ parentHost = jqLite.data(parentNode, NG_ANIMATE_PIN_DATA);
822
+ if (parentHost) {
823
+ // The pin target element becomes the next parent element
824
+ parentNode = getDomNode(parentHost);
825
+ continue;
826
+ }
827
+ }
828
+
829
+ parentNode = parentNode.parentNode;
830
+ }
831
+
832
+ const allowAnimation =
833
+ (!parentAnimationDetected || animateChildren) &&
834
+ elementDisabled !== true;
835
+ return allowAnimation && rootNodeDetected && bodyNodeDetected;
836
+ }
837
+
838
+ function markElementAnimationState(node, state, details) {
839
+ details = details || {};
840
+ details.state = state;
841
+
842
+ node.setAttribute(NG_ANIMATE_ATTR_NAME, state);
843
+
844
+ const oldValue = activeAnimationsLookup.get(node);
845
+ const newValue = oldValue ? extend(oldValue, details) : details;
846
+ activeAnimationsLookup.set(node, newValue);
847
+ }
848
+ },
849
+ ];
850
+ },
851
+ ];