├── 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 | --------------------------------------------------------------------------------