213 lines
7.9 KiB
JavaScript
213 lines
7.9 KiB
JavaScript
/*
|
||
* Copyright 2012 Andrey “A.I.” Sitnik <andrey@sitnik.ru>,
|
||
* 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 <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
;(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);
|