angular-gem 1.2.12 → 1.2.13

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZGQ0ZWE4ZTNlNTA3Y2YwYjBiMTUzZDlmNzJkMzM0YzMzNmIxNGNiMw==
4
+ NDJkZjcyYzg4NDUwZDhkZjNmNGExZGE0MzExY2Q1ZDM3YmJhOTJkMA==
5
5
  data.tar.gz: !binary |-
6
- NDU0MGZlM2E0YzRhOTU4ODZkMzQ3MzIxNGJlYzI0MGQxYjc2YmFmMg==
6
+ YzE3MWUyZjk1NzE5NTNmMGEyODI4NDRiM2IwMWQwYmY4MjhiYWVkOQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZGQxZTAyYTcwNTJjYTBiMDViYmExOWQ5ZjZjOWJjMjYwYWQ0NmJjYzg5Y2I4
10
- ZDJhNzUxMTVlY2I4OTAyNDRmMGFiOTJjZDQzNWJkNjQ5ZmQ1ODU1Nzc1Yjgw
11
- Yzk2ZmQ4MTJjOTEyMjFmZjUzZGE3ZTNhMzhiM2JiZGVhZmE1ZWU=
9
+ YjJmYjBjODRlYWJhMmUwNzFiMTIzMjFmZjU5MzExYzRkYjQyMDdjY2I3MGYx
10
+ YjQ3Njg0ZWQzODUxMjQ4ZjllZjAyMmFhZWZjOTE3MzZkZDNmOTAzZjZjODA0
11
+ MjYzMTAxOWU5NzUwNzcyZmMxYjcwZjgyOTRhM2QzNDEyNjI0ZTQ=
12
12
  data.tar.gz: !binary |-
13
- NWJlMzJhOGM2Yjg4NGUwMTRiZDViNzJjNDRlNDRmNTc3ODcxNGExNzM1YmY4
14
- MjZkYTcyMjMxOTEzOWEzYjA4OGQ4ZjBiYjU4MzNmOTA0MzMxYjkyMGVmZjdh
15
- NzNjOTVhZjk5OGNhMzU0NWE5YmY3NjQ1OTFmZTVmY2ZiM2Q3OTE=
13
+ YjQ1MTI1MDg5OGU5YTI3YWVjZThmZjBhZjE3NGMwMGRlZGQxNjM2NTllZGU3
14
+ YjFlNjkwZmU5YWNjMDBhNzU2NDZkOTZkZjE5OTRjMGMyODBlMGVjN2MwZDBj
15
+ YTUyZTM3MjdiZTViNDAwODlmMTYyYTFlNDljYTY3OTFjNTIxMTY=
@@ -1,3 +1,3 @@
1
1
  module AngularGem
2
- VERSION = "1.2.12"
2
+ VERSION = "1.2.13"
3
3
  end
@@ -0,0 +1,1589 @@
1
+ /**
2
+ * @license AngularJS v1.2.13
3
+ * (c) 2010-2014 Google, Inc. http://angularjs.org
4
+ * License: MIT
5
+ */
6
+ (function(window, angular, undefined) {'use strict';
7
+
8
+ /* jshint maxlen: false */
9
+
10
+ /**
11
+ * @ngdoc overview
12
+ * @name ngAnimate
13
+ * @description
14
+ *
15
+ * # ngAnimate
16
+ *
17
+ * The `ngAnimate` module provides support for JavaScript, CSS3 transition and CSS3 keyframe animation hooks within existing core and custom directives.
18
+ *
19
+ * {@installModule animate}
20
+ *
21
+ * <div doc-module-components="ngAnimate"></div>
22
+ *
23
+ * # Usage
24
+ *
25
+ * To see animations in action, all that is required is to define the appropriate CSS classes
26
+ * or to register a JavaScript animation via the myModule.animation() function. The directives that support animation automatically are:
27
+ * `ngRepeat`, `ngInclude`, `ngIf`, `ngSwitch`, `ngShow`, `ngHide`, `ngView` and `ngClass`. Custom directives can take advantage of animation
28
+ * by using the `$animate` service.
29
+ *
30
+ * Below is a more detailed breakdown of the supported animation events provided by pre-existing ng directives:
31
+ *
32
+ * | Directive | Supported Animations |
33
+ * |---------------------------------------------------------- |----------------------------------------------------|
34
+ * | {@link ng.directive:ngRepeat#usage_animations ngRepeat} | enter, leave and move |
35
+ * | {@link ngRoute.directive:ngView#usage_animations ngView} | enter and leave |
36
+ * | {@link ng.directive:ngInclude#usage_animations ngInclude} | enter and leave |
37
+ * | {@link ng.directive:ngSwitch#usage_animations ngSwitch} | enter and leave |
38
+ * | {@link ng.directive:ngIf#usage_animations ngIf} | enter and leave |
39
+ * | {@link ng.directive:ngClass#usage_animations ngClass} | add and remove |
40
+ * | {@link ng.directive:ngShow#usage_animations ngShow & ngHide} | add and remove (the ng-hide class value) |
41
+ *
42
+ * You can find out more information about animations upon visiting each directive page.
43
+ *
44
+ * Below is an example of how to apply animations to a directive that supports animation hooks:
45
+ *
46
+ * <pre>
47
+ * <style type="text/css">
48
+ * .slide.ng-enter, .slide.ng-leave {
49
+ * -webkit-transition:0.5s linear all;
50
+ * transition:0.5s linear all;
51
+ * }
52
+ *
53
+ * .slide.ng-enter { } /&#42; starting animations for enter &#42;/
54
+ * .slide.ng-enter-active { } /&#42; terminal animations for enter &#42;/
55
+ * .slide.ng-leave { } /&#42; starting animations for leave &#42;/
56
+ * .slide.ng-leave-active { } /&#42; terminal animations for leave &#42;/
57
+ * </style>
58
+ *
59
+ * <!--
60
+ * the animate service will automatically add .ng-enter and .ng-leave to the element
61
+ * to trigger the CSS transition/animations
62
+ * -->
63
+ * <ANY class="slide" ng-include="..."></ANY>
64
+ * </pre>
65
+ *
66
+ * Keep in mind that if an animation is running, any child elements cannot be animated until the parent element's
67
+ * animation has completed.
68
+ *
69
+ * <h2>CSS-defined Animations</h2>
70
+ * The animate service will automatically apply two CSS classes to the animated element and these two CSS classes
71
+ * are designed to contain the start and end CSS styling. Both CSS transitions and keyframe animations are supported
72
+ * and can be used to play along with this naming structure.
73
+ *
74
+ * The following code below demonstrates how to perform animations using **CSS transitions** with Angular:
75
+ *
76
+ * <pre>
77
+ * <style type="text/css">
78
+ * /&#42;
79
+ * The animate class is apart of the element and the ng-enter class
80
+ * is attached to the element once the enter animation event is triggered
81
+ * &#42;/
82
+ * .reveal-animation.ng-enter {
83
+ * -webkit-transition: 1s linear all; /&#42; Safari/Chrome &#42;/
84
+ * transition: 1s linear all; /&#42; All other modern browsers and IE10+ &#42;/
85
+ *
86
+ * /&#42; The animation preparation code &#42;/
87
+ * opacity: 0;
88
+ * }
89
+ *
90
+ * /&#42;
91
+ * Keep in mind that you want to combine both CSS
92
+ * classes together to avoid any CSS-specificity
93
+ * conflicts
94
+ * &#42;/
95
+ * .reveal-animation.ng-enter.ng-enter-active {
96
+ * /&#42; The animation code itself &#42;/
97
+ * opacity: 1;
98
+ * }
99
+ * </style>
100
+ *
101
+ * <div class="view-container">
102
+ * <div ng-view class="reveal-animation"></div>
103
+ * </div>
104
+ * </pre>
105
+ *
106
+ * The following code below demonstrates how to perform animations using **CSS animations** with Angular:
107
+ *
108
+ * <pre>
109
+ * <style type="text/css">
110
+ * .reveal-animation.ng-enter {
111
+ * -webkit-animation: enter_sequence 1s linear; /&#42; Safari/Chrome &#42;/
112
+ * animation: enter_sequence 1s linear; /&#42; IE10+ and Future Browsers &#42;/
113
+ * }
114
+ * &#64-webkit-keyframes enter_sequence {
115
+ * from { opacity:0; }
116
+ * to { opacity:1; }
117
+ * }
118
+ * &#64keyframes enter_sequence {
119
+ * from { opacity:0; }
120
+ * to { opacity:1; }
121
+ * }
122
+ * </style>
123
+ *
124
+ * <div class="view-container">
125
+ * <div ng-view class="reveal-animation"></div>
126
+ * </div>
127
+ * </pre>
128
+ *
129
+ * Both CSS3 animations and transitions can be used together and the animate service will figure out the correct duration and delay timing.
130
+ *
131
+ * Upon DOM mutation, the event class is added first (something like `ng-enter`), then the browser prepares itself to add
132
+ * the active class (in this case `ng-enter-active`) which then triggers the animation. The animation module will automatically
133
+ * detect the CSS code to determine when the animation ends. Once the animation is over then both CSS classes will be
134
+ * removed from the DOM. If a browser does not support CSS transitions or CSS animations then the animation will start and end
135
+ * immediately resulting in a DOM element that is at its final state. This final state is when the DOM element
136
+ * has no CSS transition/animation classes applied to it.
137
+ *
138
+ * <h3>CSS Staggering Animations</h3>
139
+ * A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a
140
+ * curtain-like effect. The ngAnimate module, as of 1.2.0, supports staggering animations and the stagger effect can be
141
+ * performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for
142
+ * the animation. The style property expected within the stagger class can either be a **transition-delay** or an
143
+ * **animation-delay** property (or both if your animation contains both transitions and keyframe animations).
144
+ *
145
+ * <pre>
146
+ * .my-animation.ng-enter {
147
+ * /&#42; standard transition code &#42;/
148
+ * -webkit-transition: 1s linear all;
149
+ * transition: 1s linear all;
150
+ * opacity:0;
151
+ * }
152
+ * .my-animation.ng-enter-stagger {
153
+ * /&#42; this will have a 100ms delay between each successive leave animation &#42;/
154
+ * -webkit-transition-delay: 0.1s;
155
+ * transition-delay: 0.1s;
156
+ *
157
+ * /&#42; in case the stagger doesn't work then these two values
158
+ * must be set to 0 to avoid an accidental CSS inheritance &#42;/
159
+ * -webkit-transition-duration: 0s;
160
+ * transition-duration: 0s;
161
+ * }
162
+ * .my-animation.ng-enter.ng-enter-active {
163
+ * /&#42; standard transition styles &#42;/
164
+ * opacity:1;
165
+ * }
166
+ * </pre>
167
+ *
168
+ * Staggering animations work by default in ngRepeat (so long as the CSS class is defined). Outside of ngRepeat, to use staggering animations
169
+ * on your own, they can be triggered by firing multiple calls to the same event on $animate. However, the restrictions surrounding this
170
+ * are that each of the elements must have the same CSS className value as well as the same parent element. A stagger operation
171
+ * will also be reset if more than 10ms has passed after the last animation has been fired.
172
+ *
173
+ * The following code will issue the **ng-leave-stagger** event on the element provided:
174
+ *
175
+ * <pre>
176
+ * var kids = parent.children();
177
+ *
178
+ * $animate.leave(kids[0]); //stagger index=0
179
+ * $animate.leave(kids[1]); //stagger index=1
180
+ * $animate.leave(kids[2]); //stagger index=2
181
+ * $animate.leave(kids[3]); //stagger index=3
182
+ * $animate.leave(kids[4]); //stagger index=4
183
+ *
184
+ * $timeout(function() {
185
+ * //stagger has reset itself
186
+ * $animate.leave(kids[5]); //stagger index=0
187
+ * $animate.leave(kids[6]); //stagger index=1
188
+ * }, 100, false);
189
+ * </pre>
190
+ *
191
+ * Stagger animations are currently only supported within CSS-defined animations.
192
+ *
193
+ * <h2>JavaScript-defined Animations</h2>
194
+ * In the event that you do not want to use CSS3 transitions or CSS3 animations or if you wish to offer animations on browsers that do not
195
+ * yet support CSS transitions/animations, then you can make use of JavaScript animations defined inside of your AngularJS module.
196
+ *
197
+ * <pre>
198
+ * //!annotate="YourApp" Your AngularJS Module|Replace this or ngModule with the module that you used to define your application.
199
+ * var ngModule = angular.module('YourApp', ['ngAnimate']);
200
+ * ngModule.animation('.my-crazy-animation', function() {
201
+ * return {
202
+ * enter: function(element, done) {
203
+ * //run the animation here and call done when the animation is complete
204
+ * return function(cancelled) {
205
+ * //this (optional) function will be called when the animation
206
+ * //completes or when the animation is cancelled (the cancelled
207
+ * //flag will be set to true if cancelled).
208
+ * };
209
+ * },
210
+ * leave: function(element, done) { },
211
+ * move: function(element, done) { },
212
+ *
213
+ * //animation that can be triggered before the class is added
214
+ * beforeAddClass: function(element, className, done) { },
215
+ *
216
+ * //animation that can be triggered after the class is added
217
+ * addClass: function(element, className, done) { },
218
+ *
219
+ * //animation that can be triggered before the class is removed
220
+ * beforeRemoveClass: function(element, className, done) { },
221
+ *
222
+ * //animation that can be triggered after the class is removed
223
+ * removeClass: function(element, className, done) { }
224
+ * };
225
+ * });
226
+ * </pre>
227
+ *
228
+ * JavaScript-defined animations are created with a CSS-like class selector and a collection of events which are set to run
229
+ * a javascript callback function. When an animation is triggered, $animate will look for a matching animation which fits
230
+ * the element's CSS class attribute value and then run the matching animation event function (if found).
231
+ * In other words, if the CSS classes present on the animated element match any of the JavaScript animations then the callback function will
232
+ * be executed. It should be also noted that only simple, single class selectors are allowed (compound class selectors are not supported).
233
+ *
234
+ * Within a JavaScript animation, an object containing various event callback animation functions is expected to be returned.
235
+ * As explained above, these callbacks are triggered based on the animation event. Therefore if an enter animation is run,
236
+ * and the JavaScript animation is found, then the enter callback will handle that animation (in addition to the CSS keyframe animation
237
+ * or transition code that is defined via a stylesheet).
238
+ *
239
+ */
240
+
241
+ angular.module('ngAnimate', ['ng'])
242
+
243
+ /**
244
+ * @ngdoc object
245
+ * @name ngAnimate.$animateProvider
246
+ * @description
247
+ *
248
+ * The `$animateProvider` allows developers to register JavaScript animation event handlers directly inside of a module.
249
+ * When an animation is triggered, the $animate service will query the $animate service to find any animations that match
250
+ * the provided name value.
251
+ *
252
+ * Requires the {@link ngAnimate `ngAnimate`} module to be installed.
253
+ *
254
+ * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application.
255
+ *
256
+ */
257
+ .factory('$$animateReflow', ['$window', '$timeout', '$document',
258
+ function($window, $timeout, $document) {
259
+ var bod = $document[0].body;
260
+ var requestAnimationFrame = $window.requestAnimationFrame ||
261
+ $window.webkitRequestAnimationFrame ||
262
+ function(fn) {
263
+ return $timeout(fn, 10, false);
264
+ };
265
+
266
+ var cancelAnimationFrame = $window.cancelAnimationFrame ||
267
+ $window.webkitCancelAnimationFrame ||
268
+ function(timer) {
269
+ return $timeout.cancel(timer);
270
+ };
271
+ return function(fn) {
272
+ var id = requestAnimationFrame(function() {
273
+ var a = bod.offsetWidth + 1;
274
+ fn();
275
+ });
276
+ return function() {
277
+ cancelAnimationFrame(id);
278
+ };
279
+ };
280
+ }])
281
+
282
+ .factory('$$asyncQueueBuffer', ['$timeout', function($timeout) {
283
+ var timer, queue = [];
284
+ return function(fn) {
285
+ $timeout.cancel(timer);
286
+ queue.push(fn);
287
+ timer = $timeout(function() {
288
+ for(var i = 0; i < queue.length; i++) {
289
+ queue[i]();
290
+ }
291
+ queue = [];
292
+ }, 0, false);
293
+ };
294
+ }])
295
+
296
+ .config(['$provide', '$animateProvider', function($provide, $animateProvider) {
297
+ var noop = angular.noop;
298
+ var forEach = angular.forEach;
299
+ var selectors = $animateProvider.$$selectors;
300
+
301
+ var ELEMENT_NODE = 1;
302
+ var NG_ANIMATE_STATE = '$$ngAnimateState';
303
+ var NG_ANIMATE_CLASS_NAME = 'ng-animate';
304
+ var rootAnimateState = {running: true};
305
+
306
+ function extractElementNode(element) {
307
+ for(var i = 0; i < element.length; i++) {
308
+ var elm = element[i];
309
+ if(elm.nodeType == ELEMENT_NODE) {
310
+ return elm;
311
+ }
312
+ }
313
+ }
314
+
315
+ function stripCommentsFromElement(element) {
316
+ return angular.element(extractElementNode(element));
317
+ }
318
+
319
+ function isMatchingElement(elm1, elm2) {
320
+ return extractElementNode(elm1) == extractElementNode(elm2);
321
+ }
322
+
323
+ $provide.decorator('$animate', ['$delegate', '$injector', '$sniffer', '$rootElement', '$$asyncQueueBuffer', '$rootScope', '$document',
324
+ function($delegate, $injector, $sniffer, $rootElement, $$asyncQueueBuffer, $rootScope, $document) {
325
+
326
+ var globalAnimationCounter = 0;
327
+ $rootElement.data(NG_ANIMATE_STATE, rootAnimateState);
328
+
329
+ // disable animations during bootstrap, but once we bootstrapped, wait again
330
+ // for another digest until enabling animations. The reason why we digest twice
331
+ // is because all structural animations (enter, leave and move) all perform a
332
+ // post digest operation before animating. If we only wait for a single digest
333
+ // to pass then the structural animation would render its animation on page load.
334
+ // (which is what we're trying to avoid when the application first boots up.)
335
+ $rootScope.$$postDigest(function() {
336
+ $rootScope.$$postDigest(function() {
337
+ rootAnimateState.running = false;
338
+ });
339
+ });
340
+
341
+ var classNameFilter = $animateProvider.classNameFilter();
342
+ var isAnimatableClassName = !classNameFilter
343
+ ? function() { return true; }
344
+ : function(className) {
345
+ return classNameFilter.test(className);
346
+ };
347
+
348
+ function lookup(name) {
349
+ if (name) {
350
+ var matches = [],
351
+ flagMap = {},
352
+ classes = name.substr(1).split('.');
353
+
354
+ //the empty string value is the default animation
355
+ //operation which performs CSS transition and keyframe
356
+ //animations sniffing. This is always included for each
357
+ //element animation procedure if the browser supports
358
+ //transitions and/or keyframe animations
359
+ if ($sniffer.transitions || $sniffer.animations) {
360
+ classes.push('');
361
+ }
362
+
363
+ for(var i=0; i < classes.length; i++) {
364
+ var klass = classes[i],
365
+ selectorFactoryName = selectors[klass];
366
+ if(selectorFactoryName && !flagMap[klass]) {
367
+ matches.push($injector.get(selectorFactoryName));
368
+ flagMap[klass] = true;
369
+ }
370
+ }
371
+ return matches;
372
+ }
373
+ }
374
+
375
+ /**
376
+ * @ngdoc object
377
+ * @name ngAnimate.$animate
378
+ * @function
379
+ *
380
+ * @description
381
+ * The `$animate` service provides animation detection support while performing DOM operations (enter, leave and move) as well as during addClass and removeClass operations.
382
+ * When any of these operations are run, the $animate service
383
+ * will examine any JavaScript-defined animations (which are defined by using the $animateProvider provider object)
384
+ * as well as any CSS-defined animations against the CSS classes present on the element once the DOM operation is run.
385
+ *
386
+ * The `$animate` service is used behind the scenes with pre-existing directives and animation with these directives
387
+ * will work out of the box without any extra configuration.
388
+ *
389
+ * Requires the {@link ngAnimate `ngAnimate`} module to be installed.
390
+ *
391
+ * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application.
392
+ *
393
+ */
394
+ return {
395
+ /**
396
+ * @ngdoc function
397
+ * @name ngAnimate.$animate#enter
398
+ * @methodOf ngAnimate.$animate
399
+ * @function
400
+ *
401
+ * @description
402
+ * Appends the element to the parentElement element that resides in the document and then runs the enter animation. Once
403
+ * the animation is started, the following CSS classes will be present on the element for the duration of the animation:
404
+ *
405
+ * Below is a breakdown of each step that occurs during enter animation:
406
+ *
407
+ * | Animation Step | What the element class attribute looks like |
408
+ * |----------------------------------------------------------------------------------------------|---------------------------------------------|
409
+ * | 1. $animate.enter(...) is called | class="my-animation" |
410
+ * | 2. element is inserted into the parentElement element or beside the afterElement element | class="my-animation" |
411
+ * | 3. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
412
+ * | 4. the .ng-enter class is added to the element | class="my-animation ng-animate ng-enter" |
413
+ * | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-enter" |
414
+ * | 6. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-enter" |
415
+ * | 7. the .ng-enter-active and .ng-animate-active classes are added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-enter ng-enter-active" |
416
+ * | 8. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-enter ng-enter-active" |
417
+ * | 9. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
418
+ * | 10. The doneCallback() callback is fired (if provided) | class="my-animation" |
419
+ *
420
+ * @param {jQuery/jqLite element} element the element that will be the focus of the enter animation
421
+ * @param {jQuery/jqLite element} parentElement the parent element of the element that will be the focus of the enter animation
422
+ * @param {jQuery/jqLite element} afterElement the sibling element (which is the previous element) of the element that will be the focus of the enter animation
423
+ * @param {function()=} doneCallback the callback function that will be called once the animation is complete
424
+ */
425
+ enter : function(element, parentElement, afterElement, doneCallback) {
426
+ this.enabled(false, element);
427
+ $delegate.enter(element, parentElement, afterElement);
428
+ $rootScope.$$postDigest(function() {
429
+ element = stripCommentsFromElement(element);
430
+ performAnimation('enter', 'ng-enter', element, parentElement, afterElement, noop, doneCallback);
431
+ });
432
+ },
433
+
434
+ /**
435
+ * @ngdoc function
436
+ * @name ngAnimate.$animate#leave
437
+ * @methodOf ngAnimate.$animate
438
+ * @function
439
+ *
440
+ * @description
441
+ * Runs the leave animation operation and, upon completion, removes the element from the DOM. Once
442
+ * the animation is started, the following CSS classes will be added for the duration of the animation:
443
+ *
444
+ * Below is a breakdown of each step that occurs during leave animation:
445
+ *
446
+ * | Animation Step | What the element class attribute looks like |
447
+ * |----------------------------------------------------------------------------------------------|---------------------------------------------|
448
+ * | 1. $animate.leave(...) is called | class="my-animation" |
449
+ * | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
450
+ * | 3. the .ng-leave class is added to the element | class="my-animation ng-animate ng-leave" |
451
+ * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-leave" |
452
+ * | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-leave" |
453
+ * | 6. the .ng-leave-active and .ng-animate-active classes is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-leave ng-leave-active" |
454
+ * | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-leave ng-leave-active" |
455
+ * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
456
+ * | 9. The element is removed from the DOM | ... |
457
+ * | 10. The doneCallback() callback is fired (if provided) | ... |
458
+ *
459
+ * @param {jQuery/jqLite element} element the element that will be the focus of the leave animation
460
+ * @param {function()=} doneCallback the callback function that will be called once the animation is complete
461
+ */
462
+ leave : function(element, doneCallback) {
463
+ cancelChildAnimations(element);
464
+ this.enabled(false, element);
465
+ $rootScope.$$postDigest(function() {
466
+ element = stripCommentsFromElement(element);
467
+ performAnimation('leave', 'ng-leave', element, null, null, function() {
468
+ $delegate.leave(element);
469
+ }, doneCallback);
470
+ });
471
+ },
472
+
473
+ /**
474
+ * @ngdoc function
475
+ * @name ngAnimate.$animate#move
476
+ * @methodOf ngAnimate.$animate
477
+ * @function
478
+ *
479
+ * @description
480
+ * Fires the move DOM operation. Just before the animation starts, the animate service will either append it into the parentElement container or
481
+ * add the element directly after the afterElement element if present. Then the move animation will be run. Once
482
+ * the animation is started, the following CSS classes will be added for the duration of the animation:
483
+ *
484
+ * Below is a breakdown of each step that occurs during move animation:
485
+ *
486
+ * | Animation Step | What the element class attribute looks like |
487
+ * |----------------------------------------------------------------------------------------------|---------------------------------------------|
488
+ * | 1. $animate.move(...) is called | class="my-animation" |
489
+ * | 2. element is moved into the parentElement element or beside the afterElement element | class="my-animation" |
490
+ * | 3. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
491
+ * | 4. the .ng-move class is added to the element | class="my-animation ng-animate ng-move" |
492
+ * | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-move" |
493
+ * | 6. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-move" |
494
+ * | 7. the .ng-move-active and .ng-animate-active classes is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-move ng-move-active" |
495
+ * | 8. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-move ng-move-active" |
496
+ * | 9. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
497
+ * | 10. The doneCallback() callback is fired (if provided) | class="my-animation" |
498
+ *
499
+ * @param {jQuery/jqLite element} element the element that will be the focus of the move animation
500
+ * @param {jQuery/jqLite element} parentElement the parentElement element of the element that will be the focus of the move animation
501
+ * @param {jQuery/jqLite element} afterElement the sibling element (which is the previous element) of the element that will be the focus of the move animation
502
+ * @param {function()=} doneCallback the callback function that will be called once the animation is complete
503
+ */
504
+ move : function(element, parentElement, afterElement, doneCallback) {
505
+ cancelChildAnimations(element);
506
+ this.enabled(false, element);
507
+ $delegate.move(element, parentElement, afterElement);
508
+ $rootScope.$$postDigest(function() {
509
+ element = stripCommentsFromElement(element);
510
+ performAnimation('move', 'ng-move', element, parentElement, afterElement, noop, doneCallback);
511
+ });
512
+ },
513
+
514
+ /**
515
+ * @ngdoc function
516
+ * @name ngAnimate.$animate#addClass
517
+ * @methodOf ngAnimate.$animate
518
+ *
519
+ * @description
520
+ * Triggers a custom animation event based off the className variable and then attaches the className value to the element as a CSS class.
521
+ * Unlike the other animation methods, the animate service will suffix the className value with {@type -add} in order to provide
522
+ * the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if no CSS transitions
523
+ * or keyframes are defined on the -add or base CSS class).
524
+ *
525
+ * Below is a breakdown of each step that occurs during addClass animation:
526
+ *
527
+ * | Animation Step | What the element class attribute looks like |
528
+ * |------------------------------------------------------------------------------------------------|---------------------------------------------|
529
+ * | 1. $animate.addClass(element, 'super') is called | class="my-animation" |
530
+ * | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
531
+ * | 3. the .super-add class are added to the element | class="my-animation ng-animate super-add" |
532
+ * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate super-add" |
533
+ * | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate super-add" |
534
+ * | 6. the .super, .super-add-active and .ng-animate-active classes are added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active super super-add super-add-active" |
535
+ * | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation super-add super-add-active" |
536
+ * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation super" |
537
+ * | 9. The super class is kept on the element | class="my-animation super" |
538
+ * | 10. The doneCallback() callback is fired (if provided) | class="my-animation super" |
539
+ *
540
+ * @param {jQuery/jqLite element} element the element that will be animated
541
+ * @param {string} className the CSS class that will be added to the element and then animated
542
+ * @param {function()=} doneCallback the callback function that will be called once the animation is complete
543
+ */
544
+ addClass : function(element, className, doneCallback) {
545
+ element = stripCommentsFromElement(element);
546
+ performAnimation('addClass', className, element, null, null, function() {
547
+ $delegate.addClass(element, className);
548
+ }, doneCallback);
549
+ },
550
+
551
+ /**
552
+ * @ngdoc function
553
+ * @name ngAnimate.$animate#removeClass
554
+ * @methodOf ngAnimate.$animate
555
+ *
556
+ * @description
557
+ * Triggers a custom animation event based off the className variable and then removes the CSS class provided by the className value
558
+ * from the element. Unlike the other animation methods, the animate service will suffix the className value with {@type -remove} in
559
+ * order to provide the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if
560
+ * no CSS transitions or keyframes are defined on the -remove or base CSS classes).
561
+ *
562
+ * Below is a breakdown of each step that occurs during removeClass animation:
563
+ *
564
+ * | Animation Step | What the element class attribute looks like |
565
+ * |-----------------------------------------------------------------------------------------------|---------------------------------------------|
566
+ * | 1. $animate.removeClass(element, 'super') is called | class="my-animation super" |
567
+ * | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation super ng-animate" |
568
+ * | 3. the .super-remove class are added to the element | class="my-animation super ng-animate super-remove"|
569
+ * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation super ng-animate super-remove" |
570
+ * | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation super ng-animate super-remove" |
571
+ * | 6. the .super-remove-active and .ng-animate-active classes are added and .super is removed (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active super-remove super-remove-active" |
572
+ * | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active super-remove super-remove-active" |
573
+ * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
574
+ * | 9. The doneCallback() callback is fired (if provided) | class="my-animation" |
575
+ *
576
+ *
577
+ * @param {jQuery/jqLite element} element the element that will be animated
578
+ * @param {string} className the CSS class that will be animated and then removed from the element
579
+ * @param {function()=} doneCallback the callback function that will be called once the animation is complete
580
+ */
581
+ removeClass : function(element, className, doneCallback) {
582
+ element = stripCommentsFromElement(element);
583
+ performAnimation('removeClass', className, element, null, null, function() {
584
+ $delegate.removeClass(element, className);
585
+ }, doneCallback);
586
+ },
587
+
588
+ /**
589
+ *
590
+ * @ngdoc function
591
+ * @name ng.$animate#setClass
592
+ * @methodOf ng.$animate
593
+ * @function
594
+ * @description Adds and/or removes the given CSS classes to and from the element.
595
+ * Once complete, the done() callback will be fired (if provided).
596
+ * @param {jQuery/jqLite element} element the element which will it's CSS classes changed
597
+ * removed from it
598
+ * @param {string} add the CSS classes which will be added to the element
599
+ * @param {string} remove the CSS class which will be removed from the element
600
+ * @param {function=} done the callback function (if provided) that will be fired after the
601
+ * CSS classes have been set on the element
602
+ */
603
+ setClass : function(element, add, remove, doneCallback) {
604
+ element = stripCommentsFromElement(element);
605
+ performAnimation('setClass', [add, remove], element, null, null, function() {
606
+ $delegate.setClass(element, add, remove);
607
+ }, doneCallback);
608
+ },
609
+
610
+ /**
611
+ * @ngdoc function
612
+ * @name ngAnimate.$animate#enabled
613
+ * @methodOf ngAnimate.$animate
614
+ * @function
615
+ *
616
+ * @param {boolean=} value If provided then set the animation on or off.
617
+ * @param {jQuery/jqLite element=} element If provided then the element will be used to represent the enable/disable operation
618
+ * @return {boolean} Current animation state.
619
+ *
620
+ * @description
621
+ * Globally enables/disables animations.
622
+ *
623
+ */
624
+ enabled : function(value, element) {
625
+ switch(arguments.length) {
626
+ case 2:
627
+ if(value) {
628
+ cleanup(element);
629
+ } else {
630
+ var data = element.data(NG_ANIMATE_STATE) || {};
631
+ data.disabled = true;
632
+ element.data(NG_ANIMATE_STATE, data);
633
+ }
634
+ break;
635
+
636
+ case 1:
637
+ rootAnimateState.disabled = !value;
638
+ break;
639
+
640
+ default:
641
+ value = !rootAnimateState.disabled;
642
+ break;
643
+ }
644
+ return !!value;
645
+ }
646
+ };
647
+
648
+ /*
649
+ all animations call this shared animation triggering function internally.
650
+ The animationEvent variable refers to the JavaScript animation event that will be triggered
651
+ and the className value is the name of the animation that will be applied within the
652
+ CSS code. Element, parentElement and afterElement are provided DOM elements for the animation
653
+ and the onComplete callback will be fired once the animation is fully complete.
654
+ */
655
+ function performAnimation(animationEvent, className, element, parentElement, afterElement, domOperation, doneCallback) {
656
+
657
+ var classNameAdd, classNameRemove, setClassOperation = animationEvent == 'setClass';
658
+ if(setClassOperation) {
659
+ classNameAdd = className[0];
660
+ classNameRemove = className[1];
661
+ className = classNameAdd + ' ' + classNameRemove;
662
+ }
663
+
664
+ var currentClassName, classes, node = element[0];
665
+ if(node) {
666
+ currentClassName = node.className;
667
+ classes = currentClassName + ' ' + className;
668
+ }
669
+
670
+ //transcluded directives may sometimes fire an animation using only comment nodes
671
+ //best to catch this early on to prevent any animation operations from occurring
672
+ if(!node || !isAnimatableClassName(classes)) {
673
+ fireDOMOperation();
674
+ fireBeforeCallbackAsync();
675
+ fireAfterCallbackAsync();
676
+ fireDoneCallbackAsync();
677
+ return;
678
+ }
679
+
680
+ var elementEvents = angular.element._data(node);
681
+ elementEvents = elementEvents && elementEvents.events;
682
+
683
+ var animationLookup = (' ' + classes).replace(/\s+/g,'.');
684
+ if (!parentElement) {
685
+ parentElement = afterElement ? afterElement.parent() : element.parent();
686
+ }
687
+
688
+ var matches = lookup(animationLookup);
689
+ var isClassBased = animationEvent == 'addClass' ||
690
+ animationEvent == 'removeClass' ||
691
+ setClassOperation;
692
+ var ngAnimateState = element.data(NG_ANIMATE_STATE) || {};
693
+
694
+ var runningAnimations = ngAnimateState.active || {};
695
+ var totalActiveAnimations = ngAnimateState.totalActive || 0;
696
+ var lastAnimation = ngAnimateState.last;
697
+
698
+ //skip the animation if animations are disabled, a parent is already being animated,
699
+ //the element is not currently attached to the document body or then completely close
700
+ //the animation if any matching animations are not found at all.
701
+ //NOTE: IE8 + IE9 should close properly (run closeAnimation()) in case a NO animation is not found.
702
+ if (animationsDisabled(element, parentElement) || matches.length === 0) {
703
+ fireDOMOperation();
704
+ fireBeforeCallbackAsync();
705
+ fireAfterCallbackAsync();
706
+ closeAnimation();
707
+ return;
708
+ }
709
+
710
+ var animations = [];
711
+
712
+ //only add animations if the currently running animation is not structural
713
+ //or if there is no animation running at all
714
+ var allowAnimations = isClassBased ?
715
+ !ngAnimateState.disabled && (!lastAnimation || lastAnimation.classBased) :
716
+ true;
717
+
718
+ if(allowAnimations) {
719
+ forEach(matches, function(animation) {
720
+ //add the animation to the queue to if it is allowed to be cancelled
721
+ if(!animation.allowCancel || animation.allowCancel(element, animationEvent, className)) {
722
+ var beforeFn, afterFn = animation[animationEvent];
723
+
724
+ //Special case for a leave animation since there is no point in performing an
725
+ //animation on a element node that has already been removed from the DOM
726
+ if(animationEvent == 'leave') {
727
+ beforeFn = afterFn;
728
+ afterFn = null; //this must be falsy so that the animation is skipped for leave
729
+ } else {
730
+ beforeFn = animation['before' + animationEvent.charAt(0).toUpperCase() + animationEvent.substr(1)];
731
+ }
732
+ animations.push({
733
+ before : beforeFn,
734
+ after : afterFn
735
+ });
736
+ }
737
+ });
738
+ }
739
+
740
+ //this would mean that an animation was not allowed so let the existing
741
+ //animation do it's thing and close this one early
742
+ if(animations.length === 0) {
743
+ fireDOMOperation();
744
+ fireBeforeCallbackAsync();
745
+ fireAfterCallbackAsync();
746
+ fireDoneCallbackAsync();
747
+ return;
748
+ }
749
+
750
+ var skipAnimation = false;
751
+ if(totalActiveAnimations > 0) {
752
+ var animationsToCancel = [];
753
+ if(!isClassBased) {
754
+ if(animationEvent == 'leave' && runningAnimations['ng-leave']) {
755
+ skipAnimation = true;
756
+ } else {
757
+ //cancel all animations when a structural animation takes place
758
+ for(var klass in runningAnimations) {
759
+ animationsToCancel.push(runningAnimations[klass]);
760
+ cleanup(element, klass);
761
+ }
762
+ runningAnimations = {};
763
+ totalActiveAnimations = 0;
764
+ }
765
+ } else if(lastAnimation.event == 'setClass') {
766
+ animationsToCancel.push(lastAnimation);
767
+ cleanup(element, className);
768
+ }
769
+ else if(runningAnimations[className]) {
770
+ var current = runningAnimations[className];
771
+ if(current.event == animationEvent) {
772
+ skipAnimation = true;
773
+ } else {
774
+ animationsToCancel.push(current);
775
+ cleanup(element, className);
776
+ }
777
+ }
778
+
779
+ if(animationsToCancel.length > 0) {
780
+ angular.forEach(animationsToCancel, function(operation) {
781
+ (operation.done || noop)(true);
782
+ cancelAnimations(operation.animations);
783
+ });
784
+ }
785
+ }
786
+
787
+ if(isClassBased && !setClassOperation && !skipAnimation) {
788
+ skipAnimation = (animationEvent == 'addClass') == element.hasClass(className); //opposite of XOR
789
+ }
790
+
791
+ if(skipAnimation) {
792
+ fireBeforeCallbackAsync();
793
+ fireAfterCallbackAsync();
794
+ fireDoneCallbackAsync();
795
+ return;
796
+ }
797
+
798
+ //the ng-animate class does nothing, but it's here to allow for
799
+ //parent animations to find and cancel child animations when needed
800
+ element.addClass(NG_ANIMATE_CLASS_NAME);
801
+
802
+ var localAnimationCount = globalAnimationCounter++;
803
+ lastAnimation = {
804
+ classBased : isClassBased,
805
+ event : animationEvent,
806
+ animations : animations,
807
+ done:onBeforeAnimationsComplete
808
+ };
809
+
810
+ totalActiveAnimations++;
811
+ runningAnimations[className] = lastAnimation;
812
+
813
+ element.data(NG_ANIMATE_STATE, {
814
+ last : lastAnimation,
815
+ active : runningAnimations,
816
+ index : localAnimationCount,
817
+ totalActive : totalActiveAnimations
818
+ });
819
+
820
+ //first we run the before animations and when all of those are complete
821
+ //then we perform the DOM operation and run the next set of animations
822
+ invokeRegisteredAnimationFns(animations, 'before', onBeforeAnimationsComplete);
823
+
824
+ function onBeforeAnimationsComplete(cancelled) {
825
+ var data = element.data(NG_ANIMATE_STATE);
826
+ cancelled = cancelled ||
827
+ !data || !data.active[className] ||
828
+ (isClassBased && data.active[className].event != animationEvent);
829
+
830
+ fireDOMOperation();
831
+ if(cancelled === true) {
832
+ closeAnimation();
833
+ return;
834
+ }
835
+
836
+ //set the done function to the final done function
837
+ //so that the DOM event won't be executed twice by accident
838
+ //if the after animation is cancelled as well
839
+ var currentAnimation = data.active[className];
840
+ currentAnimation.done = closeAnimation;
841
+ invokeRegisteredAnimationFns(animations, 'after', closeAnimation);
842
+ }
843
+
844
+ function invokeRegisteredAnimationFns(animations, phase, allAnimationFnsComplete) {
845
+ phase == 'after' ?
846
+ fireAfterCallbackAsync() :
847
+ fireBeforeCallbackAsync();
848
+
849
+ var endFnName = phase + 'End';
850
+ forEach(animations, function(animation, index) {
851
+ var animationPhaseCompleted = function() {
852
+ progress(index, phase);
853
+ };
854
+
855
+ //there are no before functions for enter + move since the DOM
856
+ //operations happen before the performAnimation method fires
857
+ if(phase == 'before' && (animationEvent == 'enter' || animationEvent == 'move')) {
858
+ animationPhaseCompleted();
859
+ return;
860
+ }
861
+
862
+ if(animation[phase]) {
863
+ if(setClassOperation) {
864
+ animation[endFnName] = animation[phase](element, classNameAdd, classNameRemove, animationPhaseCompleted);
865
+ } else {
866
+ animation[endFnName] = isClassBased ?
867
+ animation[phase](element, className, animationPhaseCompleted) :
868
+ animation[phase](element, animationPhaseCompleted);
869
+ }
870
+ } else {
871
+ animationPhaseCompleted();
872
+ }
873
+ });
874
+
875
+ function progress(index, phase) {
876
+ var phaseCompletionFlag = phase + 'Complete';
877
+ var currentAnimation = animations[index];
878
+ currentAnimation[phaseCompletionFlag] = true;
879
+ (currentAnimation[endFnName] || noop)();
880
+
881
+ for(var i=0;i<animations.length;i++) {
882
+ if(!animations[i][phaseCompletionFlag]) return;
883
+ }
884
+
885
+ allAnimationFnsComplete();
886
+ }
887
+ }
888
+
889
+ function fireDOMCallback(animationPhase) {
890
+ var eventName = '$animate:' + animationPhase;
891
+ if(elementEvents && elementEvents[eventName] && elementEvents[eventName].length > 0) {
892
+ $$asyncQueueBuffer(function() {
893
+ element.triggerHandler(eventName, {
894
+ event : animationEvent,
895
+ className : className
896
+ });
897
+ });
898
+ }
899
+ }
900
+
901
+ function fireBeforeCallbackAsync() {
902
+ fireDOMCallback('before');
903
+ }
904
+
905
+ function fireAfterCallbackAsync() {
906
+ fireDOMCallback('after');
907
+ }
908
+
909
+ function fireDoneCallbackAsync() {
910
+ fireDOMCallback('close');
911
+ if(doneCallback) {
912
+ $$asyncQueueBuffer(function() {
913
+ doneCallback();
914
+ });
915
+ }
916
+ }
917
+
918
+ //it is less complicated to use a flag than managing and cancelling
919
+ //timeouts containing multiple callbacks.
920
+ function fireDOMOperation() {
921
+ if(!fireDOMOperation.hasBeenRun) {
922
+ fireDOMOperation.hasBeenRun = true;
923
+ domOperation();
924
+ }
925
+ }
926
+
927
+ function closeAnimation() {
928
+ if(!closeAnimation.hasBeenRun) {
929
+ closeAnimation.hasBeenRun = true;
930
+ var data = element.data(NG_ANIMATE_STATE);
931
+ if(data) {
932
+ /* only structural animations wait for reflow before removing an
933
+ animation, but class-based animations don't. An example of this
934
+ failing would be when a parent HTML tag has a ng-class attribute
935
+ causing ALL directives below to skip animations during the digest */
936
+ if(isClassBased) {
937
+ cleanup(element, className);
938
+ } else {
939
+ $$asyncQueueBuffer(function() {
940
+ var data = element.data(NG_ANIMATE_STATE) || {};
941
+ if(localAnimationCount == data.index) {
942
+ cleanup(element, className, animationEvent);
943
+ }
944
+ });
945
+ element.data(NG_ANIMATE_STATE, data);
946
+ }
947
+ }
948
+ fireDoneCallbackAsync();
949
+ }
950
+ }
951
+ }
952
+
953
+ function cancelChildAnimations(element) {
954
+ var node = extractElementNode(element);
955
+ forEach(node.querySelectorAll('.' + NG_ANIMATE_CLASS_NAME), function(element) {
956
+ element = angular.element(element);
957
+ var data = element.data(NG_ANIMATE_STATE);
958
+ if(data && data.active) {
959
+ angular.forEach(data.active, function(operation) {
960
+ (operation.done || noop)(true);
961
+ cancelAnimations(operation.animations);
962
+ });
963
+ }
964
+ });
965
+ }
966
+
967
+ function cancelAnimations(animations) {
968
+ var isCancelledFlag = true;
969
+ forEach(animations, function(animation) {
970
+ if(!animation.beforeComplete) {
971
+ (animation.beforeEnd || noop)(isCancelledFlag);
972
+ }
973
+ if(!animation.afterComplete) {
974
+ (animation.afterEnd || noop)(isCancelledFlag);
975
+ }
976
+ });
977
+ }
978
+
979
+ function cleanup(element, className) {
980
+ if(isMatchingElement(element, $rootElement)) {
981
+ if(!rootAnimateState.disabled) {
982
+ rootAnimateState.running = false;
983
+ rootAnimateState.structural = false;
984
+ }
985
+ } else if(className) {
986
+ var data = element.data(NG_ANIMATE_STATE) || {};
987
+
988
+ var removeAnimations = className === true;
989
+ if(!removeAnimations) {
990
+ if(data.active && data.active[className]) {
991
+ data.totalActive--;
992
+ delete data.active[className];
993
+ }
994
+ }
995
+
996
+ if(removeAnimations || !data.totalActive) {
997
+ element.removeClass(NG_ANIMATE_CLASS_NAME);
998
+ element.removeData(NG_ANIMATE_STATE);
999
+ }
1000
+ }
1001
+ }
1002
+
1003
+ function animationsDisabled(element, parentElement) {
1004
+ if (rootAnimateState.disabled) return true;
1005
+
1006
+ if(isMatchingElement(element, $rootElement)) {
1007
+ return rootAnimateState.disabled || rootAnimateState.running;
1008
+ }
1009
+
1010
+ do {
1011
+ //the element did not reach the root element which means that it
1012
+ //is not apart of the DOM. Therefore there is no reason to do
1013
+ //any animations on it
1014
+ if(parentElement.length === 0) break;
1015
+
1016
+ var isRoot = isMatchingElement(parentElement, $rootElement);
1017
+ var state = isRoot ? rootAnimateState : parentElement.data(NG_ANIMATE_STATE);
1018
+ var result = state && (!!state.disabled || state.running || state.totalActive > 0);
1019
+ if(isRoot || result) {
1020
+ return result;
1021
+ }
1022
+
1023
+ if(isRoot) return true;
1024
+ }
1025
+ while(parentElement = parentElement.parent());
1026
+
1027
+ return true;
1028
+ }
1029
+ }]);
1030
+
1031
+ $animateProvider.register('', ['$window', '$sniffer', '$timeout', '$$animateReflow',
1032
+ function($window, $sniffer, $timeout, $$animateReflow) {
1033
+ // Detect proper transitionend/animationend event names.
1034
+ var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT;
1035
+
1036
+ // If unprefixed events are not supported but webkit-prefixed are, use the latter.
1037
+ // Otherwise, just use W3C names, browsers not supporting them at all will just ignore them.
1038
+ // Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend`
1039
+ // but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`.
1040
+ // Register both events in case `window.onanimationend` is not supported because of that,
1041
+ // do the same for `transitionend` as Safari is likely to exhibit similar behavior.
1042
+ // Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit
1043
+ // therefore there is no reason to test anymore for other vendor prefixes: http://caniuse.com/#search=transition
1044
+ if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) {
1045
+ CSS_PREFIX = '-webkit-';
1046
+ TRANSITION_PROP = 'WebkitTransition';
1047
+ TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
1048
+ } else {
1049
+ TRANSITION_PROP = 'transition';
1050
+ TRANSITIONEND_EVENT = 'transitionend';
1051
+ }
1052
+
1053
+ if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) {
1054
+ CSS_PREFIX = '-webkit-';
1055
+ ANIMATION_PROP = 'WebkitAnimation';
1056
+ ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';
1057
+ } else {
1058
+ ANIMATION_PROP = 'animation';
1059
+ ANIMATIONEND_EVENT = 'animationend';
1060
+ }
1061
+
1062
+ var DURATION_KEY = 'Duration';
1063
+ var PROPERTY_KEY = 'Property';
1064
+ var DELAY_KEY = 'Delay';
1065
+ var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';
1066
+ var NG_ANIMATE_PARENT_KEY = '$$ngAnimateKey';
1067
+ var NG_ANIMATE_CSS_DATA_KEY = '$$ngAnimateCSS3Data';
1068
+ var NG_ANIMATE_BLOCK_CLASS_NAME = 'ng-animate-block-transitions';
1069
+ var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;
1070
+ var CLOSING_TIME_BUFFER = 1.5;
1071
+ var ONE_SECOND = 1000;
1072
+
1073
+ var lookupCache = {};
1074
+ var parentCounter = 0;
1075
+ var animationReflowQueue = [];
1076
+ var cancelAnimationReflow;
1077
+ function afterReflow(element, callback) {
1078
+ if(cancelAnimationReflow) {
1079
+ cancelAnimationReflow();
1080
+ }
1081
+ animationReflowQueue.push(callback);
1082
+ cancelAnimationReflow = $$animateReflow(function() {
1083
+ forEach(animationReflowQueue, function(fn) {
1084
+ fn();
1085
+ });
1086
+
1087
+ animationReflowQueue = [];
1088
+ cancelAnimationReflow = null;
1089
+ lookupCache = {};
1090
+ });
1091
+ }
1092
+
1093
+ var closingTimer = null;
1094
+ var closingTimestamp = 0;
1095
+ var animationElementQueue = [];
1096
+ function animationCloseHandler(element, totalTime) {
1097
+ var futureTimestamp = Date.now() + (totalTime * 1000);
1098
+ if(futureTimestamp <= closingTimestamp) {
1099
+ return;
1100
+ }
1101
+
1102
+ $timeout.cancel(closingTimer);
1103
+
1104
+ var node = extractElementNode(element);
1105
+ element = angular.element(node);
1106
+ animationElementQueue.push(element);
1107
+
1108
+ closingTimestamp = futureTimestamp;
1109
+ closingTimer = $timeout(function() {
1110
+ closeAllAnimations(animationElementQueue);
1111
+ animationElementQueue = [];
1112
+ }, totalTime, false);
1113
+ }
1114
+
1115
+ function closeAllAnimations(elements) {
1116
+ forEach(elements, function(element) {
1117
+ var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
1118
+ if(elementData) {
1119
+ (elementData.closeAnimationFn || noop)();
1120
+ }
1121
+ });
1122
+ }
1123
+
1124
+ function getElementAnimationDetails(element, cacheKey) {
1125
+ var data = cacheKey ? lookupCache[cacheKey] : null;
1126
+ if(!data) {
1127
+ var transitionDuration = 0;
1128
+ var transitionDelay = 0;
1129
+ var animationDuration = 0;
1130
+ var animationDelay = 0;
1131
+ var transitionDelayStyle;
1132
+ var animationDelayStyle;
1133
+ var transitionDurationStyle;
1134
+ var transitionPropertyStyle;
1135
+
1136
+ //we want all the styles defined before and after
1137
+ forEach(element, function(element) {
1138
+ if (element.nodeType == ELEMENT_NODE) {
1139
+ var elementStyles = $window.getComputedStyle(element) || {};
1140
+
1141
+ transitionDurationStyle = elementStyles[TRANSITION_PROP + DURATION_KEY];
1142
+
1143
+ transitionDuration = Math.max(parseMaxTime(transitionDurationStyle), transitionDuration);
1144
+
1145
+ transitionPropertyStyle = elementStyles[TRANSITION_PROP + PROPERTY_KEY];
1146
+
1147
+ transitionDelayStyle = elementStyles[TRANSITION_PROP + DELAY_KEY];
1148
+
1149
+ transitionDelay = Math.max(parseMaxTime(transitionDelayStyle), transitionDelay);
1150
+
1151
+ animationDelayStyle = elementStyles[ANIMATION_PROP + DELAY_KEY];
1152
+
1153
+ animationDelay = Math.max(parseMaxTime(animationDelayStyle), animationDelay);
1154
+
1155
+ var aDuration = parseMaxTime(elementStyles[ANIMATION_PROP + DURATION_KEY]);
1156
+
1157
+ if(aDuration > 0) {
1158
+ aDuration *= parseInt(elementStyles[ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY], 10) || 1;
1159
+ }
1160
+
1161
+ animationDuration = Math.max(aDuration, animationDuration);
1162
+ }
1163
+ });
1164
+ data = {
1165
+ total : 0,
1166
+ transitionPropertyStyle: transitionPropertyStyle,
1167
+ transitionDurationStyle: transitionDurationStyle,
1168
+ transitionDelayStyle: transitionDelayStyle,
1169
+ transitionDelay: transitionDelay,
1170
+ transitionDuration: transitionDuration,
1171
+ animationDelayStyle: animationDelayStyle,
1172
+ animationDelay: animationDelay,
1173
+ animationDuration: animationDuration
1174
+ };
1175
+ if(cacheKey) {
1176
+ lookupCache[cacheKey] = data;
1177
+ }
1178
+ }
1179
+ return data;
1180
+ }
1181
+
1182
+ function parseMaxTime(str) {
1183
+ var maxValue = 0;
1184
+ var values = angular.isString(str) ?
1185
+ str.split(/\s*,\s*/) :
1186
+ [];
1187
+ forEach(values, function(value) {
1188
+ maxValue = Math.max(parseFloat(value) || 0, maxValue);
1189
+ });
1190
+ return maxValue;
1191
+ }
1192
+
1193
+ function getCacheKey(element) {
1194
+ var parentElement = element.parent();
1195
+ var parentID = parentElement.data(NG_ANIMATE_PARENT_KEY);
1196
+ if(!parentID) {
1197
+ parentElement.data(NG_ANIMATE_PARENT_KEY, ++parentCounter);
1198
+ parentID = parentCounter;
1199
+ }
1200
+ return parentID + '-' + extractElementNode(element).className;
1201
+ }
1202
+
1203
+ function animateSetup(animationEvent, element, className, calculationDecorator) {
1204
+ var cacheKey = getCacheKey(element);
1205
+ var eventCacheKey = cacheKey + ' ' + className;
1206
+ var itemIndex = lookupCache[eventCacheKey] ? ++lookupCache[eventCacheKey].total : 0;
1207
+
1208
+ var stagger = {};
1209
+ if(itemIndex > 0) {
1210
+ var staggerClassName = className + '-stagger';
1211
+ var staggerCacheKey = cacheKey + ' ' + staggerClassName;
1212
+ var applyClasses = !lookupCache[staggerCacheKey];
1213
+
1214
+ applyClasses && element.addClass(staggerClassName);
1215
+
1216
+ stagger = getElementAnimationDetails(element, staggerCacheKey);
1217
+
1218
+ applyClasses && element.removeClass(staggerClassName);
1219
+ }
1220
+
1221
+ /* the animation itself may need to add/remove special CSS classes
1222
+ * before calculating the anmation styles */
1223
+ calculationDecorator = calculationDecorator ||
1224
+ function(fn) { return fn(); };
1225
+
1226
+ element.addClass(className);
1227
+
1228
+ var formerData = element.data(NG_ANIMATE_CSS_DATA_KEY) || {};
1229
+
1230
+ var timings = calculationDecorator(function() {
1231
+ return getElementAnimationDetails(element, eventCacheKey);
1232
+ });
1233
+
1234
+ var transitionDuration = timings.transitionDuration;
1235
+ var animationDuration = timings.animationDuration;
1236
+ if(transitionDuration === 0 && animationDuration === 0) {
1237
+ element.removeClass(className);
1238
+ return false;
1239
+ }
1240
+
1241
+ element.data(NG_ANIMATE_CSS_DATA_KEY, {
1242
+ running : formerData.running || 0,
1243
+ itemIndex : itemIndex,
1244
+ stagger : stagger,
1245
+ timings : timings,
1246
+ closeAnimationFn : angular.noop
1247
+ });
1248
+
1249
+ //temporarily disable the transition so that the enter styles
1250
+ //don't animate twice (this is here to avoid a bug in Chrome/FF).
1251
+ var isCurrentlyAnimating = formerData.running > 0 || animationEvent == 'setClass';
1252
+ if(transitionDuration > 0) {
1253
+ blockTransitions(element, className, isCurrentlyAnimating);
1254
+ }
1255
+ if(animationDuration > 0) {
1256
+ blockKeyframeAnimations(element);
1257
+ }
1258
+
1259
+ return true;
1260
+ }
1261
+
1262
+ function isStructuralAnimation(className) {
1263
+ return className == 'ng-enter' || className == 'ng-move' || className == 'ng-leave';
1264
+ }
1265
+
1266
+ function blockTransitions(element, className, isAnimating) {
1267
+ if(isStructuralAnimation(className) || !isAnimating) {
1268
+ extractElementNode(element).style[TRANSITION_PROP + PROPERTY_KEY] = 'none';
1269
+ } else {
1270
+ element.addClass(NG_ANIMATE_BLOCK_CLASS_NAME);
1271
+ }
1272
+ }
1273
+
1274
+ function blockKeyframeAnimations(element) {
1275
+ extractElementNode(element).style[ANIMATION_PROP] = 'none 0s';
1276
+ }
1277
+
1278
+ function unblockTransitions(element, className) {
1279
+ var prop = TRANSITION_PROP + PROPERTY_KEY;
1280
+ var node = extractElementNode(element);
1281
+ if(node.style[prop] && node.style[prop].length > 0) {
1282
+ node.style[prop] = '';
1283
+ }
1284
+ element.removeClass(NG_ANIMATE_BLOCK_CLASS_NAME);
1285
+ }
1286
+
1287
+ function unblockKeyframeAnimations(element) {
1288
+ var prop = ANIMATION_PROP;
1289
+ var node = extractElementNode(element);
1290
+ if(node.style[prop] && node.style[prop].length > 0) {
1291
+ node.style[prop] = '';
1292
+ }
1293
+ }
1294
+
1295
+ function animateRun(animationEvent, element, className, activeAnimationComplete) {
1296
+ var node = extractElementNode(element);
1297
+ var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
1298
+ if(node.className.indexOf(className) == -1 || !elementData) {
1299
+ activeAnimationComplete();
1300
+ return;
1301
+ }
1302
+
1303
+ var activeClassName = '';
1304
+ forEach(className.split(' '), function(klass, i) {
1305
+ activeClassName += (i > 0 ? ' ' : '') + klass + '-active';
1306
+ });
1307
+
1308
+ var stagger = elementData.stagger;
1309
+ var timings = elementData.timings;
1310
+ var itemIndex = elementData.itemIndex;
1311
+ var maxDuration = Math.max(timings.transitionDuration, timings.animationDuration);
1312
+ var maxDelay = Math.max(timings.transitionDelay, timings.animationDelay);
1313
+ var maxDelayTime = maxDelay * ONE_SECOND;
1314
+
1315
+ var startTime = Date.now();
1316
+ var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT;
1317
+
1318
+ var style = '', appliedStyles = [];
1319
+ if(timings.transitionDuration > 0) {
1320
+ var propertyStyle = timings.transitionPropertyStyle;
1321
+ if(propertyStyle.indexOf('all') == -1) {
1322
+ style += CSS_PREFIX + 'transition-property: ' + propertyStyle + ';';
1323
+ style += CSS_PREFIX + 'transition-duration: ' + timings.transitionDurationStyle + ';';
1324
+ appliedStyles.push(CSS_PREFIX + 'transition-property');
1325
+ appliedStyles.push(CSS_PREFIX + 'transition-duration');
1326
+ }
1327
+ }
1328
+
1329
+ if(itemIndex > 0) {
1330
+ if(stagger.transitionDelay > 0 && stagger.transitionDuration === 0) {
1331
+ var delayStyle = timings.transitionDelayStyle;
1332
+ style += CSS_PREFIX + 'transition-delay: ' +
1333
+ prepareStaggerDelay(delayStyle, stagger.transitionDelay, itemIndex) + '; ';
1334
+ appliedStyles.push(CSS_PREFIX + 'transition-delay');
1335
+ }
1336
+
1337
+ if(stagger.animationDelay > 0 && stagger.animationDuration === 0) {
1338
+ style += CSS_PREFIX + 'animation-delay: ' +
1339
+ prepareStaggerDelay(timings.animationDelayStyle, stagger.animationDelay, itemIndex) + '; ';
1340
+ appliedStyles.push(CSS_PREFIX + 'animation-delay');
1341
+ }
1342
+ }
1343
+
1344
+ if(appliedStyles.length > 0) {
1345
+ //the element being animated may sometimes contain comment nodes in
1346
+ //the jqLite object, so we're safe to use a single variable to house
1347
+ //the styles since there is always only one element being animated
1348
+ var oldStyle = node.getAttribute('style') || '';
1349
+ node.setAttribute('style', oldStyle + ' ' + style);
1350
+ }
1351
+
1352
+ element.on(css3AnimationEvents, onAnimationProgress);
1353
+ element.addClass(activeClassName);
1354
+ elementData.closeAnimationFn = function() {
1355
+ onEnd();
1356
+ activeAnimationComplete();
1357
+ };
1358
+
1359
+ var staggerTime = itemIndex * (Math.max(stagger.animationDelay, stagger.transitionDelay) || 0);
1360
+ var animationTime = (maxDelay + maxDuration) * CLOSING_TIME_BUFFER;
1361
+ var totalTime = (staggerTime + animationTime) * ONE_SECOND;
1362
+
1363
+ elementData.running++;
1364
+ animationCloseHandler(element, totalTime);
1365
+ return onEnd;
1366
+
1367
+ // This will automatically be called by $animate so
1368
+ // there is no need to attach this internally to the
1369
+ // timeout done method.
1370
+ function onEnd(cancelled) {
1371
+ element.off(css3AnimationEvents, onAnimationProgress);
1372
+ element.removeClass(activeClassName);
1373
+ animateClose(element, className);
1374
+ var node = extractElementNode(element);
1375
+ for (var i in appliedStyles) {
1376
+ node.style.removeProperty(appliedStyles[i]);
1377
+ }
1378
+ }
1379
+
1380
+ function onAnimationProgress(event) {
1381
+ event.stopPropagation();
1382
+ var ev = event.originalEvent || event;
1383
+ var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now();
1384
+
1385
+ /* Firefox (or possibly just Gecko) likes to not round values up
1386
+ * when a ms measurement is used for the animation */
1387
+ var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES));
1388
+
1389
+ /* $manualTimeStamp is a mocked timeStamp value which is set
1390
+ * within browserTrigger(). This is only here so that tests can
1391
+ * mock animations properly. Real events fallback to event.timeStamp,
1392
+ * or, if they don't, then a timeStamp is automatically created for them.
1393
+ * We're checking to see if the timeStamp surpasses the expected delay,
1394
+ * but we're using elapsedTime instead of the timeStamp on the 2nd
1395
+ * pre-condition since animations sometimes close off early */
1396
+ if(Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) {
1397
+ activeAnimationComplete();
1398
+ }
1399
+ }
1400
+ }
1401
+
1402
+ function prepareStaggerDelay(delayStyle, staggerDelay, index) {
1403
+ var style = '';
1404
+ forEach(delayStyle.split(','), function(val, i) {
1405
+ style += (i > 0 ? ',' : '') +
1406
+ (index * staggerDelay + parseInt(val, 10)) + 's';
1407
+ });
1408
+ return style;
1409
+ }
1410
+
1411
+ function animateBefore(animationEvent, element, className, calculationDecorator) {
1412
+ if(animateSetup(animationEvent, element, className, calculationDecorator)) {
1413
+ return function(cancelled) {
1414
+ cancelled && animateClose(element, className);
1415
+ };
1416
+ }
1417
+ }
1418
+
1419
+ function animateAfter(animationEvent, element, className, afterAnimationComplete) {
1420
+ if(element.data(NG_ANIMATE_CSS_DATA_KEY)) {
1421
+ return animateRun(animationEvent, element, className, afterAnimationComplete);
1422
+ } else {
1423
+ animateClose(element, className);
1424
+ afterAnimationComplete();
1425
+ }
1426
+ }
1427
+
1428
+ function animate(animationEvent, element, className, animationComplete) {
1429
+ //If the animateSetup function doesn't bother returning a
1430
+ //cancellation function then it means that there is no animation
1431
+ //to perform at all
1432
+ var preReflowCancellation = animateBefore(animationEvent, element, className);
1433
+ if(!preReflowCancellation) {
1434
+ animationComplete();
1435
+ return;
1436
+ }
1437
+
1438
+ //There are two cancellation functions: one is before the first
1439
+ //reflow animation and the second is during the active state
1440
+ //animation. The first function will take care of removing the
1441
+ //data from the element which will not make the 2nd animation
1442
+ //happen in the first place
1443
+ var cancel = preReflowCancellation;
1444
+ afterReflow(element, function() {
1445
+ unblockTransitions(element, className);
1446
+ unblockKeyframeAnimations(element);
1447
+ //once the reflow is complete then we point cancel to
1448
+ //the new cancellation function which will remove all of the
1449
+ //animation properties from the active animation
1450
+ cancel = animateAfter(animationEvent, element, className, animationComplete);
1451
+ });
1452
+
1453
+ return function(cancelled) {
1454
+ (cancel || noop)(cancelled);
1455
+ };
1456
+ }
1457
+
1458
+ function animateClose(element, className) {
1459
+ element.removeClass(className);
1460
+ var data = element.data(NG_ANIMATE_CSS_DATA_KEY);
1461
+ if(data) {
1462
+ if(data.running) {
1463
+ data.running--;
1464
+ }
1465
+ if(!data.running || data.running === 0) {
1466
+ element.removeData(NG_ANIMATE_CSS_DATA_KEY);
1467
+ }
1468
+ }
1469
+ }
1470
+
1471
+ return {
1472
+ enter : function(element, animationCompleted) {
1473
+ return animate('enter', element, 'ng-enter', animationCompleted);
1474
+ },
1475
+
1476
+ leave : function(element, animationCompleted) {
1477
+ return animate('leave', element, 'ng-leave', animationCompleted);
1478
+ },
1479
+
1480
+ move : function(element, animationCompleted) {
1481
+ return animate('move', element, 'ng-move', animationCompleted);
1482
+ },
1483
+
1484
+ beforeSetClass : function(element, add, remove, animationCompleted) {
1485
+ var className = suffixClasses(remove, '-remove') + ' ' +
1486
+ suffixClasses(add, '-add');
1487
+ var cancellationMethod = animateBefore('setClass', element, className, function(fn) {
1488
+ /* when classes are removed from an element then the transition style
1489
+ * that is applied is the transition defined on the element without the
1490
+ * CSS class being there. This is how CSS3 functions outside of ngAnimate.
1491
+ * http://plnkr.co/edit/j8OzgTNxHTb4n3zLyjGW?p=preview */
1492
+ var klass = element.attr('class');
1493
+ element.removeClass(remove);
1494
+ element.addClass(add);
1495
+ var timings = fn();
1496
+ element.attr('class', klass);
1497
+ return timings;
1498
+ });
1499
+
1500
+ if(cancellationMethod) {
1501
+ afterReflow(element, function() {
1502
+ unblockTransitions(element, className);
1503
+ unblockKeyframeAnimations(element);
1504
+ animationCompleted();
1505
+ });
1506
+ return cancellationMethod;
1507
+ }
1508
+ animationCompleted();
1509
+ },
1510
+
1511
+ beforeAddClass : function(element, className, animationCompleted) {
1512
+ var cancellationMethod = animateBefore('addClass', element, suffixClasses(className, '-add'), function(fn) {
1513
+
1514
+ /* when a CSS class is added to an element then the transition style that
1515
+ * is applied is the transition defined on the element when the CSS class
1516
+ * is added at the time of the animation. This is how CSS3 functions
1517
+ * outside of ngAnimate. */
1518
+ element.addClass(className);
1519
+ var timings = fn();
1520
+ element.removeClass(className);
1521
+ return timings;
1522
+ });
1523
+
1524
+ if(cancellationMethod) {
1525
+ afterReflow(element, function() {
1526
+ unblockTransitions(element, className);
1527
+ unblockKeyframeAnimations(element);
1528
+ animationCompleted();
1529
+ });
1530
+ return cancellationMethod;
1531
+ }
1532
+ animationCompleted();
1533
+ },
1534
+
1535
+ setClass : function(element, add, remove, animationCompleted) {
1536
+ remove = suffixClasses(remove, '-remove');
1537
+ add = suffixClasses(add, '-add');
1538
+ var className = remove + ' ' + add;
1539
+ return animateAfter('setClass', element, className, animationCompleted);
1540
+ },
1541
+
1542
+ addClass : function(element, className, animationCompleted) {
1543
+ return animateAfter('addClass', element, suffixClasses(className, '-add'), animationCompleted);
1544
+ },
1545
+
1546
+ beforeRemoveClass : function(element, className, animationCompleted) {
1547
+ var cancellationMethod = animateBefore('removeClass', element, suffixClasses(className, '-remove'), function(fn) {
1548
+ /* when classes are removed from an element then the transition style
1549
+ * that is applied is the transition defined on the element without the
1550
+ * CSS class being there. This is how CSS3 functions outside of ngAnimate.
1551
+ * http://plnkr.co/edit/j8OzgTNxHTb4n3zLyjGW?p=preview */
1552
+ var klass = element.attr('class');
1553
+ element.removeClass(className);
1554
+ var timings = fn();
1555
+ element.attr('class', klass);
1556
+ return timings;
1557
+ });
1558
+
1559
+ if(cancellationMethod) {
1560
+ afterReflow(element, function() {
1561
+ unblockTransitions(element, className);
1562
+ unblockKeyframeAnimations(element);
1563
+ animationCompleted();
1564
+ });
1565
+ return cancellationMethod;
1566
+ }
1567
+ animationCompleted();
1568
+ },
1569
+
1570
+ removeClass : function(element, className, animationCompleted) {
1571
+ return animateAfter('removeClass', element, suffixClasses(className, '-remove'), animationCompleted);
1572
+ }
1573
+ };
1574
+
1575
+ function suffixClasses(classes, suffix) {
1576
+ var className = '';
1577
+ classes = angular.isArray(classes) ? classes : classes.split(/\s+/);
1578
+ forEach(classes, function(klass, i) {
1579
+ if(klass && klass.length > 0) {
1580
+ className += (i > 0 ? ' ' : '') + klass + suffix;
1581
+ }
1582
+ });
1583
+ return className;
1584
+ }
1585
+ }]);
1586
+ }]);
1587
+
1588
+
1589
+ })(window, window.angular);