OLD | NEW |
(Empty) | |
| 1 part of angular.animate; |
| 2 |
| 3 /** |
| 4 * This defines the standard set of CSS animation classes, transitions, and |
| 5 * nomenclature that will eventually be the foundation of the AngularDart |
| 6 * animation framework. This implementation uses the [AnimationLoop] class to |
| 7 * queue and run CSS based transition and keyframe animations. |
| 8 */ |
| 9 @Injectable() |
| 10 class CssAnimate implements Animate { |
| 11 static const NG_ANIMATE = "ng-animate"; |
| 12 static const NG_MOVE = "ng-move"; |
| 13 static const NG_INSERT = "ng-enter"; |
| 14 static const NG_REMOVE = "ng-leave"; |
| 15 |
| 16 static const NG_ADD_POSTFIX = "-add"; |
| 17 static const NG_REMOVE_POSTFIX = "-remove"; |
| 18 static const NG_ACTIVE_POSTFIX = "-active"; |
| 19 |
| 20 final NoOpAnimation _noOp = new NoOpAnimation(); |
| 21 |
| 22 final AnimationLoop _runner; |
| 23 final AnimationOptimizer _optimizer; |
| 24 final CssAnimationMap _animationMap; |
| 25 |
| 26 CssAnimate(this._runner, this._animationMap, this._optimizer); |
| 27 |
| 28 Animation addClass(dom.Element element, String cssClass) { |
| 29 if (!_optimizer.shouldAnimate(element)) { |
| 30 element.classes.add(cssClass); |
| 31 return _noOp; |
| 32 } |
| 33 |
| 34 cancelAnimation(element, "$cssClass$NG_REMOVE_POSTFIX"); |
| 35 var event = "$cssClass$NG_ADD_POSTFIX"; |
| 36 return animate(element, event, addAtEnd: cssClass); |
| 37 } |
| 38 |
| 39 Animation removeClass(dom.Element element, String cssClass) { |
| 40 if (!_optimizer.shouldAnimate(element)) { |
| 41 element.classes.remove(cssClass); |
| 42 return _noOp; |
| 43 } |
| 44 |
| 45 cancelAnimation(element, "$cssClass$NG_ADD_POSTFIX"); |
| 46 |
| 47 var event = "$cssClass$NG_REMOVE_POSTFIX"; |
| 48 return animate(element, event, removeAtEnd: cssClass); |
| 49 } |
| 50 |
| 51 Animation insert(Iterable<dom.Node> nodes, dom.Node parent, |
| 52 { dom.Node insertBefore }) { |
| 53 util.domInsert(nodes, parent, insertBefore: insertBefore); |
| 54 |
| 55 var animations = util.getElements(nodes) |
| 56 .where((el) =>_optimizer.shouldAnimate(el)) |
| 57 .map((el) => animate(el, NG_INSERT)); |
| 58 |
| 59 return _animationFromList(animations); |
| 60 } |
| 61 |
| 62 Animation remove(Iterable<dom.Node> nodes) { |
| 63 var animations = nodes.map((node) { |
| 64 if (node.nodeType == dom.Node.ELEMENT_NODE && |
| 65 _optimizer.shouldAnimate(node)) { |
| 66 return animate(node, NG_REMOVE); |
| 67 } |
| 68 return _noOp; |
| 69 }); |
| 70 |
| 71 var result = _animationFromList(animations)..onCompleted.then((result) { |
| 72 if (result.isCompleted) nodes.toList().forEach((n) => n.remove()); |
| 73 }); |
| 74 |
| 75 return result; |
| 76 } |
| 77 |
| 78 Animation move(Iterable<dom.Node> nodes, dom.Node parent, |
| 79 { dom.Node insertBefore }) { |
| 80 util.domMove(nodes, parent, insertBefore: insertBefore); |
| 81 |
| 82 var animations = util.getElements(nodes) |
| 83 .where((el) => _optimizer.shouldAnimate(el)) |
| 84 .map((el) => animate(el, NG_MOVE)); |
| 85 |
| 86 return _animationFromList(animations); |
| 87 } |
| 88 |
| 89 /** |
| 90 * Run a css animation on a element for a given css class. If the css |
| 91 * animation already exists, the method will attempt to return the existing |
| 92 * instance. |
| 93 */ |
| 94 CssAnimation animate( |
| 95 dom.Element element, |
| 96 String event, |
| 97 { String addAtStart, |
| 98 String addAtEnd, |
| 99 String removeAtStart, |
| 100 String removeAtEnd }) { |
| 101 |
| 102 var _existing = _animationMap.findExisting(element, event); |
| 103 if (_existing != null) return _existing; |
| 104 |
| 105 var animation = new CssAnimation( |
| 106 element, |
| 107 event, |
| 108 "$event$NG_ACTIVE_POSTFIX", |
| 109 addAtStart: addAtStart, |
| 110 addAtEnd: addAtEnd, |
| 111 removeAtStart: removeAtStart, |
| 112 removeAtEnd: removeAtEnd, |
| 113 animationMap: _animationMap, |
| 114 optimizer: _optimizer); |
| 115 |
| 116 _runner.play(animation); |
| 117 return animation; |
| 118 } |
| 119 |
| 120 /** |
| 121 * For a given element and css event, attempt to find an existing instance |
| 122 * of the given animation and cancel it. |
| 123 */ |
| 124 void cancelAnimation(dom.Element element, String event) { |
| 125 var existing = _animationMap.findExisting(element, event); |
| 126 |
| 127 if (existing != null) existing.cancel(); |
| 128 } |
| 129 } |
| 130 |
| 131 /** |
| 132 * Tracked set of currently running css animations grouped by element. |
| 133 */ |
| 134 @Injectable() |
| 135 class CssAnimationMap { |
| 136 final Map<dom.Element, Map<String, CssAnimation>> cssAnimations |
| 137 = new Map<dom.Element, Map<String, CssAnimation>>(); |
| 138 |
| 139 void track(CssAnimation animation) { |
| 140 var animations = cssAnimations.putIfAbsent(animation.element, |
| 141 () => <String, CssAnimation>{}); |
| 142 animations[animation.eventClass] = animation; |
| 143 } |
| 144 |
| 145 void forget(CssAnimation animation) { |
| 146 var animations = cssAnimations[animation.element]; |
| 147 animations.remove(animation.eventClass); |
| 148 if (animations.length == 0) cssAnimations.remove(animation.element); |
| 149 } |
| 150 |
| 151 CssAnimation findExisting(dom.Element element, String event) { |
| 152 var animations = cssAnimations[element]; |
| 153 if (animations == null) return null; |
| 154 return animations[event]; |
| 155 } |
| 156 } |
OLD | NEW |