I would like to bump a menu item out 5px on mouseover and have it return to its original position using Scriptaculous. I am using the afterFinish callback to ensure that the bump-out Move effect is completed before the bump-back-in Move effect runs.
The problem is that the item doesn't return to its original position if you quickly mouseover and mouseout more than once. The more you mouseover-and-out, the more it's off. I thought this is what the afterFinish callback was supposed to prevent. It seems to work correctly with the Morph effect, and it's supposed to work with all Scriptaculous effects, as stated below:
Javascript - Scriptaculous - Effect Callback function
I've tried using effects queues, same result, and spent several hours scouring various forums to help me understand this.
Here is the Morph example that works correctly:
<SCRIPT>
function morphMe(obj) {
new Effect.Morph($(obj), {
style: {
height: '200px',
width: '200px'},
afterFinish: function(){ new Effect.Morph($(obj), {
style: {
height: '20px',
width: '200px'}});
}
})
}
</SCRIPT>
<div id="bumptest" class="leftnav" style="position: absolute; left: 100px; width: 200px; border: 1px solid green" onmouseover="morphme(this);">Morph Me</div>
Here's the Move example that doesn't work as expected on quick mouseover and outs. Perhaps I need use setTimeout but I don't understand why this should be necessary.
<SCRIPT>
function OnFinish(obj){
new Effect.Move(obj.element.id, {x: -5, y: 0, duration: .4});
}
function bumpOut(myObject){
new Effect.Move(myObject,
{ x: 5,
y: 0,
duration: 0.4,
afterFinish: OnFinish,
});
}
</SCRIPT>
<div id="bumptest" class="leftnav" style="position: absolute; left: 100px; width: 200px; border: 1px solid green" onmouseover="bumpOut(this);">Bump me right and then back</div>
Any help, maybe even a mod using setTimeout or a pointer to a solid script that already does this, greatly appreciated.
Thanks,
motorhobo
You'll need to think parallel: the problem occurs when several effects are running at the same time. Actually, it's because of the way that scriptacoulous handles effects: it calculates the target position at creation time of the effect.
The following scenario doesn't take afterFinish into account:
(The same reasoning applies to highlight(): If you highlight several times at once, the background color doesn't revert to the original one. Also applies to: Scale, BlindDown/Up, and some others.)
The solution to this is to give absolute values at every call:
$(this).morph({left:106px}); // etc.
Queues are another part of the solution. When bumpOut
is called, make sure that any OnFinish-Effect is cancelled - otherwise the position of the box will flicker. More validity checks may be necessary to make sure that:
A third roadblock: mouseover is triggered also when a child element of bumptest
(even a <b>
!) is hovered, so much more often than you'd normally expect. Use mouseenter / mouseleave if you want to get the event of entering / leaving bumptest
only once.