├── AutoAnimations.js
├── LICENSE
├── README.md
└── bower.json
/AutoAnimations.js:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | AUTO ANIMATIONS
4 |
5 | Automatically animate all inserted and removed DOM elements with good defaults:
6 | - Slide down/up for elements with display=block & position=static
7 | - Fade in/out for all others
8 | - Elements with existing CSS transitions or animations will be left alone
9 | - Uses velocity.js to assure smooth 60fps animations
10 |
11 | USAGE: Just include this script and add an animation duration to your css, e.g.
12 |
13 | * { animation-duration: .2s; }
14 |
15 | EXCEPTIONS: If you don't want some element to automatically animate (e.g. external libraries) just set its animation-duration to 0s, e.g. :
16 | .SomeCustomComponent, .SomeCustomComponent * {animation-duration: 0s; }
17 |
18 | */
19 |
20 | (function(){
21 |
22 | // Configuration needed by AutoAnimations. Put it in the CSS instead
23 | //document.styleSheets[0].insertRule("* {animation-duration: .5s}", 0);
24 |
25 | "use strict";
26 | //already loaded exit
27 | if (HTMLElement.prototype._insertBefore) {
28 | return;
29 | }
30 |
31 | // load Velocity.js if needed
32 | var velocityURL = "//cdn.rawgit.com/julianshapiro/velocity/1.2.3/velocity.min.js";
33 |
34 | if (window.Velocity || (window.$ && $.Velocity)) {
35 | AutoAnimations();
36 | } else if (window.require){
37 | require([velocityURL], function (Velocity) {
38 | AutoAnimations();
39 | });
40 | } else {
41 | var xmlhttp = new XMLHttpRequest();
42 | xmlhttp.open("GET", velocityURL);
43 | xmlhttp.onreadystatechange = function(){
44 | if ((xmlhttp.status == 200) && (xmlhttp.readyState == 4)) {
45 | eval(xmlhttp.responseText);
46 | AutoAnimations();
47 | }};
48 | xmlhttp.send();
49 | }
50 |
51 | function AutoAnimations() {
52 |
53 | var Velocity = window.Velocity || $.Velocity;
54 |
55 | // Override native methods (yup, this is hard core)
56 |
57 | HTMLElement.prototype._appendChild = HTMLElement.prototype.appendChild;
58 | HTMLElement.prototype.appendChild = function() {
59 | var result = this._appendChild.apply( this, arguments );
60 | showElement.apply( this, arguments );
61 | return result;
62 | };
63 |
64 | HTMLElement.prototype._insertBefore = HTMLElement.prototype.insertBefore;
65 | HTMLElement.prototype.insertBefore = function() {
66 | var result = this._insertBefore.apply( this, arguments );
67 | showElement.apply( this, arguments );
68 | return result;
69 | };
70 |
71 | HTMLElement.prototype._replaceChild = HTMLElement.prototype.replaceChild;
72 | HTMLElement.prototype.replaceChild = function() {
73 | return swapElements.apply( this, arguments );
74 | };
75 |
76 | HTMLElement.prototype._removeChild = HTMLElement.prototype.removeChild;
77 | HTMLElement.prototype.removeChild = function() {
78 | hideElement.apply( this, arguments );
79 | };
80 |
81 | function showElement(node) {
82 | toggleElement(node, true);
83 | }
84 |
85 | function hideElement(node) {
86 | if (isAnimating(node)) {
87 | // probably we're inside a removechild cycle
88 | if (node.nextElementSibling) {
89 | do {
90 | node = node.nextElementSibling;
91 | } while (node.nextElementSibling && isAnimating(node));
92 | }
93 | if (isAnimating(node)) {
94 | if (node.previousElementSibling) {
95 | do {
96 | node = node.previousElementSibling;
97 | } while (node.previousElementSibling && isAnimating(node));
98 | }
99 | }
100 | }
101 | if (!isAnimating(node)) {
102 | toggleElement(node, false, function(){
103 | if (node.parentNode) {
104 | node.parentNode._removeChild(node);
105 | }
106 | });
107 | }
108 | }
109 |
110 | function isAnimating(node) {
111 | var velocityData = Velocity.Utilities.data(node);
112 | return velocityData && velocityData.velocity && velocityData.velocity.isAnimating;
113 | }
114 |
115 | function swapElements(newChild, oldChild) {
116 | // REACT uses noscript often
117 | if (oldChild.tagName == "NOSCRIPT") {
118 | //treat this as a show
119 | oldChild.parentNode._replaceChild(newChild, oldChild);
120 | toggleElement(newChild, true);
121 | } else if (newChild.tagName == "NOSCRIPT"){
122 | //treat this as a hide
123 | toggleElement(oldChild, false, function() {
124 | if(oldChild.parentNode)
125 | oldChild.parentNode._replaceChild(newChild, oldChild);
126 | });
127 | } else {
128 | oldChild.parentNode._replaceChild(newChild, oldChild);
129 | }
130 | }
131 |
132 | function toggleElement(node, show, onComplete) {
133 | // Do not animate some elements
134 | if (!node.parentNode || node.parentElement.dataset.reactid == ".0"
135 | || node.parentElement.tagName == "HEAD" || node.parentNode.parentNode == null
136 | || !(node instanceof HTMLElement)) {
137 | if (onComplete)
138 | onComplete();
139 | return;
140 | }
141 |
142 | var style = window.getComputedStyle(node);
143 |
144 | // Only animate elements with animation-duration that do not have any
145 | // other animations or transitions properties set
146 | if (style.animationDuration == "0s" || style.transform != "none"
147 | || style.animationName != "none" || style.transitionDuration != "0s" ) {
148 | if (onComplete)
149 | onComplete();
150 | return;
151 | }
152 | var animationProperties = {
153 | duration: parseFloat(style.animationDuration) * 1000,
154 | complete: onComplete,
155 | display: style.display //keep display value
156 | };
157 |
158 | //inline, inline-block fixed and absolute will fade instead of slide
159 | if (style.position != "static" || style.float != "none" || style.display.indexOf("inline") != -1) {
160 | if (show) {
161 | node.style.display = 'none';
162 | Velocity.Redirects.fadeIn(node, animationProperties);
163 | } else {
164 | Velocity.Redirects.fadeOut(node, animationProperties);
165 | }
166 | } else {
167 | if (show) {
168 | node.style.display = 'none';
169 | Velocity.Redirects.slideDown(node, animationProperties);
170 | } else {
171 | Velocity.Redirects.slideUp(node, animationProperties);
172 | }
173 | }
174 | }
175 | }
176 | })();
177 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 tiagosimoes
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AutoAnimations
2 | _"It's like auto-tune for web pages"_
3 |
4 | Automatically animate all inserted and removed DOM elements with good defaults:
5 | - Slide down/up for elements with display=block & position=static
6 | - Fade in/out for all others
7 | - Elements with existing CSS transitions or animations will be left alone
8 | - Uses velocity.js to assure smooth 60fps animations even in mobile
9 |
10 |
11 |
12 |
13 | compare with http://todomvc.com/examples/react/ (that has no autoanimate)
14 |
15 | ##USAGE
16 | Just include this script, and add an animation-duration to your css, e.g.
17 |
18 |
* { 19 | animation-duration: .2s; 20 | }21 | 22 | ####NOTES 23 | - Elements shown/hidden using the style's display (e.g. jquery's show, hide and toggle) will not be animated. 24 | - In javascript UI frameworks (e.g. React) it's recommended that this script is run after first render 25 | - You can add this as the URL of a bookmark to create a bookmarklet to test it in any web page: 26 | -
javascript:(function(){document.styleSheets[0].insertRule("* {animation-duration: .2s}", 0);document.body.appendChild(document.createElement('script')).src='https://rawgit.com/OutSystems/AutoAnimations/master/AutoAnimations.js';})();27 | - This overrides HTMLElement prototype methods, so it's a huge hack (only a POC) and there might be several side effects. 28 | 29 | ####EXCEPTIONS 30 | If you don't want some element to automatically animate (e.g. external libraries) just set its animation-duration to 0s, e.g. : 31 |
.SomeCustomComponent, .SomeCustomComponent * {animation-duration: 0s; }32 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "auto-animations", 3 | "main": "AutoAnimations.js", 4 | "homepage": "https://github.com/OutSystems/AutoAnimations", 5 | "authors": [ 6 | "tiagosimoes" 7 | ], 8 | "description": "Automatically animate all inserted and removed DOM elements", 9 | "moduleType": [], 10 | "keywords": [ 11 | "auto", 12 | "animation", 13 | "velocity", 14 | "automatic" 15 | ], 16 | "license": "MIT", 17 | "ignore": [ 18 | "**/.*", 19 | "node_modules", 20 | "bower_components", 21 | "test", 22 | "tests" 23 | ] 24 | } 25 | --------------------------------------------------------------------------------