/* * Copyright 2012 Andrey “A.I.” Sitnik , * sponsored by Evil Martians. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ ;(function($) { "use strict"; // Common methods and properties for jQuery Transition Events plugin. // Mostly for internal usage, but maybe helpful for some hack stuff: // // if ( $.Transitions.isSupported() ) { // // CSS Transitions is supported // } $.Transitions = { // Hash of property name to event name with vendor prefixes. // It is used to detect prefix. _names: { // Webkit must be on bottom, because Opera try to use webkit // prefix. 'transition': 'transitionend', 'OTransition': 'oTransitionEnd', 'WebkitTransition': 'webkitTransitionEnd', 'MozTransition': 'transitionend' }, // Return array of milliseconds for CSS value of `transition-duration`. // It’s used in `$.fn.afterTransition`. _parseTimes: function (string) { var value, array = string.split(/,\s*/); for (var i = 0; i < array.length; i++) { value = array[i]; array[i] = parseFloat(value); if ( value.match(/\ds/) ) { array[i] = array[i] * 1000; } } return array; }, // Autodetect vendor prefix and return `transitionend` event name. // // If browser didn’t support CSS Transitions it will return `false`. getEvent: function () { var finded = false; for ( var prop in this._names ) { if ( typeof(document.body.style[prop]) != 'undefined' ) { finded = this._names[prop]; break; } } this.getEvent = function () { return finded; }; return finded; }, // Alias to vendor prefixed `requestAnimationFrame`. Will be replace // by native function after first call. animFrame: function (callback) { var raf = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame; if ( raf ) { this.animFrame = function (callback) { return raf.call(window, callback); }; } else { this.animFrame = function (callback) { return setTimeout(callback, 10); }; } return this.animFrame(callback); }, // Return `true` if browser support CSS Transitions. isSupported: function () { return this.getEvent() !== false; } } // jQuery node methods. $.extend($.fn, { // Call `callback` after CSS Transition finish // `delay + (durationPart * duration)`. It will call `callback` only // once, in difference from `transitionEnd`. // // $('.show-video').click(function () { // $('.slider').addClass('video-position').afterTransition( // function () { autoPlayVideo(); }); // }); // // You can set `durationPart` to call `callback` in the middle of // transition: // // $('.fliper').addClass('rotate').afterTransition(0.5, function () { // $(this).find('.backface').show(); // }); // // Callback will get object with `propertyName` and `elapsedTime` // properties. If transition is set to difference properties, it will // be called on every property. // // This method doesn’t check, that transition is really finished (it can // be canceled in the middle). afterTransition: function (durationPart, callback) { if ( typeof(callback) == 'undefined' ) { callback = durationPart; durationPart = 1; } if ( !$.Transitions.isSupported() ) { for (var i = 0; i < this.length; i++) { callback.call(this[i], { type: 'aftertransition', elapsedTime: 0, propertyName: '', currentTarget: this[i] }); } return this; } for (var i = 0; i < this.length; i++) { var el = $(this[i]); var props = el.css('transition-property').split(/,\s*/); var durations = el.css('transition-duration'); var delays = el.css('transition-delay'); durations = $.Transitions._parseTimes(durations); delays = $.Transitions._parseTimes(delays); var prop, duration, delay, after, elapsed; for (var j = 0; j < props.length; j++) { prop = props[j]; duration = durations[ durations.length == 1 ? 0 : j ]; delay = delays[ delays.length == 1 ? 0 : j ]; after = delay + (duration * durationPart); elapsed = duration * durationPart / 1000; (function (el, prop, after, elapsed) { setTimeout(function () { $.Transitions.animFrame(function () { callback.call(el[0], { type: 'aftertransition', elapsedTime: elapsed, propertyName: prop, currentTarget: el[0] }); }); }, after); })(el, prop, after, elapsed); } } return this; }, // Set `callback` to listen every CSS Transition finish. // It will call `callback` on every finished transition, // in difference from `afterTransition`. // // It just bind to `transitionend` event, but detect vendor prefix. // // Callback will get event object with `propertyName` and `elapsedTime` // properties. If transition is set to difference properties, it will // be called on every property. // // Note, that `callback` will get original event object, not from // jQuery. // // var slider = $('.slider').transitionEnd(function () { // if ( slider.hasClass('video-position') ) { // autoPlayVideo(); // } // }); // // $('.show-video').click(function () { // slider.addClass('video-position'); // }); // // If transition will be canceled before finish, event won’t be fired. transitionEnd: function (callback) { for (var i = 0; i < this.length; i++) { this[i].addEventListener($.Transitions.getEvent(), function (e) { callback.call(this, e); }); } return this; } }); }).call(this, jQuery);