/*!
* Trend 0.2.0
*
* Fail-safe TransitionEnd event for jQuery.
*
* Adds a new "trend" event that can be used in browsers that don't
* support "transitionend".
*
* NOTE: Only supports being bound with "jQuery.one".
*
* Copyright 2014, Pixel Union - http://pixelunion.net
* Released under the MIT license
*/
;(function($){
// Prefixed transitionend event names
var transitionEndEvents =
"webkitTransitionEnd " +
"otransitionend " +
"oTransitionEnd " +
"msTransitionEnd " +
"transitionend";
// Prefixed transition duration property names
var transitionDurationProperties = [
"transition-duration",
"-moz-transition-duration",
"-webkit-transition-duration",
"-ms-transition-duration",
"-o-transition-duration",
"-khtml-transition-duration"
];
// Prefixed transition delay property names
var transitionDelayProperties = [
"transition-delay",
"-moz-transition-delay",
"-webkit-transition-delay",
"-ms-transition-delay",
"-o-transition-delay",
"-khtml-transition-delay"
];
// Parses a CSS time value into milliseconds.
var parseTime = function(s) {
s = s.replace(/\s/, "");
var v = window.parseFloat(s);
return s.match(/[^m]s$/i)
? v * 1000
: v;
};
// Parses the longest time unit found in a series of CSS properties.
// Returns a value in milliseconds.
var parseProperties = function(el, properties) {
var duration = 0;
for (var i = 0; i < properties.length; i++) {
// Get raw CSS value
var value = el.css(properties[i]);
if (!value) continue;
// Multiple transitions--pick the longest
if (value.indexOf(",") !== -1) {
var values = value.split(",");
var durations = (function(){
var results = [];
for (var i = 0; i < values.length; i++) {
var duration = parseTime(values[i]);
results.push(duration);
}
return results;
})();
duration = Math.max.apply(Math, durations);
}
// Single transition
else {
duration = parseTime(value);
}
// Accept first vaue
break;
}
return duration;
};
$.event.special.trend = {
// Triggers an event handler when an element is done transitioning.
//
// Handles browsers that don't support transitionend by adding a
// timeout with the transition duration.
add: function(handleObj) {
var el = $(this);
var fired = false;
// Mark element as being in transition
el.data("trend", true);
// Calculate a fallback duration. + 20 because some browsers fire
// timeouts faster than transitionend.
var time =
parseProperties(el, transitionDurationProperties) +
parseProperties(el, transitionDelayProperties) +
20;
var cb = function(e) {
// transitionend events can be sent for each property. Let's just
// skip all but the first. Also handles the timeout callback.
if (fired) return;
// Child elements that also have transitions can be fired before we
// complete. This will catch and ignore those. Unfortunately, we'll
// have to rely on the timeout in these cases.
if (e && e.srcElement !== el[0]) return;
// Mark element has not being in transition
el.data("trend", false);
// Callback
fired = true;
if (handleObj.handler) handleObj.handler();
};
el.one(transitionEndEvents, cb);
el.data("trend-timeout", window.setTimeout(cb, time));
},
remove: function(handleObj) {
var el = $(this);
el.off(transitionEndEvents);
window.clearTimeout(el.data("trend-timeout"));
}
};
})(jQuery);