;(function ( $, window, document, undefined ) { /** * animo is a powerful little tool that makes managing CSS animations extremely easy. Stack animations, set callbacks, make magic. * Modern browsers and almost all mobile browsers support CSS animations (http://caniuse.com/css-animation). * * @author Daniel Raftery : twitter/ThrivingKings * @version 1.0.2 */ function animo( element, options, callback, other_cb ) { // Default configuration var defaults = { duration: 1, animation: null, iterate: 1, timing: "linear", keep: false }; // Browser prefixes for CSS this.prefixes = ["", "-moz-", "-o-animation-", "-webkit-"]; // Cache the element this.element = $(element); this.bare = element; // For stacking of animations this.queue = []; // Hacky this.listening = false; // Figure out where the callback is var cb = (typeof callback == "function" ? callback : other_cb); // Options can sometimes be a command switch(options) { case "blur": defaults = { amount: 3, duration: 0.5, focusAfter: null }; this.options = $.extend( defaults, callback ); this._blur(cb); break; case "focus": this._focus(); break; case "rotate": defaults = { degrees: 15, duration: 0.5 }; this.options = $.extend( defaults, callback ); this._rotate(cb); break; case "cleanse": this.cleanse(); break; default: this.options = $.extend( defaults, options ); this.init(cb); break; } } animo.prototype = { // A standard CSS animation init: function(callback) { var $me = this; // Are we stacking animations? if(Object.prototype.toString.call( $me.options.animation ) === '[object Array]') { $.merge($me.queue, $me.options.animation); } else { $me.queue.push($me.options.animation); } $me.cleanse(); $me.animate(callback); }, // The actual adding of the class and listening for completion animate: function(callback) { this.element.addClass('animated'); this.element.addClass(this.queue[0]); this.element.data("animo", this.queue[0]); var ai = this.prefixes.length; // Add the options for each prefix while(ai--) { this.element.css(this.prefixes[ai]+"animation-duration", this.options.duration+"s"); this.element.css(this.prefixes[ai]+"animation-iteration-count", this.options.iterate); this.element.css(this.prefixes[ai]+"animation-timing-function", this.options.timing); } var $me = this, _cb = callback; if($me.queue.length>1) { _cb = null; } // Listen for the end of the animation this._end("AnimationEnd", function() { // If there are more, clean it up and move on if($me.element.hasClass($me.queue[0])) { if(!$me.options.keep) { $me.cleanse(); } $me.queue.shift(); if($me.queue.length) { $me.animate(callback); } } }, _cb); }, cleanse: function() { this.element.removeClass('animated'); this.element.removeClass(this.queue[0]); this.element.removeClass(this.element.data("animo")); var ai = this.prefixes.length; while(ai--) { this.element.css(this.prefixes[ai]+"animation-duration", ""); this.element.css(this.prefixes[ai]+"animation-iteration-count", ""); this.element.css(this.prefixes[ai]+"animation-timing-function", ""); this.element.css(this.prefixes[ai]+"transition", ""); this.element.css(this.prefixes[ai]+"transform", ""); this.element.css(this.prefixes[ai]+"filter", ""); } }, _blur: function(callback) { if(this.element.is("img")) { var svg_id = "svg_" + (((1 + Math.random()) * 0x1000000) | 0).toString(16).substring(1); var filter_id = "filter_" + (((1 + Math.random()) * 0x1000000) | 0).toString(16).substring(1); $('body').append(''); var ai = this.prefixes.length; while(ai--) { this.element.css(this.prefixes[ai]+"filter", "blur("+this.options.amount+"px)"); this.element.css(this.prefixes[ai]+"transition", this.options.duration+"s all linear"); } this.element.css("filter", "url(#"+filter_id+")"); this.element.data("svgid", svg_id); } else { var color = this.element.css('color'); var ai = this.prefixes.length; // Add the options for each prefix while(ai--) { this.element.css(this.prefixes[ai]+"transition", "all "+this.options.duration+"s linear"); } this.element.css("text-shadow", "0 0 "+this.options.amount+"px "+color); this.element.css("color", "transparent"); } this._end("TransitionEnd", null, callback); var $me = this; if(this.options.focusAfter) { var focus_wait = window.setTimeout(function() { $me._focus(); focus_wait = window.clearTimeout(focus_wait); }, (this.options.focusAfter*1000)); } }, _focus: function() { var ai = this.prefixes.length; if(this.element.is("img")) { while(ai--) { this.element.css(this.prefixes[ai]+"filter", ""); this.element.css(this.prefixes[ai]+"transition", ""); } var $svg = $('#'+this.element.data('svgid')); $svg.remove(); } else { while(ai--) { this.element.css(this.prefixes[ai]+"transition", ""); } this.element.css("text-shadow", ""); this.element.css("color", ""); } }, _rotate: function(callback) { var ai = this.prefixes.length; // Add the options for each prefix while(ai--) { this.element.css(this.prefixes[ai]+"transition", "all "+this.options.duration+"s linear"); this.element.css(this.prefixes[ai]+"transform", "rotate("+this.options.degrees+"deg)"); } this._end("TransitionEnd", null, callback); }, _end: function(type, todo, callback) { var $me = this; var binding = type.toLowerCase()+" webkit"+type+" o"+type+" MS"+type; this.element.bind(binding, function() { $me.element.unbind(binding); if(typeof todo == "function") { todo(); } if(typeof callback == "function") { callback($me); } }); } }; $.fn.animo = function ( options, callback, other_cb ) { return this.each(function() { new animo( this, options, callback, other_cb ); }); }; })( jQuery, window, document );