angularjs-rails 1.2.0.rc3 → 1.2.0
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.
- checksums.yaml +4 -4
- data/lib/angularjs-rails/version.rb +1 -1
- data/vendor/assets/javascripts/angular-animate.js +673 -291
- data/vendor/assets/javascripts/angular-cookies.js +6 -4
- data/vendor/assets/javascripts/angular-loader.js +19 -15
- data/vendor/assets/javascripts/angular-mocks.js +104 -66
- data/vendor/assets/javascripts/angular-resource.js +103 -82
- data/vendor/assets/javascripts/angular-route.js +75 -59
- data/vendor/assets/javascripts/angular-sanitize.js +116 -97
- data/vendor/assets/javascripts/angular-scenario.js +2201 -1295
- data/vendor/assets/javascripts/angular-touch.js +19 -8
- data/vendor/assets/javascripts/angular.js +2064 -1174
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 057e98f881260457560c9c3c48db4315c9ed9274
|
4
|
+
data.tar.gz: 1472731f282bbfe48e9f70bedd9e60952cf90f51
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51a1b04c1ddf80a54cd25787cb1c03107c942bb52aae366a8a69921f67a0851e277ee1fe1b10ee871c22d6534c56bdee88ee9b5e8bb490087145c145ad89ec9a
|
7
|
+
data.tar.gz: 51f3e1f860e730c6b5c43f3eace759b111ffaff3d1df91b452cd8c527dfbba7400f3641fbcf9582d959f6d6e9337f4f1ad772b6e71ffdfe8ef581a9e96a7f69d
|
@@ -1,10 +1,12 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.2.0
|
2
|
+
* @license AngularJS v1.2.0
|
3
3
|
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
6
6
|
(function(window, angular, undefined) {'use strict';
|
7
7
|
|
8
|
+
/* jshint maxlen: false */
|
9
|
+
|
8
10
|
/**
|
9
11
|
* @ngdoc overview
|
10
12
|
* @name ngAnimate
|
@@ -12,28 +14,30 @@
|
|
12
14
|
*
|
13
15
|
* # ngAnimate
|
14
16
|
*
|
15
|
-
* `ngAnimate`
|
17
|
+
* The `ngAnimate` module provides support for JavaScript, CSS3 transition and CSS3 keyframe animation hooks within existing core and custom directives.
|
16
18
|
*
|
17
19
|
* {@installModule animate}
|
18
20
|
*
|
21
|
+
* <div doc-module-components="ngAnimate"></div>
|
22
|
+
*
|
19
23
|
* # Usage
|
20
24
|
*
|
21
25
|
* To see animations in action, all that is required is to define the appropriate CSS classes
|
22
|
-
* or to register a JavaScript animation via the
|
23
|
-
* `ngRepeat`, `ngInclude`, `ngSwitch`, `ngShow`, `ngHide` and `
|
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
|
24
28
|
* by using the `$animate` service.
|
25
29
|
*
|
26
30
|
* Below is a more detailed breakdown of the supported animation events provided by pre-existing ng directives:
|
27
31
|
*
|
28
32
|
* | Directive | Supported Animations |
|
29
33
|
* |---------------------------------------------------------- |----------------------------------------------------|
|
30
|
-
* | {@link ng.directive:ngRepeat#
|
31
|
-
* | {@link ngRoute.directive:ngView#
|
32
|
-
* | {@link ng.directive:ngInclude#
|
33
|
-
* | {@link ng.directive:ngSwitch#
|
34
|
-
* | {@link ng.directive:ngIf#
|
35
|
-
* | {@link ng.directive:ngClass#
|
36
|
-
* | {@link ng.directive:ngShow#
|
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) |
|
37
41
|
*
|
38
42
|
* You can find out more information about animations upon visiting each directive page.
|
39
43
|
*
|
@@ -41,11 +45,8 @@
|
|
41
45
|
*
|
42
46
|
* <pre>
|
43
47
|
* <style type="text/css">
|
44
|
-
* .slide.ng-enter
|
45
|
-
* .slide.ng-leave > div {
|
48
|
+
* .slide.ng-enter, .slide.ng-leave {
|
46
49
|
* -webkit-transition:0.5s linear all;
|
47
|
-
* -moz-transition:0.5s linear all;
|
48
|
-
* -o-transition:0.5s linear all;
|
49
50
|
* transition:0.5s linear all;
|
50
51
|
* }
|
51
52
|
*
|
@@ -80,9 +81,7 @@
|
|
80
81
|
* */
|
81
82
|
* .reveal-animation.ng-enter {
|
82
83
|
* -webkit-transition: 1s linear all; /* Safari/Chrome */
|
83
|
-
*
|
84
|
-
* -o-transition: 1s linear all; /* Opera */
|
85
|
-
* transition: 1s linear all; /* IE10+ and Future Browsers */
|
84
|
+
* transition: 1s linear all; /* All other modern browsers and IE10+ */
|
86
85
|
*
|
87
86
|
* /* The animation preparation code */
|
88
87
|
* opacity: 0;
|
@@ -110,22 +109,12 @@
|
|
110
109
|
* <style type="text/css">
|
111
110
|
* .reveal-animation.ng-enter {
|
112
111
|
* -webkit-animation: enter_sequence 1s linear; /* Safari/Chrome */
|
113
|
-
* -moz-animation: enter_sequence 1s linear; /* Firefox */
|
114
|
-
* -o-animation: enter_sequence 1s linear; /* Opera */
|
115
112
|
* animation: enter_sequence 1s linear; /* IE10+ and Future Browsers */
|
116
113
|
* }
|
117
114
|
* @-webkit-keyframes enter_sequence {
|
118
115
|
* from { opacity:0; }
|
119
116
|
* to { opacity:1; }
|
120
117
|
* }
|
121
|
-
* @-moz-keyframes enter_sequence {
|
122
|
-
* from { opacity:0; }
|
123
|
-
* to { opacity:1; }
|
124
|
-
* }
|
125
|
-
* @-o-keyframes enter_sequence {
|
126
|
-
* from { opacity:0; }
|
127
|
-
* to { opacity:1; }
|
128
|
-
* }
|
129
118
|
* @keyframes enter_sequence {
|
130
119
|
* from { opacity:0; }
|
131
120
|
* to { opacity:1; }
|
@@ -146,6 +135,61 @@
|
|
146
135
|
* immediately resulting in a DOM element that is at its final state. This final state is when the DOM element
|
147
136
|
* has no CSS transition/animation classes applied to it.
|
148
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
|
+
* /* standard transition code */
|
148
|
+
* -webkit-transition: 1s linear all;
|
149
|
+
* transition: 1s linear all;
|
150
|
+
* opacity:0;
|
151
|
+
* }
|
152
|
+
* .my-animation.ng-enter-stagger {
|
153
|
+
* /* this will have a 100ms delay between each successive leave animation */
|
154
|
+
* -webkit-transition-delay: 0.1s;
|
155
|
+
* transition-delay: 0.1s;
|
156
|
+
*
|
157
|
+
* /* in case the stagger doesn't work then these two values
|
158
|
+
* must be set to 0 to avoid an accidental CSS inheritance */
|
159
|
+
* -webkit-transition-duration: 0s;
|
160
|
+
* transition-duration: 0s;
|
161
|
+
* }
|
162
|
+
* .my-animation.ng-enter.ng-enter-active {
|
163
|
+
* /* standard transition styles */
|
164
|
+
* opacity:1;
|
165
|
+
* }
|
166
|
+
* </pre>
|
167
|
+
*
|
168
|
+
* Staggering animations work by default in ngRepeat (so long as the CSS class is defiend). 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
|
+
*
|
149
193
|
* <h2>JavaScript-defined Animations</h2>
|
150
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
|
151
195
|
* yet support CSS transitions/animations, then you can make use of JavaScript animations defined inside of your AngularJS module.
|
@@ -156,18 +200,27 @@
|
|
156
200
|
* ngModule.animation('.my-crazy-animation', function() {
|
157
201
|
* return {
|
158
202
|
* enter: function(element, done) {
|
159
|
-
* //run the animation
|
160
|
-
*
|
161
|
-
*
|
162
|
-
* //
|
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).
|
163
208
|
* }
|
164
209
|
* }
|
165
210
|
* leave: function(element, done) { },
|
166
211
|
* move: function(element, done) { },
|
167
|
-
*
|
168
|
-
*
|
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
|
169
217
|
* addClass: function(element, className, done) { },
|
170
|
-
*
|
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) { }
|
171
224
|
* }
|
172
225
|
* });
|
173
226
|
* </pre>
|
@@ -176,7 +229,7 @@
|
|
176
229
|
* a javascript callback function. When an animation is triggered, $animate will look for a matching animation which fits
|
177
230
|
* the element's CSS class attribute value and then run the matching animation event function (if found).
|
178
231
|
* In other words, if the CSS classes present on the animated element match any of the JavaScript animations then the callback function
|
179
|
-
* be executed. It should be also noted that only simple class selectors are allowed.
|
232
|
+
* be executed. It should be also noted that only simple, single class selectors are allowed (compound class selectors are not supported).
|
180
233
|
*
|
181
234
|
* Within a JavaScript animation, an object containing various event callback animation functions is expected to be returned.
|
182
235
|
* As explained above, these callbacks are triggered based on the animation event. Therefore if an enter animation is run,
|
@@ -192,9 +245,9 @@ angular.module('ngAnimate', ['ng'])
|
|
192
245
|
* @name ngAnimate.$animateProvider
|
193
246
|
* @description
|
194
247
|
*
|
195
|
-
* The `$
|
196
|
-
*
|
197
|
-
*
|
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.
|
198
251
|
*
|
199
252
|
* Requires the {@link ngAnimate `ngAnimate`} module to be installed.
|
200
253
|
*
|
@@ -206,14 +259,21 @@ angular.module('ngAnimate', ['ng'])
|
|
206
259
|
var forEach = angular.forEach;
|
207
260
|
var selectors = $animateProvider.$$selectors;
|
208
261
|
|
262
|
+
var ELEMENT_NODE = 1;
|
209
263
|
var NG_ANIMATE_STATE = '$$ngAnimateState';
|
210
264
|
var NG_ANIMATE_CLASS_NAME = 'ng-animate';
|
211
|
-
var rootAnimateState = {running:true};
|
212
|
-
|
213
|
-
|
214
|
-
|
265
|
+
var rootAnimateState = {running: true};
|
266
|
+
|
267
|
+
$provide.decorator('$animate', ['$delegate', '$injector', '$sniffer', '$rootElement', '$timeout', '$rootScope', '$document',
|
268
|
+
function($delegate, $injector, $sniffer, $rootElement, $timeout, $rootScope, $document) {
|
269
|
+
|
215
270
|
$rootElement.data(NG_ANIMATE_STATE, rootAnimateState);
|
216
271
|
|
272
|
+
// disable animations during bootstrap, but once we bootstrapped, enable animations
|
273
|
+
$rootScope.$$postDigest(function() {
|
274
|
+
rootAnimateState.running = false;
|
275
|
+
});
|
276
|
+
|
217
277
|
function lookup(name) {
|
218
278
|
if (name) {
|
219
279
|
var matches = [],
|
@@ -244,12 +304,11 @@ angular.module('ngAnimate', ['ng'])
|
|
244
304
|
/**
|
245
305
|
* @ngdoc object
|
246
306
|
* @name ngAnimate.$animate
|
247
|
-
* @requires $timeout, $sniffer, $rootElement
|
248
307
|
* @function
|
249
308
|
*
|
250
309
|
* @description
|
251
|
-
* The `$animate` service provides animation detection support while performing DOM operations (enter, leave and move)
|
252
|
-
*
|
310
|
+
* The `$animate` service provides animation detection support while performing DOM operations (enter, leave and move) as well as during addClass and removeClass operations.
|
311
|
+
* When any of these operations are run, the $animate service
|
253
312
|
* will examine any JavaScript-defined animations (which are defined by using the $animateProvider provider object)
|
254
313
|
* as well as any CSS-defined animations against the CSS classes present on the element once the DOM operation is run.
|
255
314
|
*
|
@@ -269,35 +328,34 @@ angular.module('ngAnimate', ['ng'])
|
|
269
328
|
* @function
|
270
329
|
*
|
271
330
|
* @description
|
272
|
-
* Appends the element to the
|
331
|
+
* Appends the element to the parentElement element that resides in the document and then runs the enter animation. Once
|
273
332
|
* the animation is started, the following CSS classes will be present on the element for the duration of the animation:
|
274
333
|
*
|
275
334
|
* Below is a breakdown of each step that occurs during enter animation:
|
276
335
|
*
|
277
|
-
* | Animation Step | What the element class attribute looks like
|
278
|
-
*
|
279
|
-
* | 1. $animate.enter(...) is called | class="my-animation"
|
280
|
-
* | 2. element is inserted into the
|
281
|
-
* | 3. $animate runs any JavaScript-defined animations on the element | class="my-animation"
|
282
|
-
* | 4. the .ng-enter class is added to the element | class="my-animation ng-enter"
|
283
|
-
* | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-enter"
|
284
|
-
* | 6.
|
285
|
-
* | 7.
|
286
|
-
* | 8.
|
287
|
-
* | 9. The
|
336
|
+
* | Animation Step | What the element class attribute looks like |
|
337
|
+
* |----------------------------------------------------------------------------------------------|---------------------------------------------|
|
338
|
+
* | 1. $animate.enter(...) is called | class="my-animation" |
|
339
|
+
* | 2. element is inserted into the parentElement element or beside the afterElement element | class="my-animation" |
|
340
|
+
* | 3. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
|
341
|
+
* | 4. the .ng-enter class is added to the element | class="my-animation ng-animate ng-enter" |
|
342
|
+
* | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-enter" |
|
343
|
+
* | 6. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-enter" |
|
344
|
+
* | 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" |
|
345
|
+
* | 8. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-enter ng-enter-active" |
|
346
|
+
* | 9. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
|
347
|
+
* | 10. The doneCallback() callback is fired (if provided) | class="my-animation" |
|
288
348
|
*
|
289
349
|
* @param {jQuery/jqLite element} element the element that will be the focus of the enter animation
|
290
|
-
* @param {jQuery/jqLite element}
|
291
|
-
* @param {jQuery/jqLite element}
|
292
|
-
* @param {function()=}
|
350
|
+
* @param {jQuery/jqLite element} parentElement the parent element of the element that will be the focus of the enter animation
|
351
|
+
* @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
|
352
|
+
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
|
293
353
|
*/
|
294
|
-
enter : function(element,
|
354
|
+
enter : function(element, parentElement, afterElement, doneCallback) {
|
295
355
|
this.enabled(false, element);
|
296
|
-
$delegate.enter(element,
|
356
|
+
$delegate.enter(element, parentElement, afterElement);
|
297
357
|
$rootScope.$$postDigest(function() {
|
298
|
-
performAnimation('enter', 'ng-enter', element,
|
299
|
-
done && $timeout(done, 0, false);
|
300
|
-
});
|
358
|
+
performAnimation('enter', 'ng-enter', element, parentElement, afterElement, noop, doneCallback);
|
301
359
|
});
|
302
360
|
},
|
303
361
|
|
@@ -313,28 +371,29 @@ angular.module('ngAnimate', ['ng'])
|
|
313
371
|
*
|
314
372
|
* Below is a breakdown of each step that occurs during enter animation:
|
315
373
|
*
|
316
|
-
* | Animation Step | What the element class attribute looks like
|
317
|
-
*
|
318
|
-
* | 1. $animate.leave(...) is called | class="my-animation"
|
319
|
-
* | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation"
|
320
|
-
* | 3. the .ng-leave class is added to the element | class="my-animation ng-leave"
|
321
|
-
* | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-leave"
|
322
|
-
* | 5.
|
323
|
-
* | 6.
|
324
|
-
* | 7.
|
325
|
-
* | 8. The
|
326
|
-
* | 9. The
|
374
|
+
* | Animation Step | What the element class attribute looks like |
|
375
|
+
* |----------------------------------------------------------------------------------------------|---------------------------------------------|
|
376
|
+
* | 1. $animate.leave(...) is called | class="my-animation" |
|
377
|
+
* | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
|
378
|
+
* | 3. the .ng-leave class is added to the element | class="my-animation ng-animate ng-leave" |
|
379
|
+
* | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-leave" |
|
380
|
+
* | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-leave" |
|
381
|
+
* | 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" |
|
382
|
+
* | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-leave ng-leave-active" |
|
383
|
+
* | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
|
384
|
+
* | 9. The element is removed from the DOM | ... |
|
385
|
+
* | 10. The doneCallback() callback is fired (if provided) | ... |
|
327
386
|
*
|
328
387
|
* @param {jQuery/jqLite element} element the element that will be the focus of the leave animation
|
329
|
-
* @param {function()=}
|
388
|
+
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
|
330
389
|
*/
|
331
|
-
leave : function(element,
|
390
|
+
leave : function(element, doneCallback) {
|
332
391
|
cancelChildAnimations(element);
|
333
392
|
this.enabled(false, element);
|
334
393
|
$rootScope.$$postDigest(function() {
|
335
394
|
performAnimation('leave', 'ng-leave', element, null, null, function() {
|
336
|
-
$delegate.leave(element
|
337
|
-
});
|
395
|
+
$delegate.leave(element);
|
396
|
+
}, doneCallback);
|
338
397
|
});
|
339
398
|
},
|
340
399
|
|
@@ -345,8 +404,8 @@ angular.module('ngAnimate', ['ng'])
|
|
345
404
|
* @function
|
346
405
|
*
|
347
406
|
* @description
|
348
|
-
* Fires the move DOM operation. Just before the animation starts, the animate service will either append it into the
|
349
|
-
* add the element directly after the
|
407
|
+
* Fires the move DOM operation. Just before the animation starts, the animate service will either append it into the parentElement container or
|
408
|
+
* add the element directly after the afterElement element if present. Then the move animation will be run. Once
|
350
409
|
* the animation is started, the following CSS classes will be added for the duration of the animation:
|
351
410
|
*
|
352
411
|
* Below is a breakdown of each step that occurs during move animation:
|
@@ -354,28 +413,27 @@ angular.module('ngAnimate', ['ng'])
|
|
354
413
|
* | Animation Step | What the element class attribute looks like |
|
355
414
|
* |----------------------------------------------------------------------------------------------|---------------------------------------------|
|
356
415
|
* | 1. $animate.move(...) is called | class="my-animation" |
|
357
|
-
* | 2. element is moved into the
|
358
|
-
* | 3. $animate runs any JavaScript-defined animations on the element | class="my-animation"
|
359
|
-
* | 4. the .ng-move class is added to the element | class="my-animation ng-move"
|
360
|
-
* | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-move"
|
361
|
-
* | 6.
|
362
|
-
* | 7.
|
363
|
-
* | 8.
|
364
|
-
* | 9. The
|
416
|
+
* | 2. element is moved into the parentElement element or beside the afterElement element | class="my-animation" |
|
417
|
+
* | 3. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
|
418
|
+
* | 4. the .ng-move class is added to the element | class="my-animation ng-animate ng-move" |
|
419
|
+
* | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-move" |
|
420
|
+
* | 6. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-move" |
|
421
|
+
* | 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" |
|
422
|
+
* | 8. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-move ng-move-active" |
|
423
|
+
* | 9. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
|
424
|
+
* | 10. The doneCallback() callback is fired (if provided) | class="my-animation" |
|
365
425
|
*
|
366
426
|
* @param {jQuery/jqLite element} element the element that will be the focus of the move animation
|
367
|
-
* @param {jQuery/jqLite element}
|
368
|
-
* @param {jQuery/jqLite element}
|
369
|
-
* @param {function()=}
|
427
|
+
* @param {jQuery/jqLite element} parentElement the parentElement element of the element that will be the focus of the move animation
|
428
|
+
* @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
|
429
|
+
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
|
370
430
|
*/
|
371
|
-
move : function(element,
|
431
|
+
move : function(element, parentElement, afterElement, doneCallback) {
|
372
432
|
cancelChildAnimations(element);
|
373
433
|
this.enabled(false, element);
|
374
|
-
$delegate.move(element,
|
434
|
+
$delegate.move(element, parentElement, afterElement);
|
375
435
|
$rootScope.$$postDigest(function() {
|
376
|
-
performAnimation('move', 'ng-move', element,
|
377
|
-
done && $timeout(done, 0, false);
|
378
|
-
});
|
436
|
+
performAnimation('move', 'ng-move', element, parentElement, afterElement, noop, doneCallback);
|
379
437
|
});
|
380
438
|
},
|
381
439
|
|
@@ -388,30 +446,31 @@ angular.module('ngAnimate', ['ng'])
|
|
388
446
|
* Triggers a custom animation event based off the className variable and then attaches the className value to the element as a CSS class.
|
389
447
|
* Unlike the other animation methods, the animate service will suffix the className value with {@type -add} in order to provide
|
390
448
|
* the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if no CSS transitions
|
391
|
-
* or keyframes are defined on the -add CSS class).
|
449
|
+
* or keyframes are defined on the -add or base CSS class).
|
392
450
|
*
|
393
451
|
* Below is a breakdown of each step that occurs during addClass animation:
|
394
452
|
*
|
395
453
|
* | Animation Step | What the element class attribute looks like |
|
396
454
|
* |------------------------------------------------------------------------------------------------|---------------------------------------------|
|
397
|
-
* | 1. $animate.addClass(element, 'super') is called | class=""
|
398
|
-
* | 2. $animate runs any JavaScript-defined animations on the element | class=""
|
399
|
-
* | 3. the .super-add class
|
400
|
-
* | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="super-add"
|
401
|
-
* | 5.
|
402
|
-
* | 6.
|
403
|
-
* | 7.
|
404
|
-
* | 8. The
|
405
|
-
* | 9. The
|
455
|
+
* | 1. $animate.addClass(element, 'super') is called | class="my-animation" |
|
456
|
+
* | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" |
|
457
|
+
* | 3. the .super-add class are added to the element | class="my-animation ng-animate super-add" |
|
458
|
+
* | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate super-add" |
|
459
|
+
* | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate super-add" |
|
460
|
+
* | 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" |
|
461
|
+
* | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation super-add super-add-active" |
|
462
|
+
* | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation super" |
|
463
|
+
* | 9. The super class is kept on the element | class="my-animation super" |
|
464
|
+
* | 10. The doneCallback() callback is fired (if provided) | class="my-animation super" |
|
406
465
|
*
|
407
466
|
* @param {jQuery/jqLite element} element the element that will be animated
|
408
|
-
* @param {string} className the CSS class that will be
|
409
|
-
* @param {function()=}
|
467
|
+
* @param {string} className the CSS class that will be added to the element and then animated
|
468
|
+
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
|
410
469
|
*/
|
411
|
-
addClass : function(element, className,
|
470
|
+
addClass : function(element, className, doneCallback) {
|
412
471
|
performAnimation('addClass', className, element, null, null, function() {
|
413
|
-
$delegate.addClass(element, className
|
414
|
-
});
|
472
|
+
$delegate.addClass(element, className);
|
473
|
+
}, doneCallback);
|
415
474
|
},
|
416
475
|
|
417
476
|
/**
|
@@ -423,29 +482,31 @@ angular.module('ngAnimate', ['ng'])
|
|
423
482
|
* Triggers a custom animation event based off the className variable and then removes the CSS class provided by the className value
|
424
483
|
* from the element. Unlike the other animation methods, the animate service will suffix the className value with {@type -remove} in
|
425
484
|
* order to provide the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if
|
426
|
-
* no CSS transitions or keyframes are defined on the -remove CSS
|
485
|
+
* no CSS transitions or keyframes are defined on the -remove or base CSS classes).
|
427
486
|
*
|
428
487
|
* Below is a breakdown of each step that occurs during removeClass animation:
|
429
488
|
*
|
430
489
|
* | Animation Step | What the element class attribute looks like |
|
431
|
-
*
|
432
|
-
* | 1. $animate.removeClass(element, 'super') is called | class="super"
|
433
|
-
* | 2. $animate runs any JavaScript-defined animations on the element | class="super"
|
434
|
-
* | 3. the .super-remove class
|
435
|
-
* | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="super super-remove"
|
436
|
-
* | 5.
|
437
|
-
* | 6.
|
438
|
-
* | 7.
|
439
|
-
* | 8. The
|
490
|
+
* |-----------------------------------------------------------------------------------------------|---------------------------------------------|
|
491
|
+
* | 1. $animate.removeClass(element, 'super') is called | class="my-animation super" |
|
492
|
+
* | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation super ng-animate" |
|
493
|
+
* | 3. the .super-remove class are added to the element | class="my-animation super ng-animate super-remove"|
|
494
|
+
* | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation super ng-animate super-remove" |
|
495
|
+
* | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation super ng-animate super-remove" |
|
496
|
+
* | 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" |
|
497
|
+
* | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active super-remove super-remove-active" |
|
498
|
+
* | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
|
499
|
+
* | 9. The doneCallback() callback is fired (if provided) | class="my-animation" |
|
500
|
+
*
|
440
501
|
*
|
441
502
|
* @param {jQuery/jqLite element} element the element that will be animated
|
442
503
|
* @param {string} className the CSS class that will be animated and then removed from the element
|
443
|
-
* @param {function()=}
|
504
|
+
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
|
444
505
|
*/
|
445
|
-
removeClass : function(element, className,
|
506
|
+
removeClass : function(element, className, doneCallback) {
|
446
507
|
performAnimation('removeClass', className, element, null, null, function() {
|
447
|
-
$delegate.removeClass(element, className
|
448
|
-
});
|
508
|
+
$delegate.removeClass(element, className);
|
509
|
+
}, doneCallback);
|
449
510
|
},
|
450
511
|
|
451
512
|
/**
|
@@ -466,21 +527,19 @@ angular.module('ngAnimate', ['ng'])
|
|
466
527
|
case 2:
|
467
528
|
if(value) {
|
468
529
|
cleanup(element);
|
469
|
-
}
|
470
|
-
else {
|
530
|
+
} else {
|
471
531
|
var data = element.data(NG_ANIMATE_STATE) || {};
|
472
|
-
data.
|
473
|
-
data.running = true;
|
532
|
+
data.disabled = true;
|
474
533
|
element.data(NG_ANIMATE_STATE, data);
|
475
534
|
}
|
476
535
|
break;
|
477
536
|
|
478
537
|
case 1:
|
479
|
-
rootAnimateState.
|
538
|
+
rootAnimateState.disabled = !value;
|
480
539
|
break;
|
481
540
|
|
482
541
|
default:
|
483
|
-
value = !rootAnimateState.
|
542
|
+
value = !rootAnimateState.disabled;
|
484
543
|
break;
|
485
544
|
}
|
486
545
|
return !!value;
|
@@ -489,86 +548,162 @@ angular.module('ngAnimate', ['ng'])
|
|
489
548
|
|
490
549
|
/*
|
491
550
|
all animations call this shared animation triggering function internally.
|
492
|
-
The
|
551
|
+
The animationEvent variable refers to the JavaScript animation event that will be triggered
|
493
552
|
and the className value is the name of the animation that will be applied within the
|
494
|
-
CSS code. Element,
|
553
|
+
CSS code. Element, parentElement and afterElement are provided DOM elements for the animation
|
495
554
|
and the onComplete callback will be fired once the animation is fully complete.
|
496
555
|
*/
|
497
|
-
function performAnimation(
|
556
|
+
function performAnimation(animationEvent, className, element, parentElement, afterElement, domOperation, doneCallback) {
|
498
557
|
var classes = (element.attr('class') || '') + ' ' + className;
|
499
|
-
var animationLookup = (' ' + classes).replace(/\s+/g,'.')
|
500
|
-
|
501
|
-
|
502
|
-
animations.push({
|
503
|
-
start : animation[event]
|
504
|
-
});
|
505
|
-
});
|
506
|
-
|
507
|
-
if (!parent) {
|
508
|
-
parent = after ? after.parent() : element.parent();
|
558
|
+
var animationLookup = (' ' + classes).replace(/\s+/g,'.');
|
559
|
+
if (!parentElement) {
|
560
|
+
parentElement = afterElement ? afterElement.parent() : element.parent();
|
509
561
|
}
|
510
|
-
var disabledAnimation = { running : true };
|
511
562
|
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
563
|
+
var matches = lookup(animationLookup);
|
564
|
+
var isClassBased = animationEvent == 'addClass' || animationEvent == 'removeClass';
|
565
|
+
var ngAnimateState = element.data(NG_ANIMATE_STATE) || {};
|
566
|
+
|
567
|
+
//skip the animation if animations are disabled, a parent is already being animated,
|
568
|
+
//the element is not currently attached to the document body or then completely close
|
569
|
+
//the animation if any matching animations are not found at all.
|
570
|
+
//NOTE: IE8 + IE9 should close properly (run closeAnimation()) in case a NO animation is not found.
|
571
|
+
if (animationsDisabled(element, parentElement) || matches.length === 0) {
|
572
|
+
domOperation();
|
573
|
+
closeAnimation();
|
516
574
|
return;
|
517
575
|
}
|
518
576
|
|
519
|
-
var
|
577
|
+
var animations = [];
|
578
|
+
//only add animations if the currently running animation is not structural
|
579
|
+
//or if there is no animation running at all
|
580
|
+
if(!ngAnimateState.running || !(isClassBased && ngAnimateState.structural)) {
|
581
|
+
forEach(matches, function(animation) {
|
582
|
+
//add the animation to the queue to if it is allowed to be cancelled
|
583
|
+
if(!animation.allowCancel || animation.allowCancel(element, animationEvent, className)) {
|
584
|
+
var beforeFn, afterFn = animation[animationEvent];
|
585
|
+
|
586
|
+
//Special case for a leave animation since there is no point in performing an
|
587
|
+
//animation on a element node that has already been removed from the DOM
|
588
|
+
if(animationEvent == 'leave') {
|
589
|
+
beforeFn = afterFn;
|
590
|
+
afterFn = null; //this must be falsy so that the animation is skipped for leave
|
591
|
+
} else {
|
592
|
+
beforeFn = animation['before' + animationEvent.charAt(0).toUpperCase() + animationEvent.substr(1)];
|
593
|
+
}
|
594
|
+
animations.push({
|
595
|
+
before : beforeFn,
|
596
|
+
after : afterFn
|
597
|
+
});
|
598
|
+
}
|
599
|
+
});
|
600
|
+
}
|
520
601
|
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
602
|
+
//this would mean that an animation was not allowed so let the existing
|
603
|
+
//animation do it's thing and close this one early
|
604
|
+
if(animations.length === 0) {
|
605
|
+
domOperation();
|
606
|
+
fireDoneCallbackAsync();
|
607
|
+
return;
|
608
|
+
}
|
527
609
|
|
610
|
+
if(ngAnimateState.running) {
|
528
611
|
//if an animation is currently running on the element then lets take the steps
|
529
612
|
//to cancel that animation and fire any required callbacks
|
530
|
-
$timeout.cancel(ngAnimateState.
|
613
|
+
$timeout.cancel(ngAnimateState.closeAnimationTimeout);
|
614
|
+
cleanup(element);
|
531
615
|
cancelAnimations(ngAnimateState.animations);
|
532
|
-
(ngAnimateState.done || noop)();
|
616
|
+
(ngAnimateState.done || noop)(true);
|
617
|
+
}
|
618
|
+
|
619
|
+
//There is no point in perform a class-based animation if the element already contains
|
620
|
+
//(on addClass) or doesn't contain (on removeClass) the className being animated.
|
621
|
+
//The reason why this is being called after the previous animations are cancelled
|
622
|
+
//is so that the CSS classes present on the element can be properly examined.
|
623
|
+
if((animationEvent == 'addClass' && element.hasClass(className)) ||
|
624
|
+
(animationEvent == 'removeClass' && !element.hasClass(className))) {
|
625
|
+
domOperation();
|
626
|
+
fireDoneCallbackAsync();
|
627
|
+
return;
|
533
628
|
}
|
534
629
|
|
630
|
+
//the ng-animate class does nothing, but it's here to allow for
|
631
|
+
//parent animations to find and cancel child animations when needed
|
632
|
+
element.addClass(NG_ANIMATE_CLASS_NAME);
|
633
|
+
|
535
634
|
element.data(NG_ANIMATE_STATE, {
|
536
635
|
running:true,
|
537
636
|
structural:!isClassBased,
|
538
637
|
animations:animations,
|
539
|
-
done:
|
638
|
+
done:onBeforeAnimationsComplete
|
540
639
|
});
|
541
640
|
|
542
|
-
//the
|
543
|
-
//
|
544
|
-
|
641
|
+
//first we run the before animations and when all of those are complete
|
642
|
+
//then we perform the DOM operation and run the next set of animations
|
643
|
+
invokeRegisteredAnimationFns(animations, 'before', onBeforeAnimationsComplete);
|
545
644
|
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
645
|
+
function onBeforeAnimationsComplete(cancelled) {
|
646
|
+
domOperation();
|
647
|
+
if(cancelled === true) {
|
648
|
+
closeAnimation();
|
649
|
+
return;
|
650
|
+
}
|
550
651
|
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
652
|
+
//set the done function to the final done function
|
653
|
+
//so that the DOM event won't be executed twice by accident
|
654
|
+
//if the after animation is cancelled as well
|
655
|
+
var data = element.data(NG_ANIMATE_STATE);
|
656
|
+
if(data) {
|
657
|
+
data.done = closeAnimation;
|
658
|
+
element.data(NG_ANIMATE_STATE, data);
|
557
659
|
}
|
558
|
-
|
660
|
+
invokeRegisteredAnimationFns(animations, 'after', closeAnimation);
|
661
|
+
}
|
662
|
+
|
663
|
+
function invokeRegisteredAnimationFns(animations, phase, allAnimationFnsComplete) {
|
664
|
+
var endFnName = phase + 'End';
|
665
|
+
forEach(animations, function(animation, index) {
|
666
|
+
var animationPhaseCompleted = function() {
|
667
|
+
progress(index, phase);
|
668
|
+
};
|
669
|
+
|
670
|
+
//there are no before functions for enter + move since the DOM
|
671
|
+
//operations happen before the performAnimation method fires
|
672
|
+
if(phase == 'before' && (animationEvent == 'enter' || animationEvent == 'move')) {
|
673
|
+
animationPhaseCompleted();
|
674
|
+
return;
|
675
|
+
}
|
559
676
|
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
677
|
+
if(animation[phase]) {
|
678
|
+
animation[endFnName] = isClassBased ?
|
679
|
+
animation[phase](element, className, animationPhaseCompleted) :
|
680
|
+
animation[phase](element, animationPhaseCompleted);
|
681
|
+
} else {
|
682
|
+
animationPhaseCompleted();
|
683
|
+
}
|
684
|
+
});
|
685
|
+
|
686
|
+
function progress(index, phase) {
|
687
|
+
var phaseCompletionFlag = phase + 'Complete';
|
688
|
+
var currentAnimation = animations[index];
|
689
|
+
currentAnimation[phaseCompletionFlag] = true;
|
690
|
+
(currentAnimation[endFnName] || noop)();
|
691
|
+
|
692
|
+
for(var i=0;i<animations.length;i++) {
|
693
|
+
if(!animations[i][phaseCompletionFlag]) return;
|
694
|
+
}
|
695
|
+
|
696
|
+
allAnimationFnsComplete();
|
565
697
|
}
|
566
|
-
done();
|
567
698
|
}
|
568
699
|
|
569
|
-
function
|
570
|
-
|
571
|
-
|
700
|
+
function fireDoneCallbackAsync() {
|
701
|
+
doneCallback && $timeout(doneCallback, 0, false);
|
702
|
+
}
|
703
|
+
|
704
|
+
function closeAnimation() {
|
705
|
+
if(!closeAnimation.hasBeenRun) {
|
706
|
+
closeAnimation.hasBeenRun = true;
|
572
707
|
var data = element.data(NG_ANIMATE_STATE);
|
573
708
|
if(data) {
|
574
709
|
/* only structural animations wait for reflow before removing an
|
@@ -578,19 +713,24 @@ angular.module('ngAnimate', ['ng'])
|
|
578
713
|
if(isClassBased) {
|
579
714
|
cleanup(element);
|
580
715
|
} else {
|
581
|
-
data.
|
716
|
+
data.closeAnimationTimeout = $timeout(function() {
|
582
717
|
cleanup(element);
|
583
718
|
}, 0, false);
|
584
719
|
element.data(NG_ANIMATE_STATE, data);
|
585
720
|
}
|
586
721
|
}
|
587
|
-
(
|
722
|
+
fireDoneCallbackAsync();
|
588
723
|
}
|
589
724
|
}
|
590
725
|
}
|
591
726
|
|
592
727
|
function cancelChildAnimations(element) {
|
593
|
-
|
728
|
+
var node = element[0];
|
729
|
+
if(node.nodeType != ELEMENT_NODE) {
|
730
|
+
return;
|
731
|
+
}
|
732
|
+
|
733
|
+
forEach(node.querySelectorAll('.' + NG_ANIMATE_CLASS_NAME), function(element) {
|
594
734
|
element = angular.element(element);
|
595
735
|
var data = element.data(NG_ANIMATE_STATE);
|
596
736
|
if(data) {
|
@@ -603,21 +743,58 @@ angular.module('ngAnimate', ['ng'])
|
|
603
743
|
function cancelAnimations(animations) {
|
604
744
|
var isCancelledFlag = true;
|
605
745
|
forEach(animations, function(animation) {
|
606
|
-
(
|
746
|
+
if(!animations['beforeComplete']) {
|
747
|
+
(animation.beforeEnd || noop)(isCancelledFlag);
|
748
|
+
}
|
749
|
+
if(!animations['afterComplete']) {
|
750
|
+
(animation.afterEnd || noop)(isCancelledFlag);
|
751
|
+
}
|
607
752
|
});
|
608
753
|
}
|
609
754
|
|
610
755
|
function cleanup(element) {
|
611
|
-
element
|
612
|
-
|
756
|
+
if(element[0] == $rootElement[0]) {
|
757
|
+
if(!rootAnimateState.disabled) {
|
758
|
+
rootAnimateState.running = false;
|
759
|
+
rootAnimateState.structural = false;
|
760
|
+
}
|
761
|
+
} else {
|
762
|
+
element.removeClass(NG_ANIMATE_CLASS_NAME);
|
763
|
+
element.removeData(NG_ANIMATE_STATE);
|
764
|
+
}
|
765
|
+
}
|
766
|
+
|
767
|
+
function animationsDisabled(element, parentElement) {
|
768
|
+
if (rootAnimateState.disabled) return true;
|
769
|
+
|
770
|
+
if(element[0] == $rootElement[0]) {
|
771
|
+
return rootAnimateState.disabled || rootAnimateState.running;
|
772
|
+
}
|
773
|
+
|
774
|
+
do {
|
775
|
+
//the element did not reach the root element which means that it
|
776
|
+
//is not apart of the DOM. Therefore there is no reason to do
|
777
|
+
//any animations on it
|
778
|
+
if(parentElement.length === 0) break;
|
779
|
+
|
780
|
+
var isRoot = parentElement[0] == $rootElement[0];
|
781
|
+
var state = isRoot ? rootAnimateState : parentElement.data(NG_ANIMATE_STATE);
|
782
|
+
var result = state && (!!state.disabled || !!state.running);
|
783
|
+
if(isRoot || result) {
|
784
|
+
return result;
|
785
|
+
}
|
786
|
+
|
787
|
+
if(isRoot) return true;
|
788
|
+
}
|
789
|
+
while(parentElement = parentElement.parent());
|
790
|
+
|
791
|
+
return true;
|
613
792
|
}
|
614
793
|
}]);
|
615
794
|
|
616
795
|
$animateProvider.register('', ['$window', '$sniffer', '$timeout', function($window, $sniffer, $timeout) {
|
617
|
-
var forEach = angular.forEach;
|
618
|
-
|
619
796
|
// Detect proper transitionend/animationend event names.
|
620
|
-
var
|
797
|
+
var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT;
|
621
798
|
|
622
799
|
// If unprefixed events are not supported but webkit-prefixed are, use the latter.
|
623
800
|
// Otherwise, just use W3C names, browsers not supporting them at all will just ignore them.
|
@@ -628,28 +805,32 @@ angular.module('ngAnimate', ['ng'])
|
|
628
805
|
// Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit
|
629
806
|
// therefore there is no reason to test anymore for other vendor prefixes: http://caniuse.com/#search=transition
|
630
807
|
if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) {
|
631
|
-
|
632
|
-
|
808
|
+
CSS_PREFIX = '-webkit-';
|
809
|
+
TRANSITION_PROP = 'WebkitTransition';
|
810
|
+
TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
|
633
811
|
} else {
|
634
|
-
|
635
|
-
|
812
|
+
TRANSITION_PROP = 'transition';
|
813
|
+
TRANSITIONEND_EVENT = 'transitionend';
|
636
814
|
}
|
637
815
|
|
638
816
|
if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) {
|
639
|
-
|
640
|
-
|
817
|
+
CSS_PREFIX = '-webkit-';
|
818
|
+
ANIMATION_PROP = 'WebkitAnimation';
|
819
|
+
ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';
|
641
820
|
} else {
|
642
|
-
|
643
|
-
|
821
|
+
ANIMATION_PROP = 'animation';
|
822
|
+
ANIMATIONEND_EVENT = 'animationend';
|
644
823
|
}
|
645
824
|
|
646
|
-
var
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
825
|
+
var DURATION_KEY = 'Duration';
|
826
|
+
var PROPERTY_KEY = 'Property';
|
827
|
+
var DELAY_KEY = 'Delay';
|
828
|
+
var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';
|
829
|
+
var NG_ANIMATE_PARENT_KEY = '$$ngAnimateKey';
|
830
|
+
var NG_ANIMATE_CSS_DATA_KEY = '$$ngAnimateCSS3Data';
|
831
|
+
var NG_ANIMATE_FALLBACK_CLASS_NAME = 'ng-animate-start';
|
832
|
+
var NG_ANIMATE_FALLBACK_ACTIVE_CLASS_NAME = 'ng-animate-active';
|
651
833
|
|
652
|
-
var NG_ANIMATE_PARENT_KEY = '$ngAnimateKey';
|
653
834
|
var lookupCache = {};
|
654
835
|
var parentCounter = 0;
|
655
836
|
|
@@ -658,139 +839,229 @@ angular.module('ngAnimate', ['ng'])
|
|
658
839
|
animationReflowQueue.push(callback);
|
659
840
|
$timeout.cancel(animationTimer);
|
660
841
|
animationTimer = $timeout(function() {
|
661
|
-
|
842
|
+
forEach(animationReflowQueue, function(fn) {
|
662
843
|
fn();
|
663
844
|
});
|
664
845
|
animationReflowQueue = [];
|
665
846
|
animationTimer = null;
|
666
847
|
lookupCache = {};
|
667
|
-
}, 10, false);
|
848
|
+
}, 10, false);
|
668
849
|
}
|
669
850
|
|
670
|
-
function
|
671
|
-
var
|
851
|
+
function applyStyle(node, style) {
|
852
|
+
var oldStyle = node.getAttribute('style') || '';
|
853
|
+
var newStyle = (oldStyle.length > 0 ? '; ' : '') + style;
|
854
|
+
node.setAttribute('style', newStyle);
|
855
|
+
return oldStyle;
|
856
|
+
}
|
857
|
+
|
858
|
+
function getElementAnimationDetails(element, cacheKey) {
|
859
|
+
var data = cacheKey ? lookupCache[cacheKey] : null;
|
672
860
|
if(!data) {
|
673
|
-
var transitionDuration = 0
|
674
|
-
|
861
|
+
var transitionDuration = 0;
|
862
|
+
var transitionDelay = 0;
|
863
|
+
var animationDuration = 0;
|
864
|
+
var animationDelay = 0;
|
865
|
+
var transitionDelayStyle;
|
866
|
+
var animationDelayStyle;
|
867
|
+
var transitionDurationStyle;
|
868
|
+
var transitionPropertyStyle;
|
675
869
|
|
676
870
|
//we want all the styles defined before and after
|
677
871
|
forEach(element, function(element) {
|
678
872
|
if (element.nodeType == ELEMENT_NODE) {
|
679
873
|
var elementStyles = $window.getComputedStyle(element) || {};
|
680
874
|
|
681
|
-
|
875
|
+
transitionDurationStyle = elementStyles[TRANSITION_PROP + DURATION_KEY];
|
876
|
+
|
877
|
+
transitionDuration = Math.max(parseMaxTime(transitionDurationStyle), transitionDuration);
|
682
878
|
|
683
|
-
|
684
|
-
transitionDelay = Math.max(parseMaxTime(elementStyles[transitionProp + delayKey]), transitionDelay);
|
879
|
+
transitionPropertyStyle = elementStyles[TRANSITION_PROP + PROPERTY_KEY];
|
685
880
|
|
686
|
-
|
881
|
+
transitionDelayStyle = elementStyles[TRANSITION_PROP + DELAY_KEY];
|
687
882
|
|
688
|
-
|
883
|
+
transitionDelay = Math.max(parseMaxTime(transitionDelayStyle), transitionDelay);
|
689
884
|
|
690
|
-
|
691
|
-
aDuration *= parseInt(elementStyles[animationProp + animationIterationCountKey]) || 1;
|
692
|
-
}
|
885
|
+
animationDelayStyle = elementStyles[ANIMATION_PROP + DELAY_KEY];
|
693
886
|
|
694
|
-
|
887
|
+
animationDelay = Math.max(parseMaxTime(animationDelayStyle), animationDelay);
|
888
|
+
|
889
|
+
var aDuration = parseMaxTime(elementStyles[ANIMATION_PROP + DURATION_KEY]);
|
890
|
+
|
891
|
+
if(aDuration > 0) {
|
892
|
+
aDuration *= parseInt(elementStyles[ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY], 10) || 1;
|
695
893
|
}
|
894
|
+
|
895
|
+
animationDuration = Math.max(aDuration, animationDuration);
|
696
896
|
}
|
697
897
|
});
|
698
898
|
data = {
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
899
|
+
total : 0,
|
900
|
+
transitionPropertyStyle: transitionPropertyStyle,
|
901
|
+
transitionDurationStyle: transitionDurationStyle,
|
902
|
+
transitionDelayStyle: transitionDelayStyle,
|
903
|
+
transitionDelay: transitionDelay,
|
904
|
+
transitionDuration: transitionDuration,
|
905
|
+
animationDelayStyle: animationDelayStyle,
|
906
|
+
animationDelay: animationDelay,
|
907
|
+
animationDuration: animationDuration
|
703
908
|
};
|
704
|
-
|
909
|
+
if(cacheKey) {
|
910
|
+
lookupCache[cacheKey] = data;
|
911
|
+
}
|
705
912
|
}
|
706
913
|
return data;
|
707
914
|
}
|
708
915
|
|
709
916
|
function parseMaxTime(str) {
|
710
|
-
var
|
917
|
+
var maxValue = 0;
|
918
|
+
var values = angular.isString(str) ?
|
919
|
+
str.split(/\s*,\s*/) :
|
920
|
+
[];
|
711
921
|
forEach(values, function(value) {
|
712
|
-
|
922
|
+
maxValue = Math.max(parseFloat(value) || 0, maxValue);
|
713
923
|
});
|
714
|
-
return
|
924
|
+
return maxValue;
|
715
925
|
}
|
716
926
|
|
717
927
|
function getCacheKey(element) {
|
718
|
-
var
|
719
|
-
var parentID =
|
928
|
+
var parentElement = element.parent();
|
929
|
+
var parentID = parentElement.data(NG_ANIMATE_PARENT_KEY);
|
720
930
|
if(!parentID) {
|
721
|
-
|
931
|
+
parentElement.data(NG_ANIMATE_PARENT_KEY, ++parentCounter);
|
722
932
|
parentID = parentCounter;
|
723
933
|
}
|
724
934
|
return parentID + '-' + element[0].className;
|
725
935
|
}
|
726
936
|
|
727
|
-
function
|
728
|
-
|
937
|
+
function animateSetup(element, className) {
|
729
938
|
var cacheKey = getCacheKey(element);
|
730
|
-
|
939
|
+
var eventCacheKey = cacheKey + ' ' + className;
|
940
|
+
var stagger = {};
|
941
|
+
var ii = lookupCache[eventCacheKey] ? ++lookupCache[eventCacheKey].total : 0;
|
731
942
|
|
732
|
-
|
733
|
-
|
943
|
+
if(ii > 0) {
|
944
|
+
var staggerClassName = className + '-stagger';
|
945
|
+
var staggerCacheKey = cacheKey + ' ' + staggerClassName;
|
946
|
+
var applyClasses = !lookupCache[staggerCacheKey];
|
947
|
+
|
948
|
+
applyClasses && element.addClass(staggerClassName);
|
949
|
+
|
950
|
+
stagger = getElementAnimationDetails(element, staggerCacheKey);
|
951
|
+
|
952
|
+
applyClasses && element.removeClass(staggerClassName);
|
734
953
|
}
|
735
954
|
|
736
955
|
element.addClass(className);
|
737
956
|
|
738
|
-
var timings = getElementAnimationDetails(element,
|
957
|
+
var timings = getElementAnimationDetails(element, eventCacheKey);
|
739
958
|
|
740
959
|
/* there is no point in performing a reflow if the animation
|
741
960
|
timeout is empty (this would cause a flicker bug normally
|
742
961
|
in the page. There is also no point in performing an animation
|
743
962
|
that only has a delay and no duration */
|
744
963
|
var maxDuration = Math.max(timings.transitionDuration, timings.animationDuration);
|
745
|
-
if(maxDuration
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
//temporarily disable the transition so that the enter styles
|
751
|
-
//don't animate twice (this is here to avoid a bug in Chrome/FF).
|
752
|
-
if(timings.transitionDuration > 0) {
|
753
|
-
node.style[transitionProp + propertyKey] = 'none';
|
754
|
-
}
|
964
|
+
if(maxDuration === 0) {
|
965
|
+
element.removeClass(className);
|
966
|
+
return false;
|
967
|
+
}
|
755
968
|
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
969
|
+
var node = element[0];
|
970
|
+
//temporarily disable the transition so that the enter styles
|
971
|
+
//don't animate twice (this is here to avoid a bug in Chrome/FF).
|
972
|
+
var activeClassName = '';
|
973
|
+
if(timings.transitionDuration > 0) {
|
974
|
+
element.addClass(NG_ANIMATE_FALLBACK_CLASS_NAME);
|
975
|
+
activeClassName += NG_ANIMATE_FALLBACK_ACTIVE_CLASS_NAME + ' ';
|
976
|
+
node.style[TRANSITION_PROP + PROPERTY_KEY] = 'none';
|
977
|
+
}
|
760
978
|
|
761
|
-
|
762
|
-
|
979
|
+
forEach(className.split(' '), function(klass, i) {
|
980
|
+
activeClassName += (i > 0 ? ' ' : '') + klass + '-active';
|
981
|
+
});
|
763
982
|
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
983
|
+
element.data(NG_ANIMATE_CSS_DATA_KEY, {
|
984
|
+
className : className,
|
985
|
+
activeClassName : activeClassName,
|
986
|
+
maxDuration : maxDuration,
|
987
|
+
classes : className + ' ' + activeClassName,
|
988
|
+
timings : timings,
|
989
|
+
stagger : stagger,
|
990
|
+
ii : ii
|
991
|
+
});
|
992
|
+
|
993
|
+
return true;
|
994
|
+
}
|
770
995
|
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
996
|
+
function animateRun(element, className, activeAnimationComplete) {
|
997
|
+
var data = element.data(NG_ANIMATE_CSS_DATA_KEY);
|
998
|
+
if(!element.hasClass(className) || !data) {
|
999
|
+
activeAnimationComplete();
|
1000
|
+
return;
|
1001
|
+
}
|
1002
|
+
|
1003
|
+
var node = element[0];
|
1004
|
+
var timings = data.timings;
|
1005
|
+
var stagger = data.stagger;
|
1006
|
+
var maxDuration = data.maxDuration;
|
1007
|
+
var activeClassName = data.activeClassName;
|
1008
|
+
var maxDelayTime = Math.max(timings.transitionDelay, timings.animationDelay) * 1000;
|
1009
|
+
var startTime = Date.now();
|
1010
|
+
var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT;
|
1011
|
+
var formerStyle;
|
1012
|
+
var ii = data.ii;
|
1013
|
+
|
1014
|
+
var applyFallbackStyle, style = '';
|
1015
|
+
if(timings.transitionDuration > 0) {
|
1016
|
+
node.style[TRANSITION_PROP + PROPERTY_KEY] = '';
|
1017
|
+
|
1018
|
+
var propertyStyle = timings.transitionPropertyStyle;
|
1019
|
+
if(propertyStyle.indexOf('all') == -1) {
|
1020
|
+
applyFallbackStyle = true;
|
1021
|
+
var fallbackProperty = $sniffer.msie ? '-ms-zoom' : 'clip';
|
1022
|
+
style += CSS_PREFIX + 'transition-property: ' + propertyStyle + ', ' + fallbackProperty + '; ';
|
1023
|
+
style += CSS_PREFIX + 'transition-duration: ' + timings.transitionDurationStyle + ', ' + timings.transitionDuration + 's; ';
|
1024
|
+
}
|
1025
|
+
}
|
1026
|
+
|
1027
|
+
if(ii > 0) {
|
1028
|
+
if(stagger.transitionDelay > 0 && stagger.transitionDuration === 0) {
|
1029
|
+
var delayStyle = timings.transitionDelayStyle;
|
1030
|
+
if(applyFallbackStyle) {
|
1031
|
+
delayStyle += ', ' + timings.transitionDelay + 's';
|
786
1032
|
}
|
1033
|
+
|
1034
|
+
style += CSS_PREFIX + 'transition-delay: ' +
|
1035
|
+
prepareStaggerDelay(delayStyle, stagger.transitionDelay, ii) + '; ';
|
1036
|
+
}
|
1037
|
+
|
1038
|
+
if(stagger.animationDelay > 0 && stagger.animationDuration === 0) {
|
1039
|
+
style += CSS_PREFIX + 'animation-delay: ' +
|
1040
|
+
prepareStaggerDelay(timings.animationDelayStyle, stagger.animationDelay, ii) + '; ';
|
787
1041
|
}
|
788
1042
|
}
|
789
|
-
|
790
|
-
|
791
|
-
|
1043
|
+
|
1044
|
+
if(style.length > 0) {
|
1045
|
+
formerStyle = applyStyle(node, style);
|
792
1046
|
}
|
793
1047
|
|
1048
|
+
element.on(css3AnimationEvents, onAnimationProgress);
|
1049
|
+
element.addClass(activeClassName);
|
1050
|
+
|
1051
|
+
// This will automatically be called by $animate so
|
1052
|
+
// there is no need to attach this internally to the
|
1053
|
+
// timeout done method.
|
1054
|
+
return function onEnd(cancelled) {
|
1055
|
+
element.off(css3AnimationEvents, onAnimationProgress);
|
1056
|
+
element.removeClass(activeClassName);
|
1057
|
+
animateClose(element, className);
|
1058
|
+
if(formerStyle != null) {
|
1059
|
+
formerStyle.length > 0 ?
|
1060
|
+
node.setAttribute('style', formerStyle) :
|
1061
|
+
node.removeAttribute('style');
|
1062
|
+
}
|
1063
|
+
};
|
1064
|
+
|
794
1065
|
function onAnimationProgress(event) {
|
795
1066
|
event.stopPropagation();
|
796
1067
|
var ev = event.originalEvent || event;
|
@@ -803,27 +1074,138 @@ angular.module('ngAnimate', ['ng'])
|
|
803
1074
|
* but we're using elapsedTime instead of the timeStamp on the 2nd
|
804
1075
|
* pre-condition since animations sometimes close off early */
|
805
1076
|
if(Math.max(timeStamp - startTime, 0) >= maxDelayTime && ev.elapsedTime >= maxDuration) {
|
806
|
-
|
1077
|
+
activeAnimationComplete();
|
807
1078
|
}
|
808
1079
|
}
|
1080
|
+
}
|
1081
|
+
|
1082
|
+
function prepareStaggerDelay(delayStyle, staggerDelay, index) {
|
1083
|
+
var style = '';
|
1084
|
+
forEach(delayStyle.split(','), function(val, i) {
|
1085
|
+
style += (i > 0 ? ',' : '') +
|
1086
|
+
(index * staggerDelay + parseInt(val, 10)) + 's';
|
1087
|
+
});
|
1088
|
+
return style;
|
1089
|
+
}
|
1090
|
+
|
1091
|
+
function animateBefore(element, className) {
|
1092
|
+
if(animateSetup(element, className)) {
|
1093
|
+
return function(cancelled) {
|
1094
|
+
cancelled && animateClose(element, className);
|
1095
|
+
};
|
1096
|
+
}
|
1097
|
+
}
|
1098
|
+
|
1099
|
+
function animateAfter(element, className, afterAnimationComplete) {
|
1100
|
+
if(element.data(NG_ANIMATE_CSS_DATA_KEY)) {
|
1101
|
+
return animateRun(element, className, afterAnimationComplete);
|
1102
|
+
} else {
|
1103
|
+
animateClose(element, className);
|
1104
|
+
afterAnimationComplete();
|
1105
|
+
}
|
1106
|
+
}
|
1107
|
+
|
1108
|
+
function animate(element, className, animationComplete) {
|
1109
|
+
//If the animateSetup function doesn't bother returning a
|
1110
|
+
//cancellation function then it means that there is no animation
|
1111
|
+
//to perform at all
|
1112
|
+
var preReflowCancellation = animateBefore(element, className);
|
1113
|
+
if(!preReflowCancellation) {
|
1114
|
+
animationComplete();
|
1115
|
+
return;
|
1116
|
+
}
|
1117
|
+
|
1118
|
+
//There are two cancellation functions: one is before the first
|
1119
|
+
//reflow animation and the second is during the active state
|
1120
|
+
//animation. The first function will take care of removing the
|
1121
|
+
//data from the element which will not make the 2nd animation
|
1122
|
+
//happen in the first place
|
1123
|
+
var cancel = preReflowCancellation;
|
1124
|
+
afterReflow(function() {
|
1125
|
+
//once the reflow is complete then we point cancel to
|
1126
|
+
//the new cancellation function which will remove all of the
|
1127
|
+
//animation properties from the active animation
|
1128
|
+
cancel = animateAfter(element, className, animationComplete);
|
1129
|
+
});
|
809
1130
|
|
1131
|
+
return function(cancelled) {
|
1132
|
+
(cancel || noop)(cancelled);
|
1133
|
+
};
|
1134
|
+
}
|
1135
|
+
|
1136
|
+
function animateClose(element, className) {
|
1137
|
+
element.removeClass(className);
|
1138
|
+
element.removeClass(NG_ANIMATE_FALLBACK_CLASS_NAME);
|
1139
|
+
element.removeData(NG_ANIMATE_CSS_DATA_KEY);
|
810
1140
|
}
|
811
1141
|
|
812
1142
|
return {
|
813
|
-
|
814
|
-
|
1143
|
+
allowCancel : function(element, animationEvent, className) {
|
1144
|
+
//always cancel the current animation if it is a
|
1145
|
+
//structural animation
|
1146
|
+
var oldClasses = (element.data(NG_ANIMATE_CSS_DATA_KEY) || {}).classes;
|
1147
|
+
if(!oldClasses || ['enter','leave','move'].indexOf(animationEvent) >= 0) {
|
1148
|
+
return true;
|
1149
|
+
}
|
1150
|
+
|
1151
|
+
var parentElement = element.parent();
|
1152
|
+
var clone = angular.element(element[0].cloneNode());
|
1153
|
+
|
1154
|
+
//make the element super hidden and override any CSS style values
|
1155
|
+
clone.attr('style','position:absolute; top:-9999px; left:-9999px');
|
1156
|
+
clone.removeAttr('id');
|
1157
|
+
clone.html('');
|
1158
|
+
|
1159
|
+
forEach(oldClasses.split(' '), function(klass) {
|
1160
|
+
clone.removeClass(klass);
|
1161
|
+
});
|
1162
|
+
|
1163
|
+
var suffix = animationEvent == 'addClass' ? '-add' : '-remove';
|
1164
|
+
clone.addClass(suffixClasses(className, suffix));
|
1165
|
+
parentElement.append(clone);
|
1166
|
+
|
1167
|
+
var timings = getElementAnimationDetails(clone);
|
1168
|
+
clone.remove();
|
1169
|
+
|
1170
|
+
return Math.max(timings.transitionDuration, timings.animationDuration) > 0;
|
1171
|
+
},
|
1172
|
+
|
1173
|
+
enter : function(element, animationCompleted) {
|
1174
|
+
return animate(element, 'ng-enter', animationCompleted);
|
815
1175
|
},
|
816
|
-
|
817
|
-
|
1176
|
+
|
1177
|
+
leave : function(element, animationCompleted) {
|
1178
|
+
return animate(element, 'ng-leave', animationCompleted);
|
818
1179
|
},
|
819
|
-
|
820
|
-
|
1180
|
+
|
1181
|
+
move : function(element, animationCompleted) {
|
1182
|
+
return animate(element, 'ng-move', animationCompleted);
|
821
1183
|
},
|
822
|
-
|
823
|
-
|
1184
|
+
|
1185
|
+
beforeAddClass : function(element, className, animationCompleted) {
|
1186
|
+
var cancellationMethod = animateBefore(element, suffixClasses(className, '-add'));
|
1187
|
+
if(cancellationMethod) {
|
1188
|
+
afterReflow(animationCompleted);
|
1189
|
+
return cancellationMethod;
|
1190
|
+
}
|
1191
|
+
animationCompleted();
|
824
1192
|
},
|
825
|
-
|
826
|
-
|
1193
|
+
|
1194
|
+
addClass : function(element, className, animationCompleted) {
|
1195
|
+
return animateAfter(element, suffixClasses(className, '-add'), animationCompleted);
|
1196
|
+
},
|
1197
|
+
|
1198
|
+
beforeRemoveClass : function(element, className, animationCompleted) {
|
1199
|
+
var cancellationMethod = animateBefore(element, suffixClasses(className, '-remove'));
|
1200
|
+
if(cancellationMethod) {
|
1201
|
+
afterReflow(animationCompleted);
|
1202
|
+
return cancellationMethod;
|
1203
|
+
}
|
1204
|
+
animationCompleted();
|
1205
|
+
},
|
1206
|
+
|
1207
|
+
removeClass : function(element, className, animationCompleted) {
|
1208
|
+
return animateAfter(element, suffixClasses(className, '-remove'), animationCompleted);
|
827
1209
|
}
|
828
1210
|
};
|
829
1211
|
|