material_raingular 0.0.7 → 0.1.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/.gitignore +1 -0
- data/lib/material_raingular/version.rb +1 -1
- data/vendor/assets/angular/angular-animate.js +1027 -620
- data/vendor/assets/angular/angular-aria.js +111 -91
- data/vendor/assets/angular/angular-cookies.js +17 -15
- data/vendor/assets/angular/angular-loader.js +70 -15
- data/vendor/assets/angular/angular-material.min.css +2 -2
- data/vendor/assets/angular/angular-material.min.js +10 -9
- data/vendor/assets/angular/angular-message-format.js +2 -2
- data/vendor/assets/angular/angular-messages.js +77 -33
- data/vendor/assets/angular/angular-resource.js +140 -40
- data/vendor/assets/angular/angular-route.js +52 -21
- data/vendor/assets/angular/angular-sanitize.js +283 -249
- data/vendor/assets/angular/angular-touch.js +117 -15
- data/vendor/assets/angular/angular.js +4528 -1947
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7420a6e01c283917cb97615df004d13474b5388a
|
4
|
+
data.tar.gz: dcab33fe3307b14c36b1e4f895c67d5983faccee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d0ea8125a33948cf5f406cd27110305ceb2e0475f1516784828599a45bd73eeac94e5c21b500906271938fd805a5c9a73e0c50642d1382202e7e6c9ea4eb39c
|
7
|
+
data.tar.gz: 30fb7edfd244066b7dd091bf405c9e470abfa6575650e4e5b0e178b3218635a21d5624e39eead40a13b290357ed0f009f3d561e66c193e8fcf336527d33e18bf
|
data/.gitignore
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.
|
3
|
-
* (c) 2010-
|
2
|
+
* @license AngularJS v1.5.3
|
3
|
+
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
6
6
|
(function(window, angular, undefined) {'use strict';
|
7
7
|
|
8
8
|
/* jshint ignore:start */
|
9
9
|
var noop = angular.noop;
|
10
|
+
var copy = angular.copy;
|
10
11
|
var extend = angular.extend;
|
11
12
|
var jqLite = angular.element;
|
12
13
|
var forEach = angular.forEach;
|
@@ -21,13 +22,63 @@ var isElement = angular.isElement;
|
|
21
22
|
var ELEMENT_NODE = 1;
|
22
23
|
var COMMENT_NODE = 8;
|
23
24
|
|
25
|
+
var ADD_CLASS_SUFFIX = '-add';
|
26
|
+
var REMOVE_CLASS_SUFFIX = '-remove';
|
27
|
+
var EVENT_CLASS_PREFIX = 'ng-';
|
28
|
+
var ACTIVE_CLASS_SUFFIX = '-active';
|
29
|
+
var PREPARE_CLASS_SUFFIX = '-prepare';
|
30
|
+
|
24
31
|
var NG_ANIMATE_CLASSNAME = 'ng-animate';
|
25
32
|
var NG_ANIMATE_CHILDREN_DATA = '$$ngAnimateChildren';
|
26
33
|
|
34
|
+
// Detect proper transitionend/animationend event names.
|
35
|
+
var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT;
|
36
|
+
|
37
|
+
// If unprefixed events are not supported but webkit-prefixed are, use the latter.
|
38
|
+
// Otherwise, just use W3C names, browsers not supporting them at all will just ignore them.
|
39
|
+
// Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend`
|
40
|
+
// but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`.
|
41
|
+
// Register both events in case `window.onanimationend` is not supported because of that,
|
42
|
+
// do the same for `transitionend` as Safari is likely to exhibit similar behavior.
|
43
|
+
// Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit
|
44
|
+
// therefore there is no reason to test anymore for other vendor prefixes:
|
45
|
+
// http://caniuse.com/#search=transition
|
46
|
+
if (isUndefined(window.ontransitionend) && isDefined(window.onwebkittransitionend)) {
|
47
|
+
CSS_PREFIX = '-webkit-';
|
48
|
+
TRANSITION_PROP = 'WebkitTransition';
|
49
|
+
TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
|
50
|
+
} else {
|
51
|
+
TRANSITION_PROP = 'transition';
|
52
|
+
TRANSITIONEND_EVENT = 'transitionend';
|
53
|
+
}
|
54
|
+
|
55
|
+
if (isUndefined(window.onanimationend) && isDefined(window.onwebkitanimationend)) {
|
56
|
+
CSS_PREFIX = '-webkit-';
|
57
|
+
ANIMATION_PROP = 'WebkitAnimation';
|
58
|
+
ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';
|
59
|
+
} else {
|
60
|
+
ANIMATION_PROP = 'animation';
|
61
|
+
ANIMATIONEND_EVENT = 'animationend';
|
62
|
+
}
|
63
|
+
|
64
|
+
var DURATION_KEY = 'Duration';
|
65
|
+
var PROPERTY_KEY = 'Property';
|
66
|
+
var DELAY_KEY = 'Delay';
|
67
|
+
var TIMING_KEY = 'TimingFunction';
|
68
|
+
var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';
|
69
|
+
var ANIMATION_PLAYSTATE_KEY = 'PlayState';
|
70
|
+
var SAFE_FAST_FORWARD_DURATION_VALUE = 9999;
|
71
|
+
|
72
|
+
var ANIMATION_DELAY_PROP = ANIMATION_PROP + DELAY_KEY;
|
73
|
+
var ANIMATION_DURATION_PROP = ANIMATION_PROP + DURATION_KEY;
|
74
|
+
var TRANSITION_DELAY_PROP = TRANSITION_PROP + DELAY_KEY;
|
75
|
+
var TRANSITION_DURATION_PROP = TRANSITION_PROP + DURATION_KEY;
|
76
|
+
|
27
77
|
var isPromiseLike = function(p) {
|
28
78
|
return p && p.then ? true : false;
|
29
|
-
}
|
79
|
+
};
|
30
80
|
|
81
|
+
var ngMinErr = angular.$$minErr('ng');
|
31
82
|
function assertArg(arg, name, reason) {
|
32
83
|
if (!arg) {
|
33
84
|
throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
|
@@ -172,13 +223,29 @@ function applyAnimationToStyles(element, options) {
|
|
172
223
|
}
|
173
224
|
}
|
174
225
|
|
175
|
-
function
|
226
|
+
function mergeAnimationDetails(element, oldAnimation, newAnimation) {
|
227
|
+
var target = oldAnimation.options || {};
|
228
|
+
var newOptions = newAnimation.options || {};
|
229
|
+
|
176
230
|
var toAdd = (target.addClass || '') + ' ' + (newOptions.addClass || '');
|
177
231
|
var toRemove = (target.removeClass || '') + ' ' + (newOptions.removeClass || '');
|
178
232
|
var classes = resolveElementClasses(element.attr('class'), toAdd, toRemove);
|
179
233
|
|
234
|
+
if (newOptions.preparationClasses) {
|
235
|
+
target.preparationClasses = concatWithSpace(newOptions.preparationClasses, target.preparationClasses);
|
236
|
+
delete newOptions.preparationClasses;
|
237
|
+
}
|
238
|
+
|
239
|
+
// noop is basically when there is no callback; otherwise something has been set
|
240
|
+
var realDomOperation = target.domOperation !== noop ? target.domOperation : null;
|
241
|
+
|
180
242
|
extend(target, newOptions);
|
181
243
|
|
244
|
+
// TODO(matsko or sreeramu): proper fix is to maintain all animation callback in array and call at last,but now only leave has the callback so no issue with this.
|
245
|
+
if (realDomOperation) {
|
246
|
+
target.domOperation = realDomOperation;
|
247
|
+
}
|
248
|
+
|
182
249
|
if (classes.addClass) {
|
183
250
|
target.addClass = classes.addClass;
|
184
251
|
} else {
|
@@ -191,6 +258,9 @@ function mergeAnimationOptions(element, target, newOptions) {
|
|
191
258
|
target.removeClass = null;
|
192
259
|
}
|
193
260
|
|
261
|
+
oldAnimation.addClass = target.addClass;
|
262
|
+
oldAnimation.removeClass = target.removeClass;
|
263
|
+
|
194
264
|
return target;
|
195
265
|
}
|
196
266
|
|
@@ -256,20 +326,77 @@ function getDomNode(element) {
|
|
256
326
|
return (element instanceof angular.element) ? element[0] : element;
|
257
327
|
}
|
258
328
|
|
329
|
+
function applyGeneratedPreparationClasses(element, event, options) {
|
330
|
+
var classes = '';
|
331
|
+
if (event) {
|
332
|
+
classes = pendClasses(event, EVENT_CLASS_PREFIX, true);
|
333
|
+
}
|
334
|
+
if (options.addClass) {
|
335
|
+
classes = concatWithSpace(classes, pendClasses(options.addClass, ADD_CLASS_SUFFIX));
|
336
|
+
}
|
337
|
+
if (options.removeClass) {
|
338
|
+
classes = concatWithSpace(classes, pendClasses(options.removeClass, REMOVE_CLASS_SUFFIX));
|
339
|
+
}
|
340
|
+
if (classes.length) {
|
341
|
+
options.preparationClasses = classes;
|
342
|
+
element.addClass(classes);
|
343
|
+
}
|
344
|
+
}
|
345
|
+
|
346
|
+
function clearGeneratedClasses(element, options) {
|
347
|
+
if (options.preparationClasses) {
|
348
|
+
element.removeClass(options.preparationClasses);
|
349
|
+
options.preparationClasses = null;
|
350
|
+
}
|
351
|
+
if (options.activeClasses) {
|
352
|
+
element.removeClass(options.activeClasses);
|
353
|
+
options.activeClasses = null;
|
354
|
+
}
|
355
|
+
}
|
356
|
+
|
357
|
+
function blockTransitions(node, duration) {
|
358
|
+
// we use a negative delay value since it performs blocking
|
359
|
+
// yet it doesn't kill any existing transitions running on the
|
360
|
+
// same element which makes this safe for class-based animations
|
361
|
+
var value = duration ? '-' + duration + 's' : '';
|
362
|
+
applyInlineStyle(node, [TRANSITION_DELAY_PROP, value]);
|
363
|
+
return [TRANSITION_DELAY_PROP, value];
|
364
|
+
}
|
365
|
+
|
366
|
+
function blockKeyframeAnimations(node, applyBlock) {
|
367
|
+
var value = applyBlock ? 'paused' : '';
|
368
|
+
var key = ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY;
|
369
|
+
applyInlineStyle(node, [key, value]);
|
370
|
+
return [key, value];
|
371
|
+
}
|
372
|
+
|
373
|
+
function applyInlineStyle(node, styleTuple) {
|
374
|
+
var prop = styleTuple[0];
|
375
|
+
var value = styleTuple[1];
|
376
|
+
node.style[prop] = value;
|
377
|
+
}
|
378
|
+
|
379
|
+
function concatWithSpace(a,b) {
|
380
|
+
if (!a) return b;
|
381
|
+
if (!b) return a;
|
382
|
+
return a + ' ' + b;
|
383
|
+
}
|
384
|
+
|
259
385
|
var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) {
|
260
|
-
var
|
261
|
-
var cancelFn;
|
386
|
+
var queue, cancelFn;
|
262
387
|
|
263
388
|
function scheduler(tasks) {
|
264
389
|
// we make a copy since RAFScheduler mutates the state
|
265
390
|
// of the passed in array variable and this would be difficult
|
266
391
|
// to track down on the outside code
|
267
|
-
|
392
|
+
queue = queue.concat(tasks);
|
268
393
|
nextTick();
|
269
394
|
}
|
270
395
|
|
396
|
+
queue = scheduler.queue = [];
|
397
|
+
|
271
398
|
/* waitUntilQuiet does two things:
|
272
|
-
* 1. It will run the FINAL `fn` value only when an
|
399
|
+
* 1. It will run the FINAL `fn` value only when an uncanceled RAF has passed through
|
273
400
|
* 2. It will delay the next wave of tasks from running until the quiet `fn` has run.
|
274
401
|
*
|
275
402
|
* The motivation here is that animation code can request more time from the scheduler
|
@@ -289,17 +416,12 @@ var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) {
|
|
289
416
|
return scheduler;
|
290
417
|
|
291
418
|
function nextTick() {
|
292
|
-
if (!
|
419
|
+
if (!queue.length) return;
|
293
420
|
|
294
|
-
var
|
295
|
-
for (var i = 0; i <
|
296
|
-
|
297
|
-
runNextTask(innerQueue);
|
298
|
-
if (innerQueue.length) {
|
299
|
-
updatedQueue.push(innerQueue);
|
300
|
-
}
|
421
|
+
var items = queue.shift();
|
422
|
+
for (var i = 0; i < items.length; i++) {
|
423
|
+
items[i]();
|
301
424
|
}
|
302
|
-
tickQueue = updatedQueue;
|
303
425
|
|
304
426
|
if (!cancelFn) {
|
305
427
|
$$rAF(function() {
|
@@ -307,27 +429,109 @@ var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) {
|
|
307
429
|
});
|
308
430
|
}
|
309
431
|
}
|
310
|
-
|
311
|
-
function runNextTask(tasks) {
|
312
|
-
var nextTask = tasks.shift();
|
313
|
-
nextTask();
|
314
|
-
}
|
315
432
|
}];
|
316
433
|
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
434
|
+
/**
|
435
|
+
* @ngdoc directive
|
436
|
+
* @name ngAnimateChildren
|
437
|
+
* @restrict AE
|
438
|
+
* @element ANY
|
439
|
+
*
|
440
|
+
* @description
|
441
|
+
*
|
442
|
+
* ngAnimateChildren allows you to specify that children of this element should animate even if any
|
443
|
+
* of the children's parents are currently animating. By default, when an element has an active `enter`, `leave`, or `move`
|
444
|
+
* (structural) animation, child elements that also have an active structural animation are not animated.
|
445
|
+
*
|
446
|
+
* Note that even if `ngAnimteChildren` is set, no child animations will run when the parent element is removed from the DOM (`leave` animation).
|
447
|
+
*
|
448
|
+
*
|
449
|
+
* @param {string} ngAnimateChildren If the value is empty, `true` or `on`,
|
450
|
+
* then child animations are allowed. If the value is `false`, child animations are not allowed.
|
451
|
+
*
|
452
|
+
* @example
|
453
|
+
* <example module="ngAnimateChildren" name="ngAnimateChildren" deps="angular-animate.js" animations="true">
|
454
|
+
<file name="index.html">
|
455
|
+
<div ng-controller="mainController as main">
|
456
|
+
<label>Show container? <input type="checkbox" ng-model="main.enterElement" /></label>
|
457
|
+
<label>Animate children? <input type="checkbox" ng-model="main.animateChildren" /></label>
|
458
|
+
<hr>
|
459
|
+
<div ng-animate-children="{{main.animateChildren}}">
|
460
|
+
<div ng-if="main.enterElement" class="container">
|
461
|
+
List of items:
|
462
|
+
<div ng-repeat="item in [0, 1, 2, 3]" class="item">Item {{item}}</div>
|
463
|
+
</div>
|
464
|
+
</div>
|
465
|
+
</div>
|
466
|
+
</file>
|
467
|
+
<file name="animations.css">
|
468
|
+
|
469
|
+
.container.ng-enter,
|
470
|
+
.container.ng-leave {
|
471
|
+
transition: all ease 1.5s;
|
472
|
+
}
|
473
|
+
|
474
|
+
.container.ng-enter,
|
475
|
+
.container.ng-leave-active {
|
476
|
+
opacity: 0;
|
477
|
+
}
|
478
|
+
|
479
|
+
.container.ng-leave,
|
480
|
+
.container.ng-enter-active {
|
481
|
+
opacity: 1;
|
482
|
+
}
|
483
|
+
|
484
|
+
.item {
|
485
|
+
background: firebrick;
|
486
|
+
color: #FFF;
|
487
|
+
margin-bottom: 10px;
|
488
|
+
}
|
489
|
+
|
490
|
+
.item.ng-enter,
|
491
|
+
.item.ng-leave {
|
492
|
+
transition: transform 1.5s ease;
|
493
|
+
}
|
494
|
+
|
495
|
+
.item.ng-enter {
|
496
|
+
transform: translateX(50px);
|
497
|
+
}
|
498
|
+
|
499
|
+
.item.ng-enter-active {
|
500
|
+
transform: translateX(0);
|
501
|
+
}
|
502
|
+
</file>
|
503
|
+
<file name="script.js">
|
504
|
+
angular.module('ngAnimateChildren', ['ngAnimate'])
|
505
|
+
.controller('mainController', function() {
|
506
|
+
this.animateChildren = false;
|
507
|
+
this.enterElement = false;
|
508
|
+
});
|
509
|
+
</file>
|
510
|
+
</example>
|
511
|
+
*/
|
512
|
+
var $$AnimateChildrenDirective = ['$interpolate', function($interpolate) {
|
513
|
+
return {
|
514
|
+
link: function(scope, element, attrs) {
|
515
|
+
var val = attrs.ngAnimateChildren;
|
516
|
+
if (angular.isString(val) && val.length === 0) { //empty attribute
|
517
|
+
element.data(NG_ANIMATE_CHILDREN_DATA, true);
|
518
|
+
} else {
|
519
|
+
// Interpolate and set the value, so that it is available to
|
520
|
+
// animations that run right after compilation
|
521
|
+
setData($interpolate(val)(scope));
|
522
|
+
attrs.$observe('ngAnimateChildren', setData);
|
523
|
+
}
|
524
|
+
|
525
|
+
function setData(value) {
|
324
526
|
value = value === 'on' || value === 'true';
|
325
527
|
element.data(NG_ANIMATE_CHILDREN_DATA, value);
|
326
|
-
}
|
528
|
+
}
|
327
529
|
}
|
328
530
|
};
|
329
531
|
}];
|
330
532
|
|
533
|
+
var ANIMATE_TIMER_KEY = '$$animateCss';
|
534
|
+
|
331
535
|
/**
|
332
536
|
* @ngdoc service
|
333
537
|
* @name $animateCss
|
@@ -493,7 +697,7 @@ var $$AnimateChildrenDirective = [function() {
|
|
493
697
|
* ```
|
494
698
|
*
|
495
699
|
* To actually start the animation we need to run `animation.start()` which will then return a promise that we can hook into to detect when the animation ends.
|
496
|
-
* If we choose not to run the animation then we MUST run `animation.end()` to perform a cleanup on the element (since some CSS classes and
|
700
|
+
* If we choose not to run the animation then we MUST run `animation.end()` to perform a cleanup on the element (since some CSS classes and styles may have been
|
497
701
|
* applied to the element during the preparation phase). Note that all other properties such as duration, delay, transitions and keyframes are just properties
|
498
702
|
* and that changing them will not reconfigure the parameters of the animation.
|
499
703
|
*
|
@@ -504,16 +708,19 @@ var $$AnimateChildrenDirective = [function() {
|
|
504
708
|
* unless you really need a digest to kick off afterwards.
|
505
709
|
*
|
506
710
|
* Keep in mind that, to make this easier, ngAnimate has tweaked the JS animations API to recognize when a runner instance is returned from $animateCss
|
507
|
-
* (so there is no need to call `runner.done(doneFn)` inside of your JavaScript animation code).
|
711
|
+
* (so there is no need to call `runner.done(doneFn)` inside of your JavaScript animation code).
|
712
|
+
* Check the {@link ngAnimate.$animateCss#usage animation code above} to see how this works.
|
508
713
|
*
|
509
714
|
* @param {DOMElement} element the element that will be animated
|
510
715
|
* @param {object} options the animation-related options that will be applied during the animation
|
511
716
|
*
|
512
717
|
* * `event` - The DOM event (e.g. enter, leave, move). When used, a generated CSS class of `ng-EVENT` and `ng-EVENT-active` will be applied
|
513
718
|
* to the element during the animation. Multiple events can be provided when spaces are used as a separator. (Note that this will not perform any DOM operation.)
|
719
|
+
* * `structural` - Indicates that the `ng-` prefix will be added to the event class. Setting to `false` or omitting will turn `ng-EVENT` and
|
720
|
+
* `ng-EVENT-active` in `EVENT` and `EVENT-active`. Unused if `event` is omitted.
|
514
721
|
* * `easing` - The CSS easing value that will be applied to the transition or keyframe animation (or both).
|
515
|
-
* * `
|
516
|
-
* * `
|
722
|
+
* * `transitionStyle` - The raw CSS transition style that will be used (e.g. `1s linear all`).
|
723
|
+
* * `keyframeStyle` - The raw CSS keyframe animation style that will be used (e.g. `1s my_animation linear`).
|
517
724
|
* * `from` - The starting CSS styles (a key/value object) that will be applied at the start of the animation.
|
518
725
|
* * `to` - The ending CSS styles (a key/value object) that will be applied across the animation via a CSS transition.
|
519
726
|
* * `addClass` - A space separated list of CSS classes that will be added to the element and spread across the animation.
|
@@ -527,63 +734,23 @@ var $$AnimateChildrenDirective = [function() {
|
|
527
734
|
* * `stagger` - A numeric time value representing the delay between successively animated elements
|
528
735
|
* ({@link ngAnimate#css-staggering-animations Click here to learn how CSS-based staggering works in ngAnimate.})
|
529
736
|
* * `staggerIndex` - The numeric index representing the stagger item (e.g. a value of 5 is equal to the sixth item in the stagger; therefore when a
|
530
|
-
*
|
531
|
-
* `applyClassesEarly` - Whether or not the classes being added or removed will be used when detecting the animation. This is set by `$animate` when enter/leave/move animations are fired to ensure that the CSS classes are resolved in time. (Note that this will prevent any transitions from
|
737
|
+
* `stagger` option value of `0.1` is used then there will be a stagger delay of `600ms`)
|
738
|
+
* * `applyClassesEarly` - Whether or not the classes being added or removed will be used when detecting the animation. This is set by `$animate` when enter/leave/move animations are fired to ensure that the CSS classes are resolved in time. (Note that this will prevent any transitions from occurring on the classes being added and removed.)
|
739
|
+
* * `cleanupStyles` - Whether or not the provided `from` and `to` styles will be removed once
|
740
|
+
* the animation is closed. This is useful for when the styles are used purely for the sake of
|
741
|
+
* the animation and do not have a lasting visual effect on the element (e.g. a collapse and open animation).
|
742
|
+
* By default this value is set to `false`.
|
532
743
|
*
|
533
744
|
* @return {object} an object with start and end methods and details about the animation.
|
534
745
|
*
|
535
746
|
* * `start` - The method to start the animation. This will return a `Promise` when called.
|
536
747
|
* * `end` - This method will cancel the animation and remove all applied CSS classes and styles.
|
537
748
|
*/
|
538
|
-
|
539
|
-
// Detect proper transitionend/animationend event names.
|
540
|
-
var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT;
|
541
|
-
|
542
|
-
// If unprefixed events are not supported but webkit-prefixed are, use the latter.
|
543
|
-
// Otherwise, just use W3C names, browsers not supporting them at all will just ignore them.
|
544
|
-
// Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend`
|
545
|
-
// but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`.
|
546
|
-
// Register both events in case `window.onanimationend` is not supported because of that,
|
547
|
-
// do the same for `transitionend` as Safari is likely to exhibit similar behavior.
|
548
|
-
// Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit
|
549
|
-
// therefore there is no reason to test anymore for other vendor prefixes:
|
550
|
-
// http://caniuse.com/#search=transition
|
551
|
-
if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) {
|
552
|
-
CSS_PREFIX = '-webkit-';
|
553
|
-
TRANSITION_PROP = 'WebkitTransition';
|
554
|
-
TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
|
555
|
-
} else {
|
556
|
-
TRANSITION_PROP = 'transition';
|
557
|
-
TRANSITIONEND_EVENT = 'transitionend';
|
558
|
-
}
|
559
|
-
|
560
|
-
if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) {
|
561
|
-
CSS_PREFIX = '-webkit-';
|
562
|
-
ANIMATION_PROP = 'WebkitAnimation';
|
563
|
-
ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';
|
564
|
-
} else {
|
565
|
-
ANIMATION_PROP = 'animation';
|
566
|
-
ANIMATIONEND_EVENT = 'animationend';
|
567
|
-
}
|
568
|
-
|
569
|
-
var DURATION_KEY = 'Duration';
|
570
|
-
var PROPERTY_KEY = 'Property';
|
571
|
-
var DELAY_KEY = 'Delay';
|
572
|
-
var TIMING_KEY = 'TimingFunction';
|
573
|
-
var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';
|
574
|
-
var ANIMATION_PLAYSTATE_KEY = 'PlayState';
|
575
|
-
var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;
|
576
|
-
var CLOSING_TIME_BUFFER = 1.5;
|
577
749
|
var ONE_SECOND = 1000;
|
578
750
|
var BASE_TEN = 10;
|
579
751
|
|
580
|
-
var
|
581
|
-
|
582
|
-
var ANIMATION_DELAY_PROP = ANIMATION_PROP + DELAY_KEY;
|
583
|
-
var ANIMATION_DURATION_PROP = ANIMATION_PROP + DURATION_KEY;
|
584
|
-
|
585
|
-
var TRANSITION_DELAY_PROP = TRANSITION_PROP + DELAY_KEY;
|
586
|
-
var TRANSITION_DURATION_PROP = TRANSITION_PROP + DURATION_KEY;
|
752
|
+
var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;
|
753
|
+
var CLOSING_TIME_BUFFER = 1.5;
|
587
754
|
|
588
755
|
var DETECT_CSS_PROPERTIES = {
|
589
756
|
transitionDuration: TRANSITION_DURATION_PROP,
|
@@ -601,6 +768,15 @@ var DETECT_STAGGER_CSS_PROPERTIES = {
|
|
601
768
|
animationDelay: ANIMATION_DELAY_PROP
|
602
769
|
};
|
603
770
|
|
771
|
+
function getCssKeyframeDurationStyle(duration) {
|
772
|
+
return [ANIMATION_DURATION_PROP, duration + 's'];
|
773
|
+
}
|
774
|
+
|
775
|
+
function getCssDelayStyle(delay, isKeyframeAnimation) {
|
776
|
+
var prop = isKeyframeAnimation ? ANIMATION_DELAY_PROP : TRANSITION_DELAY_PROP;
|
777
|
+
return [prop, delay + 's'];
|
778
|
+
}
|
779
|
+
|
604
780
|
function computeCssStyles($window, element, properties) {
|
605
781
|
var styles = Object.create(null);
|
606
782
|
var detectedStyles = $window.getComputedStyle(element) || {};
|
@@ -615,7 +791,7 @@ function computeCssStyles($window, element, properties) {
|
|
615
791
|
}
|
616
792
|
|
617
793
|
// by setting this to null in the event that the delay is not set or is set directly as 0
|
618
|
-
// then we can still allow for
|
794
|
+
// then we can still allow for negative values to be used later on and not mistake this
|
619
795
|
// value for being greater than any other negative value.
|
620
796
|
if (val === 0) {
|
621
797
|
val = null;
|
@@ -657,37 +833,6 @@ function getCssTransitionDurationStyle(duration, applyOnlyDuration) {
|
|
657
833
|
return [style, value];
|
658
834
|
}
|
659
835
|
|
660
|
-
function getCssKeyframeDurationStyle(duration) {
|
661
|
-
return [ANIMATION_DURATION_PROP, duration + 's'];
|
662
|
-
}
|
663
|
-
|
664
|
-
function getCssDelayStyle(delay, isKeyframeAnimation) {
|
665
|
-
var prop = isKeyframeAnimation ? ANIMATION_DELAY_PROP : TRANSITION_DELAY_PROP;
|
666
|
-
return [prop, delay + 's'];
|
667
|
-
}
|
668
|
-
|
669
|
-
function blockTransitions(node, duration) {
|
670
|
-
// we use a negative delay value since it performs blocking
|
671
|
-
// yet it doesn't kill any existing transitions running on the
|
672
|
-
// same element which makes this safe for class-based animations
|
673
|
-
var value = duration ? '-' + duration + 's' : '';
|
674
|
-
applyInlineStyle(node, [TRANSITION_DELAY_PROP, value]);
|
675
|
-
return [TRANSITION_DELAY_PROP, value];
|
676
|
-
}
|
677
|
-
|
678
|
-
function blockKeyframeAnimations(node, applyBlock) {
|
679
|
-
var value = applyBlock ? 'paused' : '';
|
680
|
-
var key = ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY;
|
681
|
-
applyInlineStyle(node, [key, value]);
|
682
|
-
return [key, value];
|
683
|
-
}
|
684
|
-
|
685
|
-
function applyInlineStyle(node, styleTuple) {
|
686
|
-
var prop = styleTuple[0];
|
687
|
-
var value = styleTuple[1];
|
688
|
-
node.style[prop] = value;
|
689
|
-
}
|
690
|
-
|
691
836
|
function createLocalCacheLookup() {
|
692
837
|
var cache = Object.create(null);
|
693
838
|
return {
|
@@ -715,14 +860,31 @@ function createLocalCacheLookup() {
|
|
715
860
|
};
|
716
861
|
}
|
717
862
|
|
863
|
+
// we do not reassign an already present style value since
|
864
|
+
// if we detect the style property value again we may be
|
865
|
+
// detecting styles that were added via the `from` styles.
|
866
|
+
// We make use of `isDefined` here since an empty string
|
867
|
+
// or null value (which is what getPropertyValue will return
|
868
|
+
// for a non-existing style) will still be marked as a valid
|
869
|
+
// value for the style (a falsy value implies that the style
|
870
|
+
// is to be removed at the end of the animation). If we had a simple
|
871
|
+
// "OR" statement then it would not be enough to catch that.
|
872
|
+
function registerRestorableStyles(backup, node, properties) {
|
873
|
+
forEach(properties, function(prop) {
|
874
|
+
backup[prop] = isDefined(backup[prop])
|
875
|
+
? backup[prop]
|
876
|
+
: node.style.getPropertyValue(prop);
|
877
|
+
});
|
878
|
+
}
|
879
|
+
|
718
880
|
var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
719
881
|
var gcsLookup = createLocalCacheLookup();
|
720
882
|
var gcsStaggerLookup = createLocalCacheLookup();
|
721
883
|
|
722
884
|
this.$get = ['$window', '$$jqLite', '$$AnimateRunner', '$timeout',
|
723
|
-
'
|
885
|
+
'$$forceReflow', '$sniffer', '$$rAFScheduler', '$$animateQueue',
|
724
886
|
function($window, $$jqLite, $$AnimateRunner, $timeout,
|
725
|
-
|
887
|
+
$$forceReflow, $sniffer, $$rAFScheduler, $$animateQueue) {
|
726
888
|
|
727
889
|
var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
|
728
890
|
|
@@ -745,7 +907,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
745
907
|
}
|
746
908
|
|
747
909
|
// we keep putting this in multiple times even though the value and the cacheKey are the same
|
748
|
-
// because we're keeping an
|
910
|
+
// because we're keeping an internal tally of how many duplicate animations are detected.
|
749
911
|
gcsLookup.put(cacheKey, timings);
|
750
912
|
return timings;
|
751
913
|
}
|
@@ -779,7 +941,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
779
941
|
return stagger || {};
|
780
942
|
}
|
781
943
|
|
782
|
-
var
|
944
|
+
var cancelLastRAFRequest;
|
783
945
|
var rafWaitQueue = [];
|
784
946
|
function waitUntilQuiet(callback) {
|
785
947
|
rafWaitQueue.push(callback);
|
@@ -787,27 +949,19 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
787
949
|
gcsLookup.flush();
|
788
950
|
gcsStaggerLookup.flush();
|
789
951
|
|
790
|
-
//
|
791
|
-
//
|
792
|
-
|
793
|
-
//ensure that the preparation animation is properly flushed so that
|
794
|
-
//the active state picks up from there. DO NOT REMOVE THIS LINE.
|
795
|
-
//DO NOT OPTIMIZE THIS LINE. THE MINIFIER WILL REMOVE IT OTHERWISE WHICH
|
796
|
-
//WILL RESULT IN AN UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND
|
797
|
-
//WILL TAKE YEARS AWAY FROM YOUR LIFE.
|
798
|
-
var width = bod.offsetWidth + 1;
|
952
|
+
// DO NOT REMOVE THIS LINE OR REFACTOR OUT THE `pageWidth` variable.
|
953
|
+
// PLEASE EXAMINE THE `$$forceReflow` service to understand why.
|
954
|
+
var pageWidth = $$forceReflow();
|
799
955
|
|
800
956
|
// we use a for loop to ensure that if the queue is changed
|
801
957
|
// during this looping then it will consider new requests
|
802
958
|
for (var i = 0; i < rafWaitQueue.length; i++) {
|
803
|
-
rafWaitQueue[i](
|
959
|
+
rafWaitQueue[i](pageWidth);
|
804
960
|
}
|
805
961
|
rafWaitQueue.length = 0;
|
806
962
|
});
|
807
963
|
}
|
808
964
|
|
809
|
-
return init;
|
810
|
-
|
811
965
|
function computeTimings(node, className, cacheKey) {
|
812
966
|
var timings = computeCachedCssStyles(node, className, cacheKey, DETECT_CSS_PROPERTIES);
|
813
967
|
var aD = timings.animationDelay;
|
@@ -822,9 +976,23 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
822
976
|
return timings;
|
823
977
|
}
|
824
978
|
|
825
|
-
function init(element,
|
979
|
+
return function init(element, initialOptions) {
|
980
|
+
// all of the animation functions should create
|
981
|
+
// a copy of the options data, however, if a
|
982
|
+
// parent service has already created a copy then
|
983
|
+
// we should stick to using that
|
984
|
+
var options = initialOptions || {};
|
985
|
+
if (!options.$$prepared) {
|
986
|
+
options = prepareAnimationOptions(copy(options));
|
987
|
+
}
|
988
|
+
|
989
|
+
var restoreStyles = {};
|
826
990
|
var node = getDomNode(element);
|
827
|
-
|
991
|
+
if (!node
|
992
|
+
|| !node.parentNode
|
993
|
+
|| !$$animateQueue.enabled()) {
|
994
|
+
return closeAndReturnNoopAnimator();
|
995
|
+
}
|
828
996
|
|
829
997
|
var temporaryStyles = [];
|
830
998
|
var classes = element.attr('class');
|
@@ -838,6 +1006,8 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
838
1006
|
var maxDelayTime;
|
839
1007
|
var maxDuration;
|
840
1008
|
var maxDurationTime;
|
1009
|
+
var startTime;
|
1010
|
+
var events = [];
|
841
1011
|
|
842
1012
|
if (options.duration === 0 || (!$sniffer.animations && !$sniffer.transitions)) {
|
843
1013
|
return closeAndReturnNoopAnimator();
|
@@ -852,20 +1022,20 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
852
1022
|
var addRemoveClassName = '';
|
853
1023
|
|
854
1024
|
if (isStructural) {
|
855
|
-
structuralClassName = pendClasses(method,
|
1025
|
+
structuralClassName = pendClasses(method, EVENT_CLASS_PREFIX, true);
|
856
1026
|
} else if (method) {
|
857
1027
|
structuralClassName = method;
|
858
1028
|
}
|
859
1029
|
|
860
1030
|
if (options.addClass) {
|
861
|
-
addRemoveClassName += pendClasses(options.addClass,
|
1031
|
+
addRemoveClassName += pendClasses(options.addClass, ADD_CLASS_SUFFIX);
|
862
1032
|
}
|
863
1033
|
|
864
1034
|
if (options.removeClass) {
|
865
1035
|
if (addRemoveClassName.length) {
|
866
1036
|
addRemoveClassName += ' ';
|
867
1037
|
}
|
868
|
-
addRemoveClassName += pendClasses(options.removeClass,
|
1038
|
+
addRemoveClassName += pendClasses(options.removeClass, REMOVE_CLASS_SUFFIX);
|
869
1039
|
}
|
870
1040
|
|
871
1041
|
// there may be a situation where a structural animation is combined together
|
@@ -876,17 +1046,20 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
876
1046
|
// there actually is a detected transition or keyframe animation
|
877
1047
|
if (options.applyClassesEarly && addRemoveClassName.length) {
|
878
1048
|
applyAnimationClasses(element, options);
|
879
|
-
addRemoveClassName = '';
|
880
1049
|
}
|
881
1050
|
|
882
|
-
var
|
883
|
-
var fullClassName = classes + ' ' +
|
884
|
-
var activeClasses = pendClasses(
|
1051
|
+
var preparationClasses = [structuralClassName, addRemoveClassName].join(' ').trim();
|
1052
|
+
var fullClassName = classes + ' ' + preparationClasses;
|
1053
|
+
var activeClasses = pendClasses(preparationClasses, ACTIVE_CLASS_SUFFIX);
|
885
1054
|
var hasToStyles = styles.to && Object.keys(styles.to).length > 0;
|
886
|
-
|
887
|
-
|
888
|
-
// no
|
889
|
-
|
1055
|
+
var containsKeyframeAnimation = (options.keyframeStyle || '').length > 0;
|
1056
|
+
|
1057
|
+
// there is no way we can trigger an animation if no styles and
|
1058
|
+
// no classes are being applied which would then trigger a transition,
|
1059
|
+
// unless there a is raw keyframe value that is applied to the element.
|
1060
|
+
if (!containsKeyframeAnimation
|
1061
|
+
&& !hasToStyles
|
1062
|
+
&& !preparationClasses) {
|
890
1063
|
return closeAndReturnNoopAnimator();
|
891
1064
|
}
|
892
1065
|
|
@@ -901,10 +1074,12 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
901
1074
|
};
|
902
1075
|
} else {
|
903
1076
|
cacheKey = gcsHashFn(node, fullClassName);
|
904
|
-
stagger = computeCachedCssStaggerStyles(node,
|
1077
|
+
stagger = computeCachedCssStaggerStyles(node, preparationClasses, cacheKey, DETECT_STAGGER_CSS_PROPERTIES);
|
905
1078
|
}
|
906
1079
|
|
907
|
-
|
1080
|
+
if (!options.$$skipPreparationClasses) {
|
1081
|
+
$$jqLite.addClass(element, preparationClasses);
|
1082
|
+
}
|
908
1083
|
|
909
1084
|
var applyOnlyDuration;
|
910
1085
|
|
@@ -943,7 +1118,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
943
1118
|
// transition delay to allow for the transition to naturally do it's thing. The beauty here is
|
944
1119
|
// that if there is no transition defined then nothing will happen and this will also allow
|
945
1120
|
// other transitions to be stacked on top of each other without any chopping them out.
|
946
|
-
if (isFirst) {
|
1121
|
+
if (isFirst && !options.skipBlocking) {
|
947
1122
|
blockTransitions(node, SAFE_FAST_FORWARD_DURATION_VALUE);
|
948
1123
|
}
|
949
1124
|
|
@@ -985,6 +1160,23 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
985
1160
|
return closeAndReturnNoopAnimator();
|
986
1161
|
}
|
987
1162
|
|
1163
|
+
if (options.delay != null) {
|
1164
|
+
var delayStyle;
|
1165
|
+
if (typeof options.delay !== "boolean") {
|
1166
|
+
delayStyle = parseFloat(options.delay);
|
1167
|
+
// number in options.delay means we have to recalculate the delay for the closing timeout
|
1168
|
+
maxDelay = Math.max(delayStyle, 0);
|
1169
|
+
}
|
1170
|
+
|
1171
|
+
if (flags.applyTransitionDelay) {
|
1172
|
+
temporaryStyles.push(getCssDelayStyle(delayStyle));
|
1173
|
+
}
|
1174
|
+
|
1175
|
+
if (flags.applyAnimationDelay) {
|
1176
|
+
temporaryStyles.push(getCssDelayStyle(delayStyle, true));
|
1177
|
+
}
|
1178
|
+
}
|
1179
|
+
|
988
1180
|
// we need to recalculate the delay value since we used a pre-emptive negative
|
989
1181
|
// delay value and the delay value is required for the final event checking. This
|
990
1182
|
// property will ensure that this will happen after the RAF phase has passed.
|
@@ -1001,12 +1193,18 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
1001
1193
|
stagger.animationDuration === 0;
|
1002
1194
|
}
|
1003
1195
|
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1196
|
+
if (options.from) {
|
1197
|
+
if (options.cleanupStyles) {
|
1198
|
+
registerRestorableStyles(restoreStyles, node, Object.keys(options.from));
|
1199
|
+
}
|
1200
|
+
applyAnimationFromStyles(element, options);
|
1007
1201
|
}
|
1008
1202
|
|
1009
|
-
|
1203
|
+
if (flags.blockTransition || flags.blockKeyframeAnimation) {
|
1204
|
+
applyBlocking(maxDuration);
|
1205
|
+
} else if (!options.skipBlocking) {
|
1206
|
+
blockTransitions(node, false);
|
1207
|
+
}
|
1010
1208
|
|
1011
1209
|
// TODO(matsko): for 1.5 change this code to have an animator object for better debugging
|
1012
1210
|
return {
|
@@ -1049,7 +1247,9 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
1049
1247
|
animationClosed = true;
|
1050
1248
|
animationPaused = false;
|
1051
1249
|
|
1052
|
-
|
1250
|
+
if (!options.$$skipPreparationClasses) {
|
1251
|
+
$$jqLite.removeClass(element, preparationClasses);
|
1252
|
+
}
|
1053
1253
|
$$jqLite.removeClass(element, activeClasses);
|
1054
1254
|
|
1055
1255
|
blockKeyframeAnimations(node, false);
|
@@ -1065,6 +1265,13 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
1065
1265
|
applyAnimationClasses(element, options);
|
1066
1266
|
applyAnimationStyles(element, options);
|
1067
1267
|
|
1268
|
+
if (Object.keys(restoreStyles).length) {
|
1269
|
+
forEach(restoreStyles, function(value, prop) {
|
1270
|
+
value ? node.style.setProperty(prop, value)
|
1271
|
+
: node.style.removeProperty(prop);
|
1272
|
+
});
|
1273
|
+
}
|
1274
|
+
|
1068
1275
|
// the reason why we have this option is to allow a synchronous closing callback
|
1069
1276
|
// that is fired as SOON as the animation ends (when the CSS is removed) or if
|
1070
1277
|
// the animation never takes off at all. A good example is a leave animation since
|
@@ -1074,6 +1281,18 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
1074
1281
|
options.onDone();
|
1075
1282
|
}
|
1076
1283
|
|
1284
|
+
if (events && events.length) {
|
1285
|
+
// Remove the transitionend / animationend listener(s)
|
1286
|
+
element.off(events.join(' '), onAnimationProgress);
|
1287
|
+
}
|
1288
|
+
|
1289
|
+
//Cancel the fallback closing timeout and remove the timer data
|
1290
|
+
var animationTimerData = element.data(ANIMATE_TIMER_KEY);
|
1291
|
+
if (animationTimerData) {
|
1292
|
+
$timeout.cancel(animationTimerData[0].timer);
|
1293
|
+
element.removeData(ANIMATE_TIMER_KEY);
|
1294
|
+
}
|
1295
|
+
|
1077
1296
|
// if the preparation function fails then the promise is not setup
|
1078
1297
|
if (runner) {
|
1079
1298
|
runner.complete(!rejected);
|
@@ -1096,6 +1315,8 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
1096
1315
|
cancel: cancelFn
|
1097
1316
|
});
|
1098
1317
|
|
1318
|
+
// should flush the cache animation
|
1319
|
+
waitUntilQuiet(noop);
|
1099
1320
|
close();
|
1100
1321
|
|
1101
1322
|
return {
|
@@ -1107,10 +1328,39 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
1107
1328
|
};
|
1108
1329
|
}
|
1109
1330
|
|
1331
|
+
function onAnimationProgress(event) {
|
1332
|
+
event.stopPropagation();
|
1333
|
+
var ev = event.originalEvent || event;
|
1334
|
+
|
1335
|
+
// we now always use `Date.now()` due to the recent changes with
|
1336
|
+
// event.timeStamp in Firefox, Webkit and Chrome (see #13494 for more info)
|
1337
|
+
var timeStamp = ev.$manualTimeStamp || Date.now();
|
1338
|
+
|
1339
|
+
/* Firefox (or possibly just Gecko) likes to not round values up
|
1340
|
+
* when a ms measurement is used for the animation */
|
1341
|
+
var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES));
|
1342
|
+
|
1343
|
+
/* $manualTimeStamp is a mocked timeStamp value which is set
|
1344
|
+
* within browserTrigger(). This is only here so that tests can
|
1345
|
+
* mock animations properly. Real events fallback to event.timeStamp,
|
1346
|
+
* or, if they don't, then a timeStamp is automatically created for them.
|
1347
|
+
* We're checking to see if the timeStamp surpasses the expected delay,
|
1348
|
+
* but we're using elapsedTime instead of the timeStamp on the 2nd
|
1349
|
+
* pre-condition since animationPauseds sometimes close off early */
|
1350
|
+
if (Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) {
|
1351
|
+
// we set this flag to ensure that if the transition is paused then, when resumed,
|
1352
|
+
// the animation will automatically close itself since transitions cannot be paused.
|
1353
|
+
animationCompleted = true;
|
1354
|
+
close();
|
1355
|
+
}
|
1356
|
+
}
|
1357
|
+
|
1110
1358
|
function start() {
|
1111
1359
|
if (animationClosed) return;
|
1112
|
-
|
1113
|
-
|
1360
|
+
if (!node.parentNode) {
|
1361
|
+
close();
|
1362
|
+
return;
|
1363
|
+
}
|
1114
1364
|
|
1115
1365
|
// even though we only pause keyframe animations here the pause flag
|
1116
1366
|
// will still happen when transitions are used. Only the transition will
|
@@ -1131,9 +1381,9 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
1131
1381
|
}
|
1132
1382
|
};
|
1133
1383
|
|
1134
|
-
// checking the stagger duration prevents an
|
1384
|
+
// checking the stagger duration prevents an accidentally cascade of the CSS delay style
|
1135
1385
|
// being inherited from the parent. If the transition duration is zero then we can safely
|
1136
|
-
// rely that the delay value is an
|
1386
|
+
// rely that the delay value is an intentional stagger delay style.
|
1137
1387
|
var maxStagger = itemIndex > 0
|
1138
1388
|
&& ((timings.transitionDuration && stagger.transitionDuration === 0) ||
|
1139
1389
|
(timings.animationDuration && stagger.animationDuration === 0))
|
@@ -1172,7 +1422,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
1172
1422
|
$$jqLite.addClass(element, activeClasses);
|
1173
1423
|
|
1174
1424
|
if (flags.recalculateTimingStyles) {
|
1175
|
-
fullClassName = node.className + ' ' +
|
1425
|
+
fullClassName = node.className + ' ' + preparationClasses;
|
1176
1426
|
cacheKey = gcsHashFn(node, fullClassName);
|
1177
1427
|
|
1178
1428
|
timings = computeTimings(node, fullClassName, cacheKey);
|
@@ -1189,27 +1439,16 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
1189
1439
|
flags.hasAnimations = timings.animationDuration > 0;
|
1190
1440
|
}
|
1191
1441
|
|
1192
|
-
if (flags.
|
1442
|
+
if (flags.applyAnimationDelay) {
|
1193
1443
|
relativeDelay = typeof options.delay !== "boolean" && truthyTimingValue(options.delay)
|
1194
1444
|
? parseFloat(options.delay)
|
1195
1445
|
: relativeDelay;
|
1196
1446
|
|
1197
1447
|
maxDelay = Math.max(relativeDelay, 0);
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
delayStyle = getCssDelayStyle(relativeDelay);
|
1203
|
-
temporaryStyles.push(delayStyle);
|
1204
|
-
node.style[delayStyle[0]] = delayStyle[1];
|
1205
|
-
}
|
1206
|
-
|
1207
|
-
if (flags.applyAnimationDelay) {
|
1208
|
-
timings.animationDelay = relativeDelay;
|
1209
|
-
delayStyle = getCssDelayStyle(relativeDelay, true);
|
1210
|
-
temporaryStyles.push(delayStyle);
|
1211
|
-
node.style[delayStyle[0]] = delayStyle[1];
|
1212
|
-
}
|
1448
|
+
timings.animationDelay = relativeDelay;
|
1449
|
+
delayStyle = getCssDelayStyle(relativeDelay, true);
|
1450
|
+
temporaryStyles.push(delayStyle);
|
1451
|
+
node.style[delayStyle[0]] = delayStyle[1];
|
1213
1452
|
}
|
1214
1453
|
|
1215
1454
|
maxDelayTime = maxDelay * ONE_SECOND;
|
@@ -1238,44 +1477,58 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
|
1238
1477
|
}
|
1239
1478
|
|
1240
1479
|
startTime = Date.now();
|
1241
|
-
|
1242
|
-
|
1480
|
+
var timerTime = maxDelayTime + CLOSING_TIME_BUFFER * maxDurationTime;
|
1481
|
+
var endTime = startTime + timerTime;
|
1482
|
+
|
1483
|
+
var animationsData = element.data(ANIMATE_TIMER_KEY) || [];
|
1484
|
+
var setupFallbackTimer = true;
|
1485
|
+
if (animationsData.length) {
|
1486
|
+
var currentTimerData = animationsData[0];
|
1487
|
+
setupFallbackTimer = endTime > currentTimerData.expectedEndTime;
|
1488
|
+
if (setupFallbackTimer) {
|
1489
|
+
$timeout.cancel(currentTimerData.timer);
|
1490
|
+
} else {
|
1491
|
+
animationsData.push(close);
|
1492
|
+
}
|
1493
|
+
}
|
1243
1494
|
|
1244
|
-
|
1245
|
-
|
1495
|
+
if (setupFallbackTimer) {
|
1496
|
+
var timer = $timeout(onAnimationExpired, timerTime, false);
|
1497
|
+
animationsData[0] = {
|
1498
|
+
timer: timer,
|
1499
|
+
expectedEndTime: endTime
|
1500
|
+
};
|
1501
|
+
animationsData.push(close);
|
1502
|
+
element.data(ANIMATE_TIMER_KEY, animationsData);
|
1503
|
+
}
|
1246
1504
|
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1505
|
+
if (events.length) {
|
1506
|
+
element.on(events.join(' '), onAnimationProgress);
|
1507
|
+
}
|
1508
|
+
|
1509
|
+
if (options.to) {
|
1510
|
+
if (options.cleanupStyles) {
|
1511
|
+
registerRestorableStyles(restoreStyles, node, Object.keys(options.to));
|
1512
|
+
}
|
1513
|
+
applyAnimationToStyles(element, options);
|
1514
|
+
}
|
1252
1515
|
}
|
1253
1516
|
|
1254
|
-
function
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
* mock animations properly. Real events fallback to event.timeStamp,
|
1266
|
-
* or, if they don't, then a timeStamp is automatically created for them.
|
1267
|
-
* We're checking to see if the timeStamp surpasses the expected delay,
|
1268
|
-
* but we're using elapsedTime instead of the timeStamp on the 2nd
|
1269
|
-
* pre-condition since animations sometimes close off early */
|
1270
|
-
if (Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) {
|
1271
|
-
// we set this flag to ensure that if the transition is paused then, when resumed,
|
1272
|
-
// the animation will automatically close itself since transitions cannot be paused.
|
1273
|
-
animationCompleted = true;
|
1274
|
-
close();
|
1517
|
+
function onAnimationExpired() {
|
1518
|
+
var animationsData = element.data(ANIMATE_TIMER_KEY);
|
1519
|
+
|
1520
|
+
// this will be false in the event that the element was
|
1521
|
+
// removed from the DOM (via a leave animation or something
|
1522
|
+
// similar)
|
1523
|
+
if (animationsData) {
|
1524
|
+
for (var i = 1; i < animationsData.length; i++) {
|
1525
|
+
animationsData[i]();
|
1526
|
+
}
|
1527
|
+
element.removeData(ANIMATE_TIMER_KEY);
|
1275
1528
|
}
|
1276
1529
|
}
|
1277
1530
|
}
|
1278
|
-
}
|
1531
|
+
};
|
1279
1532
|
}];
|
1280
1533
|
}];
|
1281
1534
|
|
@@ -1288,16 +1541,27 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro
|
|
1288
1541
|
var NG_OUT_ANCHOR_CLASS_NAME = 'ng-anchor-out';
|
1289
1542
|
var NG_IN_ANCHOR_CLASS_NAME = 'ng-anchor-in';
|
1290
1543
|
|
1291
|
-
|
1292
|
-
|
1544
|
+
function isDocumentFragment(node) {
|
1545
|
+
return node.parentNode && node.parentNode.nodeType === 11;
|
1546
|
+
}
|
1547
|
+
|
1548
|
+
this.$get = ['$animateCss', '$rootScope', '$$AnimateRunner', '$rootElement', '$sniffer', '$$jqLite', '$document',
|
1549
|
+
function($animateCss, $rootScope, $$AnimateRunner, $rootElement, $sniffer, $$jqLite, $document) {
|
1293
1550
|
|
1294
1551
|
// only browsers that support these properties can render animations
|
1295
1552
|
if (!$sniffer.animations && !$sniffer.transitions) return noop;
|
1296
1553
|
|
1297
|
-
var bodyNode =
|
1554
|
+
var bodyNode = $document[0].body;
|
1298
1555
|
var rootNode = getDomNode($rootElement);
|
1299
1556
|
|
1300
|
-
var rootBodyElement = jqLite(
|
1557
|
+
var rootBodyElement = jqLite(
|
1558
|
+
// this is to avoid using something that exists outside of the body
|
1559
|
+
// we also special case the doc fragment case because our unit test code
|
1560
|
+
// appends the $rootElement to the body after the app has been bootstrapped
|
1561
|
+
isDocumentFragment(rootNode) || bodyNode.contains(rootNode) ? rootNode : bodyNode
|
1562
|
+
);
|
1563
|
+
|
1564
|
+
var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
|
1301
1565
|
|
1302
1566
|
return function initDriverFn(animationDetails) {
|
1303
1567
|
return animationDetails.from && animationDetails.to
|
@@ -1392,7 +1656,7 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro
|
|
1392
1656
|
var coords = getDomNode(anchor).getBoundingClientRect();
|
1393
1657
|
|
1394
1658
|
// we iterate directly since safari messes up and doesn't return
|
1395
|
-
// all the keys for the
|
1659
|
+
// all the keys for the coords object when iterated
|
1396
1660
|
forEach(['width','height','top','left'], function(key) {
|
1397
1661
|
var value = coords[key];
|
1398
1662
|
switch (key) {
|
@@ -1449,8 +1713,8 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro
|
|
1449
1713
|
}
|
1450
1714
|
|
1451
1715
|
function prepareFromToAnchorAnimation(from, to, classes, anchors) {
|
1452
|
-
var fromAnimation = prepareRegularAnimation(from);
|
1453
|
-
var toAnimation = prepareRegularAnimation(to);
|
1716
|
+
var fromAnimation = prepareRegularAnimation(from, noop);
|
1717
|
+
var toAnimation = prepareRegularAnimation(to, noop);
|
1454
1718
|
|
1455
1719
|
var anchorAnimations = [];
|
1456
1720
|
forEach(anchors, function(anchor) {
|
@@ -1506,19 +1770,23 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro
|
|
1506
1770
|
var options = animationDetails.options || {};
|
1507
1771
|
|
1508
1772
|
if (animationDetails.structural) {
|
1509
|
-
|
1510
|
-
|
1511
|
-
options.
|
1773
|
+
options.event = animationDetails.event;
|
1774
|
+
options.structural = true;
|
1775
|
+
options.applyClassesEarly = true;
|
1512
1776
|
|
1513
1777
|
// we special case the leave animation since we want to ensure that
|
1514
1778
|
// the element is removed as soon as the animation is over. Otherwise
|
1515
1779
|
// a flicker might appear or the element may not be removed at all
|
1516
|
-
|
1517
|
-
if (options.event === 'leave') {
|
1780
|
+
if (animationDetails.event === 'leave') {
|
1518
1781
|
options.onDone = options.domOperation;
|
1519
1782
|
}
|
1520
|
-
}
|
1521
|
-
|
1783
|
+
}
|
1784
|
+
|
1785
|
+
// We assign the preparationClasses as the actual animation event since
|
1786
|
+
// the internals of $animateCss will just suffix the event token values
|
1787
|
+
// with `-active` to trigger the animation.
|
1788
|
+
if (options.preparationClasses) {
|
1789
|
+
options.event = concatWithSpace(options.event, options.preparationClasses);
|
1522
1790
|
}
|
1523
1791
|
|
1524
1792
|
var animator = $animateCss(element, options);
|
@@ -1537,12 +1805,14 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro
|
|
1537
1805
|
// by the time...
|
1538
1806
|
|
1539
1807
|
var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) {
|
1540
|
-
this.$get = ['$injector', '$$AnimateRunner', '$$
|
1541
|
-
function($injector, $$AnimateRunner, $$
|
1808
|
+
this.$get = ['$injector', '$$AnimateRunner', '$$jqLite',
|
1809
|
+
function($injector, $$AnimateRunner, $$jqLite) {
|
1542
1810
|
|
1543
1811
|
var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
|
1544
1812
|
// $animateJs(element, 'enter');
|
1545
1813
|
return function(element, event, classes, options) {
|
1814
|
+
var animationClosed = false;
|
1815
|
+
|
1546
1816
|
// the `classes` argument is optional and if it is not used
|
1547
1817
|
// then the classes will be resolved from the element's className
|
1548
1818
|
// property as well as options.addClass/options.removeClass.
|
@@ -1595,8 +1865,32 @@ var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) {
|
|
1595
1865
|
applyAnimationClasses(element, options);
|
1596
1866
|
}
|
1597
1867
|
|
1868
|
+
function close() {
|
1869
|
+
animationClosed = true;
|
1870
|
+
applyOptions();
|
1871
|
+
applyAnimationStyles(element, options);
|
1872
|
+
}
|
1873
|
+
|
1874
|
+
var runner;
|
1875
|
+
|
1598
1876
|
return {
|
1877
|
+
$$willAnimate: true,
|
1878
|
+
end: function() {
|
1879
|
+
if (runner) {
|
1880
|
+
runner.end();
|
1881
|
+
} else {
|
1882
|
+
close();
|
1883
|
+
runner = new $$AnimateRunner();
|
1884
|
+
runner.complete(true);
|
1885
|
+
}
|
1886
|
+
return runner;
|
1887
|
+
},
|
1599
1888
|
start: function() {
|
1889
|
+
if (runner) {
|
1890
|
+
return runner;
|
1891
|
+
}
|
1892
|
+
|
1893
|
+
runner = new $$AnimateRunner();
|
1600
1894
|
var closeActiveAnimations;
|
1601
1895
|
var chain = [];
|
1602
1896
|
|
@@ -1621,8 +1915,7 @@ var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) {
|
|
1621
1915
|
});
|
1622
1916
|
}
|
1623
1917
|
|
1624
|
-
|
1625
|
-
var runner = new $$AnimateRunner({
|
1918
|
+
runner.setHost({
|
1626
1919
|
end: function() {
|
1627
1920
|
endAnimations();
|
1628
1921
|
},
|
@@ -1635,9 +1928,7 @@ var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) {
|
|
1635
1928
|
return runner;
|
1636
1929
|
|
1637
1930
|
function onComplete(success) {
|
1638
|
-
|
1639
|
-
applyOptions();
|
1640
|
-
applyAnimationStyles(element, options);
|
1931
|
+
close(success);
|
1641
1932
|
runner.complete(success);
|
1642
1933
|
}
|
1643
1934
|
|
@@ -1857,6 +2148,7 @@ var NG_ANIMATE_PIN_DATA = '$ngAnimatePin';
|
|
1857
2148
|
var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
1858
2149
|
var PRE_DIGEST_STATE = 1;
|
1859
2150
|
var RUNNING_STATE = 2;
|
2151
|
+
var ONE_SPACE = ' ';
|
1860
2152
|
|
1861
2153
|
var rules = this.rules = {
|
1862
2154
|
skip: [],
|
@@ -1864,28 +2156,50 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
1864
2156
|
join: []
|
1865
2157
|
};
|
1866
2158
|
|
2159
|
+
function makeTruthyCssClassMap(classString) {
|
2160
|
+
if (!classString) {
|
2161
|
+
return null;
|
2162
|
+
}
|
2163
|
+
|
2164
|
+
var keys = classString.split(ONE_SPACE);
|
2165
|
+
var map = Object.create(null);
|
2166
|
+
|
2167
|
+
forEach(keys, function(key) {
|
2168
|
+
map[key] = true;
|
2169
|
+
});
|
2170
|
+
return map;
|
2171
|
+
}
|
2172
|
+
|
2173
|
+
function hasMatchingClasses(newClassString, currentClassString) {
|
2174
|
+
if (newClassString && currentClassString) {
|
2175
|
+
var currentClassMap = makeTruthyCssClassMap(currentClassString);
|
2176
|
+
return newClassString.split(ONE_SPACE).some(function(className) {
|
2177
|
+
return currentClassMap[className];
|
2178
|
+
});
|
2179
|
+
}
|
2180
|
+
}
|
2181
|
+
|
1867
2182
|
function isAllowed(ruleType, element, currentAnimation, previousAnimation) {
|
1868
2183
|
return rules[ruleType].some(function(fn) {
|
1869
2184
|
return fn(element, currentAnimation, previousAnimation);
|
1870
2185
|
});
|
1871
2186
|
}
|
1872
2187
|
|
1873
|
-
function hasAnimationClasses(
|
1874
|
-
|
1875
|
-
var
|
1876
|
-
var b = (options.removeClass || '').length > 0;
|
2188
|
+
function hasAnimationClasses(animation, and) {
|
2189
|
+
var a = (animation.addClass || '').length > 0;
|
2190
|
+
var b = (animation.removeClass || '').length > 0;
|
1877
2191
|
return and ? a && b : a || b;
|
1878
2192
|
}
|
1879
2193
|
|
1880
2194
|
rules.join.push(function(element, newAnimation, currentAnimation) {
|
1881
2195
|
// if the new animation is class-based then we can just tack that on
|
1882
|
-
return !newAnimation.structural && hasAnimationClasses(newAnimation
|
2196
|
+
return !newAnimation.structural && hasAnimationClasses(newAnimation);
|
1883
2197
|
});
|
1884
2198
|
|
1885
2199
|
rules.skip.push(function(element, newAnimation, currentAnimation) {
|
1886
2200
|
// there is no need to animate anything if no classes are being added and
|
1887
2201
|
// there is no structural animation that will be triggered
|
1888
|
-
return !newAnimation.structural && !hasAnimationClasses(newAnimation
|
2202
|
+
return !newAnimation.structural && !hasAnimationClasses(newAnimation);
|
1889
2203
|
});
|
1890
2204
|
|
1891
2205
|
rules.skip.push(function(element, newAnimation, currentAnimation) {
|
@@ -1895,8 +2209,8 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
1895
2209
|
});
|
1896
2210
|
|
1897
2211
|
rules.skip.push(function(element, newAnimation, currentAnimation) {
|
1898
|
-
// if there is
|
1899
|
-
return currentAnimation.structural && !newAnimation.structural;
|
2212
|
+
// if there is an ongoing current animation then don't even bother running the class-based animation
|
2213
|
+
return currentAnimation.structural && currentAnimation.state === RUNNING_STATE && !newAnimation.structural;
|
1900
2214
|
});
|
1901
2215
|
|
1902
2216
|
rules.cancel.push(function(element, newAnimation, currentAnimation) {
|
@@ -1911,23 +2225,51 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
1911
2225
|
});
|
1912
2226
|
|
1913
2227
|
rules.cancel.push(function(element, newAnimation, currentAnimation) {
|
1914
|
-
|
1915
|
-
|
2228
|
+
// cancel the animation if classes added / removed in both animation cancel each other out,
|
2229
|
+
// but only if the current animation isn't structural
|
2230
|
+
|
2231
|
+
if (currentAnimation.structural) return false;
|
1916
2232
|
|
1917
|
-
|
1918
|
-
|
2233
|
+
var nA = newAnimation.addClass;
|
2234
|
+
var nR = newAnimation.removeClass;
|
2235
|
+
var cA = currentAnimation.addClass;
|
2236
|
+
var cR = currentAnimation.removeClass;
|
2237
|
+
|
2238
|
+
// early detection to save the global CPU shortage :)
|
2239
|
+
if ((isUndefined(nA) && isUndefined(nR)) || (isUndefined(cA) && isUndefined(cR))) {
|
2240
|
+
return false;
|
2241
|
+
}
|
2242
|
+
|
2243
|
+
return hasMatchingClasses(nA, cR) || hasMatchingClasses(nR, cA);
|
1919
2244
|
});
|
1920
2245
|
|
1921
2246
|
this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$HashMap',
|
1922
|
-
'$$animation', '$$AnimateRunner', '$templateRequest', '$$jqLite',
|
2247
|
+
'$$animation', '$$AnimateRunner', '$templateRequest', '$$jqLite', '$$forceReflow',
|
1923
2248
|
function($$rAF, $rootScope, $rootElement, $document, $$HashMap,
|
1924
|
-
$$animation, $$AnimateRunner, $templateRequest, $$jqLite) {
|
2249
|
+
$$animation, $$AnimateRunner, $templateRequest, $$jqLite, $$forceReflow) {
|
1925
2250
|
|
1926
2251
|
var activeAnimationsLookup = new $$HashMap();
|
1927
2252
|
var disabledElementsLookup = new $$HashMap();
|
1928
|
-
|
1929
2253
|
var animationsEnabled = null;
|
1930
2254
|
|
2255
|
+
function postDigestTaskFactory() {
|
2256
|
+
var postDigestCalled = false;
|
2257
|
+
return function(fn) {
|
2258
|
+
// we only issue a call to postDigest before
|
2259
|
+
// it has first passed. This prevents any callbacks
|
2260
|
+
// from not firing once the animation has completed
|
2261
|
+
// since it will be out of the digest cycle.
|
2262
|
+
if (postDigestCalled) {
|
2263
|
+
fn();
|
2264
|
+
} else {
|
2265
|
+
$rootScope.$$postDigest(function() {
|
2266
|
+
postDigestCalled = true;
|
2267
|
+
fn();
|
2268
|
+
});
|
2269
|
+
}
|
2270
|
+
};
|
2271
|
+
}
|
2272
|
+
|
1931
2273
|
// Wait until all directive and route-related templates are downloaded and
|
1932
2274
|
// compiled. The $templateRequest.totalPendingRequests variable keeps track of
|
1933
2275
|
// all of the remote templates being currently downloaded. If there are no
|
@@ -1957,8 +2299,6 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
1957
2299
|
}
|
1958
2300
|
);
|
1959
2301
|
|
1960
|
-
var bodyElement = jqLite($document[0].body);
|
1961
|
-
|
1962
2302
|
var callbackRegistry = {};
|
1963
2303
|
|
1964
2304
|
// remember that the classNameFilter is set during the provider/config
|
@@ -1972,18 +2312,28 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
1972
2312
|
|
1973
2313
|
var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
|
1974
2314
|
|
1975
|
-
function
|
1976
|
-
return
|
2315
|
+
function normalizeAnimationDetails(element, animation) {
|
2316
|
+
return mergeAnimationDetails(element, animation, {});
|
1977
2317
|
}
|
1978
2318
|
|
1979
|
-
|
2319
|
+
// IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
|
2320
|
+
var contains = Node.prototype.contains || function(arg) {
|
2321
|
+
// jshint bitwise: false
|
2322
|
+
return this === arg || !!(this.compareDocumentPosition(arg) & 16);
|
2323
|
+
// jshint bitwise: true
|
2324
|
+
};
|
2325
|
+
|
2326
|
+
function findCallbacks(parent, element, event) {
|
1980
2327
|
var targetNode = getDomNode(element);
|
2328
|
+
var targetParentNode = getDomNode(parent);
|
1981
2329
|
|
1982
2330
|
var matches = [];
|
1983
2331
|
var entries = callbackRegistry[event];
|
1984
2332
|
if (entries) {
|
1985
2333
|
forEach(entries, function(entry) {
|
1986
|
-
if (entry.node
|
2334
|
+
if (contains.call(entry.node, targetNode)) {
|
2335
|
+
matches.push(entry.callback);
|
2336
|
+
} else if (event === 'leave' && contains.call(entry.node, targetParentNode)) {
|
1987
2337
|
matches.push(entry.callback);
|
1988
2338
|
}
|
1989
2339
|
});
|
@@ -1992,15 +2342,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
1992
2342
|
return matches;
|
1993
2343
|
}
|
1994
2344
|
|
1995
|
-
|
1996
|
-
$$rAF(function() {
|
1997
|
-
forEach(findCallbacks(element, event), function(callback) {
|
1998
|
-
callback(element, phase, data);
|
1999
|
-
});
|
2000
|
-
});
|
2001
|
-
}
|
2002
|
-
|
2003
|
-
return {
|
2345
|
+
var $animate = {
|
2004
2346
|
on: function(event, container, callback) {
|
2005
2347
|
var node = extractElementNode(container);
|
2006
2348
|
callbackRegistry[event] = callbackRegistry[event] || [];
|
@@ -2008,6 +2350,11 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2008
2350
|
node: node,
|
2009
2351
|
callback: callback
|
2010
2352
|
});
|
2353
|
+
|
2354
|
+
// Remove the callback when the element is removed from the DOM
|
2355
|
+
jqLite(container).on('$destroy', function() {
|
2356
|
+
$animate.off(event, container, callback);
|
2357
|
+
});
|
2011
2358
|
},
|
2012
2359
|
|
2013
2360
|
off: function(event, container, callback) {
|
@@ -2066,12 +2413,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2066
2413
|
bool = !recordExists;
|
2067
2414
|
} else {
|
2068
2415
|
// (element, bool) - Element setter
|
2069
|
-
|
2070
|
-
if (!bool) {
|
2071
|
-
disabledElementsLookup.put(node, true);
|
2072
|
-
} else if (recordExists) {
|
2073
|
-
disabledElementsLookup.remove(node);
|
2074
|
-
}
|
2416
|
+
disabledElementsLookup.put(node, !bool);
|
2075
2417
|
}
|
2076
2418
|
}
|
2077
2419
|
}
|
@@ -2080,7 +2422,14 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2080
2422
|
}
|
2081
2423
|
};
|
2082
2424
|
|
2083
|
-
|
2425
|
+
return $animate;
|
2426
|
+
|
2427
|
+
function queueAnimation(element, event, initialOptions) {
|
2428
|
+
// we always make a copy of the options since
|
2429
|
+
// there should never be any side effects on
|
2430
|
+
// the input data when running `$animateCss`.
|
2431
|
+
var options = copy(initialOptions);
|
2432
|
+
|
2084
2433
|
var node, parent;
|
2085
2434
|
element = stripCommentsFromElement(element);
|
2086
2435
|
if (element) {
|
@@ -2094,22 +2443,25 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2094
2443
|
// These methods will become available after the digest has passed
|
2095
2444
|
var runner = new $$AnimateRunner();
|
2096
2445
|
|
2097
|
-
//
|
2098
|
-
|
2099
|
-
// happens then there is no way we can perform an animation
|
2100
|
-
if (!node) {
|
2101
|
-
close();
|
2102
|
-
return runner;
|
2103
|
-
}
|
2446
|
+
// this is used to trigger callbacks in postDigest mode
|
2447
|
+
var runInNextPostDigestOrNow = postDigestTaskFactory();
|
2104
2448
|
|
2105
2449
|
if (isArray(options.addClass)) {
|
2106
2450
|
options.addClass = options.addClass.join(' ');
|
2107
2451
|
}
|
2108
2452
|
|
2453
|
+
if (options.addClass && !isString(options.addClass)) {
|
2454
|
+
options.addClass = null;
|
2455
|
+
}
|
2456
|
+
|
2109
2457
|
if (isArray(options.removeClass)) {
|
2110
2458
|
options.removeClass = options.removeClass.join(' ');
|
2111
2459
|
}
|
2112
2460
|
|
2461
|
+
if (options.removeClass && !isString(options.removeClass)) {
|
2462
|
+
options.removeClass = null;
|
2463
|
+
}
|
2464
|
+
|
2113
2465
|
if (options.from && !isObject(options.from)) {
|
2114
2466
|
options.from = null;
|
2115
2467
|
}
|
@@ -2118,6 +2470,14 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2118
2470
|
options.to = null;
|
2119
2471
|
}
|
2120
2472
|
|
2473
|
+
// there are situations where a directive issues an animation for
|
2474
|
+
// a jqLite wrapper that contains only comment nodes... If this
|
2475
|
+
// happens then there is no way we can perform an animation
|
2476
|
+
if (!node) {
|
2477
|
+
close();
|
2478
|
+
return runner;
|
2479
|
+
}
|
2480
|
+
|
2121
2481
|
var className = [node.className, options.addClass, options.removeClass].join(' ');
|
2122
2482
|
if (!isAnimatableClassName(className)) {
|
2123
2483
|
close();
|
@@ -2129,7 +2489,9 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2129
2489
|
// this is a hard disable of all animations for the application or on
|
2130
2490
|
// the element itself, therefore there is no need to continue further
|
2131
2491
|
// past this point if not enabled
|
2132
|
-
|
2492
|
+
// Animations are also disabled if the document is currently hidden (page is not visible
|
2493
|
+
// to the user), because browsers slow down or do not flush calls to requestAnimationFrame
|
2494
|
+
var skipAnimations = !animationsEnabled || $document[0].hidden || disabledElementsLookup.get(node);
|
2133
2495
|
var existingAnimation = (!skipAnimations && activeAnimationsLookup.get(node)) || {};
|
2134
2496
|
var hasExistingAnimation = !!existingAnimation.state;
|
2135
2497
|
|
@@ -2152,6 +2514,8 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2152
2514
|
structural: isStructural,
|
2153
2515
|
element: element,
|
2154
2516
|
event: event,
|
2517
|
+
addClass: options.addClass,
|
2518
|
+
removeClass: options.removeClass,
|
2155
2519
|
close: close,
|
2156
2520
|
options: options,
|
2157
2521
|
runner: runner
|
@@ -2164,11 +2528,10 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2164
2528
|
close();
|
2165
2529
|
return runner;
|
2166
2530
|
} else {
|
2167
|
-
|
2531
|
+
mergeAnimationDetails(element, existingAnimation, newAnimation);
|
2168
2532
|
return existingAnimation.runner;
|
2169
2533
|
}
|
2170
2534
|
}
|
2171
|
-
|
2172
2535
|
var cancelAnimationFlag = isAllowed('cancel', element, newAnimation, existingAnimation);
|
2173
2536
|
if (cancelAnimationFlag) {
|
2174
2537
|
if (existingAnimation.state === RUNNING_STATE) {
|
@@ -2182,8 +2545,10 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2182
2545
|
// method which will call the runner methods in async.
|
2183
2546
|
existingAnimation.close();
|
2184
2547
|
} else {
|
2185
|
-
// this will merge the
|
2186
|
-
|
2548
|
+
// this will merge the new animation options into existing animation options
|
2549
|
+
mergeAnimationDetails(element, existingAnimation, newAnimation);
|
2550
|
+
|
2551
|
+
return existingAnimation.runner;
|
2187
2552
|
}
|
2188
2553
|
} else {
|
2189
2554
|
// a joined animation means that this animation will take over the existing one
|
@@ -2192,18 +2557,23 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2192
2557
|
var joinAnimationFlag = isAllowed('join', element, newAnimation, existingAnimation);
|
2193
2558
|
if (joinAnimationFlag) {
|
2194
2559
|
if (existingAnimation.state === RUNNING_STATE) {
|
2195
|
-
|
2560
|
+
normalizeAnimationDetails(element, newAnimation);
|
2196
2561
|
} else {
|
2562
|
+
applyGeneratedPreparationClasses(element, isStructural ? event : null, options);
|
2563
|
+
|
2197
2564
|
event = newAnimation.event = existingAnimation.event;
|
2198
|
-
options =
|
2199
|
-
|
2565
|
+
options = mergeAnimationDetails(element, existingAnimation, newAnimation);
|
2566
|
+
|
2567
|
+
//we return the same runner since only the option values of this animation will
|
2568
|
+
//be fed into the `existingAnimation`.
|
2569
|
+
return existingAnimation.runner;
|
2200
2570
|
}
|
2201
2571
|
}
|
2202
2572
|
}
|
2203
2573
|
} else {
|
2204
2574
|
// normalization in this case means that it removes redundant CSS classes that
|
2205
2575
|
// already exist (addClass) or do not exist (removeClass) on the element
|
2206
|
-
|
2576
|
+
normalizeAnimationDetails(element, newAnimation);
|
2207
2577
|
}
|
2208
2578
|
|
2209
2579
|
// when the options are merged and cleaned up we may end up not having to do
|
@@ -2213,7 +2583,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2213
2583
|
if (!isValidAnimation) {
|
2214
2584
|
// animate (from/to) can be quickly checked first, otherwise we check if any classes are present
|
2215
2585
|
isValidAnimation = (newAnimation.event === 'animate' && Object.keys(newAnimation.options.to || {}).length > 0)
|
2216
|
-
|| hasAnimationClasses(newAnimation
|
2586
|
+
|| hasAnimationClasses(newAnimation);
|
2217
2587
|
}
|
2218
2588
|
|
2219
2589
|
if (!isValidAnimation) {
|
@@ -2222,10 +2592,6 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2222
2592
|
return runner;
|
2223
2593
|
}
|
2224
2594
|
|
2225
|
-
if (isStructural) {
|
2226
|
-
closeParentClassBasedAnimations(parent);
|
2227
|
-
}
|
2228
|
-
|
2229
2595
|
// the counter keeps track of cancelled animations
|
2230
2596
|
var counter = (existingAnimation.counter || 0) + 1;
|
2231
2597
|
newAnimation.counter = counter;
|
@@ -2247,7 +2613,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2247
2613
|
var isValidAnimation = parentElement.length > 0
|
2248
2614
|
&& (animationDetails.event === 'animate'
|
2249
2615
|
|| animationDetails.structural
|
2250
|
-
|| hasAnimationClasses(animationDetails
|
2616
|
+
|| hasAnimationClasses(animationDetails));
|
2251
2617
|
|
2252
2618
|
// this means that the previous animation was cancelled
|
2253
2619
|
// even if the follow-up animation is the same event
|
@@ -2279,16 +2645,13 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2279
2645
|
|
2280
2646
|
// this combined multiple class to addClass / removeClass into a setClass event
|
2281
2647
|
// so long as a structural event did not take over the animation
|
2282
|
-
event = !animationDetails.structural && hasAnimationClasses(animationDetails
|
2648
|
+
event = !animationDetails.structural && hasAnimationClasses(animationDetails, true)
|
2283
2649
|
? 'setClass'
|
2284
2650
|
: animationDetails.event;
|
2285
2651
|
|
2286
|
-
if (animationDetails.structural) {
|
2287
|
-
closeParentClassBasedAnimations(parentElement);
|
2288
|
-
}
|
2289
|
-
|
2290
2652
|
markElementAnimationState(element, RUNNING_STATE);
|
2291
2653
|
var realRunner = $$animation(element, event, animationDetails.options);
|
2654
|
+
|
2292
2655
|
realRunner.done(function(status) {
|
2293
2656
|
close(!status);
|
2294
2657
|
var animationDetails = activeAnimationsLookup.get(node);
|
@@ -2307,11 +2670,25 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2307
2670
|
return runner;
|
2308
2671
|
|
2309
2672
|
function notifyProgress(runner, event, phase, data) {
|
2310
|
-
|
2673
|
+
runInNextPostDigestOrNow(function() {
|
2674
|
+
var callbacks = findCallbacks(parent, element, event);
|
2675
|
+
if (callbacks.length) {
|
2676
|
+
// do not optimize this call here to RAF because
|
2677
|
+
// we don't know how heavy the callback code here will
|
2678
|
+
// be and if this code is buffered then this can
|
2679
|
+
// lead to a performance regression.
|
2680
|
+
$$rAF(function() {
|
2681
|
+
forEach(callbacks, function(callback) {
|
2682
|
+
callback(element, phase, data);
|
2683
|
+
});
|
2684
|
+
});
|
2685
|
+
}
|
2686
|
+
});
|
2311
2687
|
runner.progress(event, phase, data);
|
2312
2688
|
}
|
2313
2689
|
|
2314
2690
|
function close(reject) { // jshint ignore:line
|
2691
|
+
clearGeneratedClasses(element, options);
|
2315
2692
|
applyAnimationClasses(element, options);
|
2316
2693
|
applyAnimationStyles(element, options);
|
2317
2694
|
options.domOperation();
|
@@ -2325,15 +2702,15 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2325
2702
|
forEach(children, function(child) {
|
2326
2703
|
var state = parseInt(child.getAttribute(NG_ANIMATE_ATTR_NAME));
|
2327
2704
|
var animationDetails = activeAnimationsLookup.get(child);
|
2328
|
-
|
2329
|
-
|
2330
|
-
|
2331
|
-
|
2332
|
-
|
2333
|
-
|
2705
|
+
if (animationDetails) {
|
2706
|
+
switch (state) {
|
2707
|
+
case RUNNING_STATE:
|
2708
|
+
animationDetails.runner.end();
|
2709
|
+
/* falls through */
|
2710
|
+
case PRE_DIGEST_STATE:
|
2334
2711
|
activeAnimationsLookup.remove(child);
|
2335
|
-
|
2336
|
-
|
2712
|
+
break;
|
2713
|
+
}
|
2337
2714
|
}
|
2338
2715
|
});
|
2339
2716
|
}
|
@@ -2348,67 +2725,61 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2348
2725
|
return getDomNode(nodeOrElmA) === getDomNode(nodeOrElmB);
|
2349
2726
|
}
|
2350
2727
|
|
2351
|
-
|
2352
|
-
|
2353
|
-
|
2354
|
-
|
2355
|
-
|
2356
|
-
|
2357
|
-
|
2358
|
-
examineParentAnimation(parentNode, animationDetails);
|
2359
|
-
}
|
2360
|
-
|
2361
|
-
parentNode = parentNode.parentNode;
|
2362
|
-
} while (true);
|
2363
|
-
|
2364
|
-
// since animations are detected from CSS classes, we need to flush all parent
|
2365
|
-
// class-based animations so that the parent classes are all present for child
|
2366
|
-
// animations to properly function (otherwise any CSS selectors may not work)
|
2367
|
-
function examineParentAnimation(node, animationDetails) {
|
2368
|
-
// enter/leave/move always have priority
|
2369
|
-
if (animationDetails.structural || !hasAnimationClasses(animationDetails.options)) return;
|
2370
|
-
|
2371
|
-
if (animationDetails.state === RUNNING_STATE) {
|
2372
|
-
animationDetails.runner.end();
|
2373
|
-
}
|
2374
|
-
clearElementAnimationState(node);
|
2375
|
-
}
|
2376
|
-
}
|
2377
|
-
|
2728
|
+
/**
|
2729
|
+
* This fn returns false if any of the following is true:
|
2730
|
+
* a) animations on any parent element are disabled, and animations on the element aren't explicitly allowed
|
2731
|
+
* b) a parent element has an ongoing structural animation, and animateChildren is false
|
2732
|
+
* c) the element is not a child of the body
|
2733
|
+
* d) the element is not a child of the $rootElement
|
2734
|
+
*/
|
2378
2735
|
function areAnimationsAllowed(element, parentElement, event) {
|
2379
|
-
var
|
2380
|
-
var
|
2736
|
+
var bodyElement = jqLite($document[0].body);
|
2737
|
+
var bodyElementDetected = isMatchingElement(element, bodyElement) || element[0].nodeName === 'HTML';
|
2738
|
+
var rootElementDetected = isMatchingElement(element, $rootElement);
|
2381
2739
|
var parentAnimationDetected = false;
|
2382
2740
|
var animateChildren;
|
2741
|
+
var elementDisabled = disabledElementsLookup.get(getDomNode(element));
|
2383
2742
|
|
2384
|
-
var parentHost =
|
2743
|
+
var parentHost = jqLite.data(element[0], NG_ANIMATE_PIN_DATA);
|
2385
2744
|
if (parentHost) {
|
2386
2745
|
parentElement = parentHost;
|
2387
2746
|
}
|
2388
2747
|
|
2389
|
-
|
2748
|
+
parentElement = getDomNode(parentElement);
|
2749
|
+
|
2750
|
+
while (parentElement) {
|
2390
2751
|
if (!rootElementDetected) {
|
2391
2752
|
// angular doesn't want to attempt to animate elements outside of the application
|
2392
2753
|
// therefore we need to ensure that the rootElement is an ancestor of the current element
|
2393
2754
|
rootElementDetected = isMatchingElement(parentElement, $rootElement);
|
2394
2755
|
}
|
2395
2756
|
|
2396
|
-
|
2397
|
-
if (parentNode.nodeType !== ELEMENT_NODE) {
|
2757
|
+
if (parentElement.nodeType !== ELEMENT_NODE) {
|
2398
2758
|
// no point in inspecting the #document element
|
2399
2759
|
break;
|
2400
2760
|
}
|
2401
2761
|
|
2402
|
-
var details = activeAnimationsLookup.get(
|
2762
|
+
var details = activeAnimationsLookup.get(parentElement) || {};
|
2403
2763
|
// either an enter, leave or move animation will commence
|
2404
2764
|
// therefore we can't allow any animations to take place
|
2405
2765
|
// but if a parent animation is class-based then that's ok
|
2406
2766
|
if (!parentAnimationDetected) {
|
2407
|
-
|
2767
|
+
var parentElementDisabled = disabledElementsLookup.get(parentElement);
|
2768
|
+
|
2769
|
+
if (parentElementDisabled === true && elementDisabled !== false) {
|
2770
|
+
// disable animations if the user hasn't explicitly enabled animations on the
|
2771
|
+
// current element
|
2772
|
+
elementDisabled = true;
|
2773
|
+
// element is disabled via parent element, no need to check anything else
|
2774
|
+
break;
|
2775
|
+
} else if (parentElementDisabled === false) {
|
2776
|
+
elementDisabled = false;
|
2777
|
+
}
|
2778
|
+
parentAnimationDetected = details.structural;
|
2408
2779
|
}
|
2409
2780
|
|
2410
2781
|
if (isUndefined(animateChildren) || animateChildren === true) {
|
2411
|
-
var value =
|
2782
|
+
var value = jqLite.data(parentElement, NG_ANIMATE_CHILDREN_DATA);
|
2412
2783
|
if (isDefined(value)) {
|
2413
2784
|
animateChildren = value;
|
2414
2785
|
}
|
@@ -2417,28 +2788,32 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2417
2788
|
// there is no need to continue traversing at this point
|
2418
2789
|
if (parentAnimationDetected && animateChildren === false) break;
|
2419
2790
|
|
2420
|
-
if (!rootElementDetected) {
|
2421
|
-
// angular doesn't want to attempt to animate elements outside of the application
|
2422
|
-
// therefore we need to ensure that the rootElement is an ancestor of the current element
|
2423
|
-
rootElementDetected = isMatchingElement(parentElement, $rootElement);
|
2424
|
-
if (!rootElementDetected) {
|
2425
|
-
parentHost = parentElement.data(NG_ANIMATE_PIN_DATA);
|
2426
|
-
if (parentHost) {
|
2427
|
-
parentElement = parentHost;
|
2428
|
-
}
|
2429
|
-
}
|
2430
|
-
}
|
2431
|
-
|
2432
2791
|
if (!bodyElementDetected) {
|
2433
|
-
// we also need to ensure that the element is or will be
|
2792
|
+
// we also need to ensure that the element is or will be a part of the body element
|
2434
2793
|
// otherwise it is pointless to even issue an animation to be rendered
|
2435
2794
|
bodyElementDetected = isMatchingElement(parentElement, bodyElement);
|
2436
2795
|
}
|
2437
2796
|
|
2438
|
-
|
2797
|
+
if (bodyElementDetected && rootElementDetected) {
|
2798
|
+
// If both body and root have been found, any other checks are pointless,
|
2799
|
+
// as no animation data should live outside the application
|
2800
|
+
break;
|
2801
|
+
}
|
2802
|
+
|
2803
|
+
if (!rootElementDetected) {
|
2804
|
+
// If no rootElement is detected, check if the parentElement is pinned to another element
|
2805
|
+
parentHost = jqLite.data(parentElement, NG_ANIMATE_PIN_DATA);
|
2806
|
+
if (parentHost) {
|
2807
|
+
// The pin target element becomes the next parent element
|
2808
|
+
parentElement = getDomNode(parentHost);
|
2809
|
+
continue;
|
2810
|
+
}
|
2811
|
+
}
|
2812
|
+
|
2813
|
+
parentElement = parentElement.parentNode;
|
2439
2814
|
}
|
2440
2815
|
|
2441
|
-
var allowAnimation = !parentAnimationDetected || animateChildren;
|
2816
|
+
var allowAnimation = (!parentAnimationDetected || animateChildren) && elementDisabled !== true;
|
2442
2817
|
return allowAnimation && rootElementDetected && bodyElementDetected;
|
2443
2818
|
}
|
2444
2819
|
|
@@ -2458,184 +2833,112 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|
2458
2833
|
}];
|
2459
2834
|
}];
|
2460
2835
|
|
2461
|
-
var $$
|
2462
|
-
|
2463
|
-
var passed = false;
|
2464
|
-
$$rAF(function() {
|
2465
|
-
passed = true;
|
2466
|
-
});
|
2467
|
-
return function(fn) {
|
2468
|
-
passed ? fn() : $$rAF(fn);
|
2469
|
-
};
|
2470
|
-
};
|
2471
|
-
}];
|
2472
|
-
|
2473
|
-
var $$AnimateRunnerFactory = ['$q', '$$rAFMutex', function($q, $$rAFMutex) {
|
2474
|
-
var INITIAL_STATE = 0;
|
2475
|
-
var DONE_PENDING_STATE = 1;
|
2476
|
-
var DONE_COMPLETE_STATE = 2;
|
2477
|
-
|
2478
|
-
AnimateRunner.chain = function(chain, callback) {
|
2479
|
-
var index = 0;
|
2480
|
-
|
2481
|
-
next();
|
2482
|
-
function next() {
|
2483
|
-
if (index === chain.length) {
|
2484
|
-
callback(true);
|
2485
|
-
return;
|
2486
|
-
}
|
2487
|
-
|
2488
|
-
chain[index](function(response) {
|
2489
|
-
if (response === false) {
|
2490
|
-
callback(false);
|
2491
|
-
return;
|
2492
|
-
}
|
2493
|
-
index++;
|
2494
|
-
next();
|
2495
|
-
});
|
2496
|
-
}
|
2497
|
-
};
|
2836
|
+
var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
2837
|
+
var NG_ANIMATE_REF_ATTR = 'ng-animate-ref';
|
2498
2838
|
|
2499
|
-
|
2500
|
-
var count = 0;
|
2501
|
-
var status = true;
|
2502
|
-
forEach(runners, function(runner) {
|
2503
|
-
runner.done(onProgress);
|
2504
|
-
});
|
2839
|
+
var drivers = this.drivers = [];
|
2505
2840
|
|
2506
|
-
|
2507
|
-
status = status && response;
|
2508
|
-
if (++count === runners.length) {
|
2509
|
-
callback(status);
|
2510
|
-
}
|
2511
|
-
}
|
2512
|
-
};
|
2841
|
+
var RUNNER_STORAGE_KEY = '$$animationRunner';
|
2513
2842
|
|
2514
|
-
function
|
2515
|
-
|
2843
|
+
function setRunner(element, runner) {
|
2844
|
+
element.data(RUNNER_STORAGE_KEY, runner);
|
2845
|
+
}
|
2516
2846
|
|
2517
|
-
|
2518
|
-
|
2519
|
-
this._state = 0;
|
2847
|
+
function removeRunner(element) {
|
2848
|
+
element.removeData(RUNNER_STORAGE_KEY);
|
2520
2849
|
}
|
2521
2850
|
|
2522
|
-
|
2523
|
-
|
2524
|
-
|
2525
|
-
},
|
2851
|
+
function getRunner(element) {
|
2852
|
+
return element.data(RUNNER_STORAGE_KEY);
|
2853
|
+
}
|
2526
2854
|
|
2527
|
-
|
2528
|
-
|
2529
|
-
fn();
|
2530
|
-
} else {
|
2531
|
-
this._doneCallbacks.push(fn);
|
2532
|
-
}
|
2533
|
-
},
|
2855
|
+
this.$get = ['$$jqLite', '$rootScope', '$injector', '$$AnimateRunner', '$$HashMap', '$$rAFScheduler',
|
2856
|
+
function($$jqLite, $rootScope, $injector, $$AnimateRunner, $$HashMap, $$rAFScheduler) {
|
2534
2857
|
|
2535
|
-
|
2858
|
+
var animationQueue = [];
|
2859
|
+
var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
|
2536
2860
|
|
2537
|
-
|
2538
|
-
|
2539
|
-
|
2540
|
-
|
2541
|
-
|
2542
|
-
|
2543
|
-
|
2861
|
+
function sortAnimations(animations) {
|
2862
|
+
var tree = { children: [] };
|
2863
|
+
var i, lookup = new $$HashMap();
|
2864
|
+
|
2865
|
+
// this is done first beforehand so that the hashmap
|
2866
|
+
// is filled with a list of the elements that will be animated
|
2867
|
+
for (i = 0; i < animations.length; i++) {
|
2868
|
+
var animation = animations[i];
|
2869
|
+
lookup.put(animation.domNode, animations[i] = {
|
2870
|
+
domNode: animation.domNode,
|
2871
|
+
fn: animation.fn,
|
2872
|
+
children: []
|
2544
2873
|
});
|
2545
2874
|
}
|
2546
|
-
return this.promise;
|
2547
|
-
},
|
2548
|
-
|
2549
|
-
then: function(resolveHandler, rejectHandler) {
|
2550
|
-
return this.getPromise().then(resolveHandler, rejectHandler);
|
2551
|
-
},
|
2552
|
-
|
2553
|
-
'catch': function(handler) {
|
2554
|
-
return this.getPromise()['catch'](handler);
|
2555
|
-
},
|
2556
|
-
|
2557
|
-
'finally': function(handler) {
|
2558
|
-
return this.getPromise()['finally'](handler);
|
2559
|
-
},
|
2560
2875
|
|
2561
|
-
|
2562
|
-
|
2563
|
-
this.host.pause();
|
2876
|
+
for (i = 0; i < animations.length; i++) {
|
2877
|
+
processNode(animations[i]);
|
2564
2878
|
}
|
2565
|
-
},
|
2566
2879
|
|
2567
|
-
|
2568
|
-
if (this.host.resume) {
|
2569
|
-
this.host.resume();
|
2570
|
-
}
|
2571
|
-
},
|
2880
|
+
return flatten(tree);
|
2572
2881
|
|
2573
|
-
|
2574
|
-
|
2575
|
-
|
2576
|
-
}
|
2577
|
-
this._resolve(true);
|
2578
|
-
},
|
2882
|
+
function processNode(entry) {
|
2883
|
+
if (entry.processed) return entry;
|
2884
|
+
entry.processed = true;
|
2579
2885
|
|
2580
|
-
|
2581
|
-
|
2582
|
-
|
2583
|
-
}
|
2584
|
-
this._resolve(false);
|
2585
|
-
},
|
2886
|
+
var elementNode = entry.domNode;
|
2887
|
+
var parentNode = elementNode.parentNode;
|
2888
|
+
lookup.put(elementNode, entry);
|
2586
2889
|
|
2587
|
-
|
2588
|
-
|
2589
|
-
|
2590
|
-
|
2591
|
-
|
2592
|
-
|
2593
|
-
|
2594
|
-
|
2595
|
-
|
2890
|
+
var parentEntry;
|
2891
|
+
while (parentNode) {
|
2892
|
+
parentEntry = lookup.get(parentNode);
|
2893
|
+
if (parentEntry) {
|
2894
|
+
if (!parentEntry.processed) {
|
2895
|
+
parentEntry = processNode(parentEntry);
|
2896
|
+
}
|
2897
|
+
break;
|
2898
|
+
}
|
2899
|
+
parentNode = parentNode.parentNode;
|
2900
|
+
}
|
2596
2901
|
|
2597
|
-
|
2598
|
-
|
2599
|
-
forEach(this._doneCallbacks, function(fn) {
|
2600
|
-
fn(response);
|
2601
|
-
});
|
2602
|
-
this._doneCallbacks.length = 0;
|
2603
|
-
this._state = DONE_COMPLETE_STATE;
|
2902
|
+
(parentEntry || tree).children.push(entry);
|
2903
|
+
return entry;
|
2604
2904
|
}
|
2605
|
-
}
|
2606
|
-
};
|
2607
|
-
|
2608
|
-
return AnimateRunner;
|
2609
|
-
}];
|
2610
|
-
|
2611
|
-
var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
2612
|
-
var NG_ANIMATE_REF_ATTR = 'ng-animate-ref';
|
2613
|
-
|
2614
|
-
var drivers = this.drivers = [];
|
2615
|
-
|
2616
|
-
var RUNNER_STORAGE_KEY = '$$animationRunner';
|
2617
|
-
|
2618
|
-
function setRunner(element, runner) {
|
2619
|
-
element.data(RUNNER_STORAGE_KEY, runner);
|
2620
|
-
}
|
2621
2905
|
|
2622
|
-
|
2623
|
-
|
2624
|
-
|
2906
|
+
function flatten(tree) {
|
2907
|
+
var result = [];
|
2908
|
+
var queue = [];
|
2909
|
+
var i;
|
2625
2910
|
|
2626
|
-
|
2627
|
-
|
2628
|
-
|
2911
|
+
for (i = 0; i < tree.children.length; i++) {
|
2912
|
+
queue.push(tree.children[i]);
|
2913
|
+
}
|
2629
2914
|
|
2630
|
-
|
2631
|
-
|
2915
|
+
var remainingLevelEntries = queue.length;
|
2916
|
+
var nextLevelEntries = 0;
|
2917
|
+
var row = [];
|
2918
|
+
|
2919
|
+
for (i = 0; i < queue.length; i++) {
|
2920
|
+
var entry = queue[i];
|
2921
|
+
if (remainingLevelEntries <= 0) {
|
2922
|
+
remainingLevelEntries = nextLevelEntries;
|
2923
|
+
nextLevelEntries = 0;
|
2924
|
+
result.push(row);
|
2925
|
+
row = [];
|
2926
|
+
}
|
2927
|
+
row.push(entry.fn);
|
2928
|
+
entry.children.forEach(function(childEntry) {
|
2929
|
+
nextLevelEntries++;
|
2930
|
+
queue.push(childEntry);
|
2931
|
+
});
|
2932
|
+
remainingLevelEntries--;
|
2933
|
+
}
|
2632
2934
|
|
2633
|
-
|
2634
|
-
|
2935
|
+
if (row.length) {
|
2936
|
+
result.push(row);
|
2937
|
+
}
|
2635
2938
|
|
2636
|
-
|
2637
|
-
|
2638
|
-
|
2939
|
+
return result;
|
2940
|
+
}
|
2941
|
+
}
|
2639
2942
|
|
2640
2943
|
// TODO(matsko): document the signature in a better way
|
2641
2944
|
return function(element, event, options) {
|
@@ -2665,10 +2968,10 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
2665
2968
|
options.tempClasses = null;
|
2666
2969
|
}
|
2667
2970
|
|
2668
|
-
var
|
2669
|
-
if (
|
2670
|
-
|
2671
|
-
|
2971
|
+
var prepareClassName;
|
2972
|
+
if (isStructural) {
|
2973
|
+
prepareClassName = 'ng-' + event + PREPARE_CLASS_SUFFIX;
|
2974
|
+
$$jqLite.addClass(element, prepareClassName);
|
2672
2975
|
}
|
2673
2976
|
|
2674
2977
|
animationQueue.push({
|
@@ -2677,7 +2980,6 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
2677
2980
|
element: element,
|
2678
2981
|
classes: classes,
|
2679
2982
|
event: event,
|
2680
|
-
classBasedIndex: classBasedIndex,
|
2681
2983
|
structural: isStructural,
|
2682
2984
|
options: options,
|
2683
2985
|
beforeStart: beforeStart,
|
@@ -2692,10 +2994,6 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
2692
2994
|
if (animationQueue.length > 1) return runner;
|
2693
2995
|
|
2694
2996
|
$rootScope.$$postDigest(function() {
|
2695
|
-
totalActiveClassBasedAnimations = totalPendingClassBasedAnimations;
|
2696
|
-
totalPendingClassBasedAnimations = 0;
|
2697
|
-
classBasedAnimationsQueue.length = 0;
|
2698
|
-
|
2699
2997
|
var animations = [];
|
2700
2998
|
forEach(animationQueue, function(entry) {
|
2701
2999
|
// the element was destroyed early on which removed the runner
|
@@ -2703,67 +3001,58 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
2703
3001
|
// at all and it already has been closed due to destruction.
|
2704
3002
|
if (getRunner(entry.element)) {
|
2705
3003
|
animations.push(entry);
|
3004
|
+
} else {
|
3005
|
+
entry.close();
|
2706
3006
|
}
|
2707
3007
|
});
|
2708
3008
|
|
2709
3009
|
// now any future animations will be in another postDigest
|
2710
3010
|
animationQueue.length = 0;
|
2711
3011
|
|
2712
|
-
|
2713
|
-
|
2714
|
-
|
2715
|
-
|
2716
|
-
|
2717
|
-
|
2718
|
-
|
2719
|
-
|
2720
|
-
|
2721
|
-
|
2722
|
-
|
2723
|
-
|
2724
|
-
|
2725
|
-
|
2726
|
-
|
2727
|
-
|
2728
|
-
|
2729
|
-
|
2730
|
-
|
2731
|
-
|
2732
|
-
|
2733
|
-
|
2734
|
-
|
2735
|
-
|
2736
|
-
|
2737
|
-
// temporary classes before we do any driver invoking since these
|
2738
|
-
// CSS classes may be required for proper CSS detection.
|
2739
|
-
animationEntry.beforeStart();
|
2740
|
-
|
2741
|
-
var startAnimationFn, closeFn = animationEntry.close;
|
2742
|
-
|
2743
|
-
// in the event that the element was removed before the digest runs or
|
2744
|
-
// during the RAF sequencing then we should not trigger the animation.
|
2745
|
-
var targetElement = animationEntry.anchors
|
2746
|
-
? (animationEntry.from.element || animationEntry.to.element)
|
2747
|
-
: animationEntry.element;
|
2748
|
-
|
2749
|
-
if (getRunner(targetElement)) {
|
2750
|
-
var operation = invokeFirstDriver(animationEntry);
|
2751
|
-
if (operation) {
|
2752
|
-
startAnimationFn = operation.start;
|
3012
|
+
var groupedAnimations = groupAnimations(animations);
|
3013
|
+
var toBeSortedAnimations = [];
|
3014
|
+
|
3015
|
+
forEach(groupedAnimations, function(animationEntry) {
|
3016
|
+
toBeSortedAnimations.push({
|
3017
|
+
domNode: getDomNode(animationEntry.from ? animationEntry.from.element : animationEntry.element),
|
3018
|
+
fn: function triggerAnimationStart() {
|
3019
|
+
// it's important that we apply the `ng-animate` CSS class and the
|
3020
|
+
// temporary classes before we do any driver invoking since these
|
3021
|
+
// CSS classes may be required for proper CSS detection.
|
3022
|
+
animationEntry.beforeStart();
|
3023
|
+
|
3024
|
+
var startAnimationFn, closeFn = animationEntry.close;
|
3025
|
+
|
3026
|
+
// in the event that the element was removed before the digest runs or
|
3027
|
+
// during the RAF sequencing then we should not trigger the animation.
|
3028
|
+
var targetElement = animationEntry.anchors
|
3029
|
+
? (animationEntry.from.element || animationEntry.to.element)
|
3030
|
+
: animationEntry.element;
|
3031
|
+
|
3032
|
+
if (getRunner(targetElement)) {
|
3033
|
+
var operation = invokeFirstDriver(animationEntry);
|
3034
|
+
if (operation) {
|
3035
|
+
startAnimationFn = operation.start;
|
3036
|
+
}
|
2753
3037
|
}
|
2754
|
-
}
|
2755
3038
|
|
2756
|
-
|
2757
|
-
|
2758
|
-
|
2759
|
-
|
2760
|
-
|
2761
|
-
|
2762
|
-
|
2763
|
-
|
3039
|
+
if (!startAnimationFn) {
|
3040
|
+
closeFn();
|
3041
|
+
} else {
|
3042
|
+
var animationRunner = startAnimationFn();
|
3043
|
+
animationRunner.done(function(status) {
|
3044
|
+
closeFn(!status);
|
3045
|
+
});
|
3046
|
+
updateAnimationRunners(animationEntry, animationRunner);
|
3047
|
+
}
|
2764
3048
|
}
|
2765
|
-
}
|
3049
|
+
});
|
2766
3050
|
});
|
3051
|
+
|
3052
|
+
// we need to sort each of the animations in order of parent to child
|
3053
|
+
// relationships. This ensures that the child classes are applied at the
|
3054
|
+
// right time.
|
3055
|
+
$$rAFScheduler(sortAnimations(toBeSortedAnimations));
|
2767
3056
|
});
|
2768
3057
|
|
2769
3058
|
return runner;
|
@@ -2849,7 +3138,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
2849
3138
|
};
|
2850
3139
|
|
2851
3140
|
// the anchor animations require that the from and to elements both have at least
|
2852
|
-
// one shared CSS class which
|
3141
|
+
// one shared CSS class which effectively marries the two elements together to use
|
2853
3142
|
// the same animation driver and to properly sequence the anchor animation.
|
2854
3143
|
if (group.classes.length) {
|
2855
3144
|
preparedAnimations.push(group);
|
@@ -2907,6 +3196,10 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
2907
3196
|
if (tempClasses) {
|
2908
3197
|
$$jqLite.addClass(element, tempClasses);
|
2909
3198
|
}
|
3199
|
+
if (prepareClassName) {
|
3200
|
+
$$jqLite.removeClass(element, prepareClassName);
|
3201
|
+
prepareClassName = null;
|
3202
|
+
}
|
2910
3203
|
}
|
2911
3204
|
|
2912
3205
|
function updateAnimationRunners(animation, newRunner) {
|
@@ -2948,12 +3241,127 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
2948
3241
|
}];
|
2949
3242
|
}];
|
2950
3243
|
|
3244
|
+
/**
|
3245
|
+
* @ngdoc directive
|
3246
|
+
* @name ngAnimateSwap
|
3247
|
+
* @restrict A
|
3248
|
+
* @scope
|
3249
|
+
*
|
3250
|
+
* @description
|
3251
|
+
*
|
3252
|
+
* ngAnimateSwap is a animation-oriented directive that allows for the container to
|
3253
|
+
* be removed and entered in whenever the associated expression changes. A
|
3254
|
+
* common usecase for this directive is a rotating banner or slider component which
|
3255
|
+
* contains one image being present at a time. When the active image changes
|
3256
|
+
* then the old image will perform a `leave` animation and the new element
|
3257
|
+
* will be inserted via an `enter` animation.
|
3258
|
+
*
|
3259
|
+
* @animations
|
3260
|
+
* | Animation | Occurs |
|
3261
|
+
* |----------------------------------|--------------------------------------|
|
3262
|
+
* | {@link ng.$animate#enter enter} | when the new element is inserted to the DOM |
|
3263
|
+
* | {@link ng.$animate#leave leave} | when the old element is removed from the DOM |
|
3264
|
+
*
|
3265
|
+
* @example
|
3266
|
+
* <example name="ngAnimateSwap-directive" module="ngAnimateSwapExample"
|
3267
|
+
* deps="angular-animate.js"
|
3268
|
+
* animations="true" fixBase="true">
|
3269
|
+
* <file name="index.html">
|
3270
|
+
* <div class="container" ng-controller="AppCtrl">
|
3271
|
+
* <div ng-animate-swap="number" class="cell swap-animation" ng-class="colorClass(number)">
|
3272
|
+
* {{ number }}
|
3273
|
+
* </div>
|
3274
|
+
* </div>
|
3275
|
+
* </file>
|
3276
|
+
* <file name="script.js">
|
3277
|
+
* angular.module('ngAnimateSwapExample', ['ngAnimate'])
|
3278
|
+
* .controller('AppCtrl', ['$scope', '$interval', function($scope, $interval) {
|
3279
|
+
* $scope.number = 0;
|
3280
|
+
* $interval(function() {
|
3281
|
+
* $scope.number++;
|
3282
|
+
* }, 1000);
|
3283
|
+
*
|
3284
|
+
* var colors = ['red','blue','green','yellow','orange'];
|
3285
|
+
* $scope.colorClass = function(number) {
|
3286
|
+
* return colors[number % colors.length];
|
3287
|
+
* };
|
3288
|
+
* }]);
|
3289
|
+
* </file>
|
3290
|
+
* <file name="animations.css">
|
3291
|
+
* .container {
|
3292
|
+
* height:250px;
|
3293
|
+
* width:250px;
|
3294
|
+
* position:relative;
|
3295
|
+
* overflow:hidden;
|
3296
|
+
* border:2px solid black;
|
3297
|
+
* }
|
3298
|
+
* .container .cell {
|
3299
|
+
* font-size:150px;
|
3300
|
+
* text-align:center;
|
3301
|
+
* line-height:250px;
|
3302
|
+
* position:absolute;
|
3303
|
+
* top:0;
|
3304
|
+
* left:0;
|
3305
|
+
* right:0;
|
3306
|
+
* border-bottom:2px solid black;
|
3307
|
+
* }
|
3308
|
+
* .swap-animation.ng-enter, .swap-animation.ng-leave {
|
3309
|
+
* transition:0.5s linear all;
|
3310
|
+
* }
|
3311
|
+
* .swap-animation.ng-enter {
|
3312
|
+
* top:-250px;
|
3313
|
+
* }
|
3314
|
+
* .swap-animation.ng-enter-active {
|
3315
|
+
* top:0px;
|
3316
|
+
* }
|
3317
|
+
* .swap-animation.ng-leave {
|
3318
|
+
* top:0px;
|
3319
|
+
* }
|
3320
|
+
* .swap-animation.ng-leave-active {
|
3321
|
+
* top:250px;
|
3322
|
+
* }
|
3323
|
+
* .red { background:red; }
|
3324
|
+
* .green { background:green; }
|
3325
|
+
* .blue { background:blue; }
|
3326
|
+
* .yellow { background:yellow; }
|
3327
|
+
* .orange { background:orange; }
|
3328
|
+
* </file>
|
3329
|
+
* </example>
|
3330
|
+
*/
|
3331
|
+
var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $rootScope) {
|
3332
|
+
return {
|
3333
|
+
restrict: 'A',
|
3334
|
+
transclude: 'element',
|
3335
|
+
terminal: true,
|
3336
|
+
priority: 600, // we use 600 here to ensure that the directive is caught before others
|
3337
|
+
link: function(scope, $element, attrs, ctrl, $transclude) {
|
3338
|
+
var previousElement, previousScope;
|
3339
|
+
scope.$watchCollection(attrs.ngAnimateSwap || attrs['for'], function(value) {
|
3340
|
+
if (previousElement) {
|
3341
|
+
$animate.leave(previousElement);
|
3342
|
+
}
|
3343
|
+
if (previousScope) {
|
3344
|
+
previousScope.$destroy();
|
3345
|
+
previousScope = null;
|
3346
|
+
}
|
3347
|
+
if (value || value === 0) {
|
3348
|
+
previousScope = scope.$new();
|
3349
|
+
$transclude(previousScope, function(element) {
|
3350
|
+
previousElement = element;
|
3351
|
+
$animate.enter(element, null, $element);
|
3352
|
+
});
|
3353
|
+
}
|
3354
|
+
});
|
3355
|
+
}
|
3356
|
+
};
|
3357
|
+
}];
|
3358
|
+
|
2951
3359
|
/* global angularAnimateModule: true,
|
2952
3360
|
|
2953
|
-
|
3361
|
+
ngAnimateSwapDirective,
|
3362
|
+
$$AnimateAsyncRunFactory,
|
2954
3363
|
$$rAFSchedulerFactory,
|
2955
3364
|
$$AnimateChildrenDirective,
|
2956
|
-
$$AnimateRunnerFactory,
|
2957
3365
|
$$AnimateQueueProvider,
|
2958
3366
|
$$AnimationProvider,
|
2959
3367
|
$AnimateCssProvider,
|
@@ -2968,7 +3376,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
2968
3376
|
* @description
|
2969
3377
|
*
|
2970
3378
|
* The `ngAnimate` module provides support for CSS-based animations (keyframes and transitions) as well as JavaScript-based animations via
|
2971
|
-
* callback hooks. Animations are not enabled by default, however, by including `ngAnimate`
|
3379
|
+
* callback hooks. Animations are not enabled by default, however, by including `ngAnimate` the animation hooks are enabled for an Angular app.
|
2972
3380
|
*
|
2973
3381
|
* <div doc-module-components="ngAnimate"></div>
|
2974
3382
|
*
|
@@ -3001,7 +3409,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
3001
3409
|
* CSS-based animations with ngAnimate are unique since they require no JavaScript code at all. By using a CSS class that we reference between our HTML
|
3002
3410
|
* and CSS code we can create an animation that will be picked up by Angular when an the underlying directive performs an operation.
|
3003
3411
|
*
|
3004
|
-
* The example below shows how an `enter` animation can be made possible on
|
3412
|
+
* The example below shows how an `enter` animation can be made possible on an element using `ng-if`:
|
3005
3413
|
*
|
3006
3414
|
* ```html
|
3007
3415
|
* <div ng-if="bool" class="fade">
|
@@ -3020,7 +3428,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
3020
3428
|
* opacity:0;
|
3021
3429
|
* }
|
3022
3430
|
*
|
3023
|
-
* /* The
|
3431
|
+
* /* The finishing CSS styles for the enter animation */
|
3024
3432
|
* .fade.ng-enter.ng-enter-active {
|
3025
3433
|
* opacity:1;
|
3026
3434
|
* }
|
@@ -3136,8 +3544,8 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
3136
3544
|
* /* this will have a 100ms delay between each successive leave animation */
|
3137
3545
|
* transition-delay: 0.1s;
|
3138
3546
|
*
|
3139
|
-
* /*
|
3140
|
-
*
|
3547
|
+
* /* As of 1.4.4, this must always be set: it signals ngAnimate
|
3548
|
+
* to not accidentally inherit a delay property from another CSS class */
|
3141
3549
|
* transition-duration: 0s;
|
3142
3550
|
* }
|
3143
3551
|
* .my-animation.ng-enter.ng-enter-active {
|
@@ -3202,11 +3610,39 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
3202
3610
|
* the CSS class once an animation has completed.)
|
3203
3611
|
*
|
3204
3612
|
*
|
3613
|
+
* ### The `ng-[event]-prepare` class
|
3614
|
+
*
|
3615
|
+
* This is a special class that can be used to prevent unwanted flickering / flash of content before
|
3616
|
+
* the actual animation starts. The class is added as soon as an animation is initialized, but removed
|
3617
|
+
* before the actual animation starts (after waiting for a $digest).
|
3618
|
+
* It is also only added for *structural* animations (`enter`, `move`, and `leave`).
|
3619
|
+
*
|
3620
|
+
* In practice, flickering can appear when nesting elements with structural animations such as `ngIf`
|
3621
|
+
* into elements that have class-based animations such as `ngClass`.
|
3622
|
+
*
|
3623
|
+
* ```html
|
3624
|
+
* <div ng-class="{red: myProp}">
|
3625
|
+
* <div ng-class="{blue: myProp}">
|
3626
|
+
* <div class="message" ng-if="myProp"></div>
|
3627
|
+
* </div>
|
3628
|
+
* </div>
|
3629
|
+
* ```
|
3630
|
+
*
|
3631
|
+
* It is possible that during the `enter` animation, the `.message` div will be briefly visible before it starts animating.
|
3632
|
+
* In that case, you can add styles to the CSS that make sure the element stays hidden before the animation starts:
|
3633
|
+
*
|
3634
|
+
* ```css
|
3635
|
+
* .message.ng-enter-prepare {
|
3636
|
+
* opacity: 0;
|
3637
|
+
* }
|
3638
|
+
*
|
3639
|
+
* ```
|
3640
|
+
*
|
3205
3641
|
* ## JavaScript-based Animations
|
3206
3642
|
*
|
3207
3643
|
* ngAnimate also allows for animations to be consumed by JavaScript code. The approach is similar to CSS-based animations (where there is a shared
|
3208
3644
|
* CSS class that is referenced in our HTML code) but in addition we need to register the JavaScript animation on the module. By making use of the
|
3209
|
-
* `module.animation()` module function we can register the
|
3645
|
+
* `module.animation()` module function we can register the animation.
|
3210
3646
|
*
|
3211
3647
|
* Let's see an example of a enter/leave animation using `ngRepeat`:
|
3212
3648
|
*
|
@@ -3238,7 +3674,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
3238
3674
|
* jQuery(element).fadeOut(1000, doneFn);
|
3239
3675
|
* }
|
3240
3676
|
* }
|
3241
|
-
* }]
|
3677
|
+
* }]);
|
3242
3678
|
* ```
|
3243
3679
|
*
|
3244
3680
|
* The nice thing about JS-based animations is that we can inject other services and make use of advanced animation libraries such as
|
@@ -3269,13 +3705,13 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
3269
3705
|
* // do some cool animation and call the doneFn
|
3270
3706
|
* }
|
3271
3707
|
* }
|
3272
|
-
* }]
|
3708
|
+
* }]);
|
3273
3709
|
* ```
|
3274
3710
|
*
|
3275
3711
|
* ## CSS + JS Animations Together
|
3276
3712
|
*
|
3277
3713
|
* AngularJS 1.4 and higher has taken steps to make the amalgamation of CSS and JS animations more flexible. However, unlike earlier versions of Angular,
|
3278
|
-
* defining CSS and JS animations to work off of the same CSS class will not work anymore. Therefore example below will only result in **JS animations taking
|
3714
|
+
* defining CSS and JS animations to work off of the same CSS class will not work anymore. Therefore the example below will only result in **JS animations taking
|
3279
3715
|
* charge of the animation**:
|
3280
3716
|
*
|
3281
3717
|
* ```html
|
@@ -3291,7 +3727,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
3291
3727
|
* jQuery(element).slideIn(1000, doneFn);
|
3292
3728
|
* }
|
3293
3729
|
* }
|
3294
|
-
* }]
|
3730
|
+
* }]);
|
3295
3731
|
* ```
|
3296
3732
|
*
|
3297
3733
|
* ```css
|
@@ -3304,23 +3740,22 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
3304
3740
|
* }
|
3305
3741
|
* ```
|
3306
3742
|
*
|
3307
|
-
* Does this mean that CSS and JS animations cannot be used together? Do JS-based animations always have higher priority? We can
|
3308
|
-
* lack of CSS animations by
|
3743
|
+
* Does this mean that CSS and JS animations cannot be used together? Do JS-based animations always have higher priority? We can make up for the
|
3744
|
+
* lack of CSS animations by using the `$animateCss` service to trigger our own tweaked-out, CSS-based animations directly from
|
3309
3745
|
* our own JS-based animation code:
|
3310
3746
|
*
|
3311
3747
|
* ```js
|
3312
3748
|
* myModule.animation('.slide', ['$animateCss', function($animateCss) {
|
3313
3749
|
* return {
|
3314
|
-
* enter: function(element
|
3750
|
+
* enter: function(element) {
|
3315
3751
|
* // this will trigger `.slide.ng-enter` and `.slide.ng-enter-active`.
|
3316
|
-
*
|
3752
|
+
* return $animateCss(element, {
|
3317
3753
|
* event: 'enter',
|
3318
3754
|
* structural: true
|
3319
|
-
* })
|
3320
|
-
* runner.done(doneFn);
|
3755
|
+
* });
|
3321
3756
|
* }
|
3322
3757
|
* }
|
3323
|
-
* }]
|
3758
|
+
* }]);
|
3324
3759
|
* ```
|
3325
3760
|
*
|
3326
3761
|
* The nice thing here is that we can save bandwidth by sticking to our CSS-based animation code and we don't need to rely on a 3rd-party animation framework.
|
@@ -3332,18 +3767,17 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
3332
3767
|
* ```js
|
3333
3768
|
* myModule.animation('.slide', ['$animateCss', function($animateCss) {
|
3334
3769
|
* return {
|
3335
|
-
* enter: function(element
|
3336
|
-
*
|
3770
|
+
* enter: function(element) {
|
3771
|
+
* return $animateCss(element, {
|
3337
3772
|
* event: 'enter',
|
3773
|
+
* structural: true,
|
3338
3774
|
* addClass: 'maroon-setting',
|
3339
3775
|
* from: { height:0 },
|
3340
3776
|
* to: { height: 200 }
|
3341
|
-
* })
|
3342
|
-
*
|
3343
|
-
* runner.done(doneFn);
|
3777
|
+
* });
|
3344
3778
|
* }
|
3345
3779
|
* }
|
3346
|
-
* }]
|
3780
|
+
* }]);
|
3347
3781
|
* ```
|
3348
3782
|
*
|
3349
3783
|
* Now we can fill in the rest via our transition CSS code:
|
@@ -3603,7 +4037,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
3603
4037
|
* ngModule.directive('greetingBox', ['$animate', function($animate) {
|
3604
4038
|
* return function(scope, element, attrs) {
|
3605
4039
|
* attrs.$observe('active', function(value) {
|
3606
|
-
* value ? $animate.addClass(element, 'on')
|
4040
|
+
* value ? $animate.addClass(element, 'on') : $animate.removeClass(element, 'on');
|
3607
4041
|
* });
|
3608
4042
|
* });
|
3609
4043
|
* }]);
|
@@ -3614,38 +4048,13 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
3614
4048
|
*
|
3615
4049
|
* ```css
|
3616
4050
|
* /* normally we would create a CSS class to reference on the element */
|
3617
|
-
*
|
4051
|
+
* greeting-box.on { transition:0.5s linear all; background:green; color:white; }
|
3618
4052
|
* ```
|
3619
4053
|
*
|
3620
4054
|
* The `$animate` service contains a variety of other methods like `enter`, `leave`, `animate` and `setClass`. To learn more about what's
|
3621
4055
|
* possible be sure to visit the {@link ng.$animate $animate service API page}.
|
3622
4056
|
*
|
3623
4057
|
*
|
3624
|
-
* ### Preventing Collisions With Third Party Libraries
|
3625
|
-
*
|
3626
|
-
* Some third-party frameworks place animation duration defaults across many element or className
|
3627
|
-
* selectors in order to make their code small and reuseable. This can lead to issues with ngAnimate, which
|
3628
|
-
* is expecting actual animations on these elements and has to wait for their completion.
|
3629
|
-
*
|
3630
|
-
* You can prevent this unwanted behavior by using a prefix on all your animation classes:
|
3631
|
-
*
|
3632
|
-
* ```css
|
3633
|
-
* /* prefixed with animate- */
|
3634
|
-
* .animate-fade-add.animate-fade-add-active {
|
3635
|
-
* transition:1s linear all;
|
3636
|
-
* opacity:0;
|
3637
|
-
* }
|
3638
|
-
* ```
|
3639
|
-
*
|
3640
|
-
* You then configure `$animate` to enforce this prefix:
|
3641
|
-
*
|
3642
|
-
* ```js
|
3643
|
-
* $animateProvider.classNameFilter(/animate-/);
|
3644
|
-
* ```
|
3645
|
-
*
|
3646
|
-
* This also may provide your application with a speed boost since only specific elements containing CSS class prefix
|
3647
|
-
* will be evaluated for animation when any DOM changes occur in the application.
|
3648
|
-
*
|
3649
4058
|
* ## Callbacks and Promises
|
3650
4059
|
*
|
3651
4060
|
* When `$animate` is called it returns a promise that can be used to capture when the animation has ended. Therefore if we were to trigger
|
@@ -3685,16 +4094,14 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|
3685
4094
|
* @description
|
3686
4095
|
* The ngAnimate `$animate` service documentation is the same for the core `$animate` service.
|
3687
4096
|
*
|
3688
|
-
* Click here {@link ng.$animate
|
4097
|
+
* Click here {@link ng.$animate to learn more about animations with `$animate`}.
|
3689
4098
|
*/
|
3690
4099
|
angular.module('ngAnimate', [])
|
3691
|
-
.directive('
|
4100
|
+
.directive('ngAnimateSwap', ngAnimateSwapDirective)
|
3692
4101
|
|
3693
|
-
.
|
4102
|
+
.directive('ngAnimateChildren', $$AnimateChildrenDirective)
|
3694
4103
|
.factory('$$rAFScheduler', $$rAFSchedulerFactory)
|
3695
4104
|
|
3696
|
-
.factory('$$AnimateRunner', $$AnimateRunnerFactory)
|
3697
|
-
|
3698
4105
|
.provider('$$animateQueue', $$AnimateQueueProvider)
|
3699
4106
|
.provider('$$animation', $$AnimationProvider)
|
3700
4107
|
|