I need to detect if a CSS transition is completed before allowing a function to repeat again, to prevent messing up the margins.
So how cam I have something like
I noticed such similar questions like "how do I catch touchend events?" or "mouseup events?" etc.
They are all similar for these points of view
plural: handlers are fired many times even when we are expecting to be fired by a single event
depth: events are bubbling deeper in the tree before our handler catches them.
Examples:
a touchstart can be followed by a mousedown and vice versa in a device that has both a mouse and a touch screen,
a touchend can be followed by a mouseup for the similar reasons,
a animationstart can be followed by many other similar events depending on how you wrote the css,
a animationend can also be followed by many similar events for the above reasons as well.
If we need to fire our handler once per a set of similar events, i.e. events that produced by a single action like a person that presses sth. we need to introduce an event lock and use 2 handlers one at the beginning of an event and one handler at the end even if we don't need or want a handler of the side event.
The lock can be a property at the parent node higer in the tree as you guessed.
For the infamous event couple: animationstart - animationend such a function can be:
var oneTransition = (function(){
var $parent,
type,
callback,
unlockCallback,
newCallback,
start = 'webkitTransitionStart otransitionstart oTransitionStart msTransitionStart transitionstart',
end = 'webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend';
unlockCallback = function(){
$parent.data('oneTransitionLock', false);
};
newCallback = function(e){
if($parent.data('oneTransitionLock'))
return;
else
$parent.data('oneTransitionLock', true);
callback(e);
};
return function(){
var args = Array.prototype.slice.call(arguments, 0);
$parent = $(args[0]); // 1st arg
type = args[1]; // 2nd arg
callback = args[2]; // 3rd arg
if((args.length < 3) || ((type != 'start') && (type != 'end')) || (typeof(callback) != 'function'))
return;
$parent.off(start).off(end);
if(type == 'start'){
$parent.data('oneTransitionLock', false);
$parent.on(start, newCallback);
$parent.on(end, unlockCallback);
}else if(type == 'end'){
$parent.on(start, unlockCallback);
$parent.on(end, newCallback);
}
}
})();
and you can call it like:
oneTransition(node, 'start' or 'end', funcion(){...});
The interesting part is that it can runs for either the start or the end of animation:
1st arg. a node reference,
2nd arg. a string representing the event for our callback and
3rd arg. our actual callback.
jsFiddle