views:

1234

answers:

2

I have a div where when I hover over it I have a child div (another div) to animate, but when I hover over the child div, the parent div loses focus and the child element starts animating back as if I left the parent div.

Here is the code I am using:

$$(".slide .item").each(function (element) {
 element.observe('mouseover', function (event) {
  element.writeAttribute('doing_animation', 'true');
  element.down('.meta').morph('margin: 103px 0 0;', {
   duration: 0.25,
   afterFinish: function (event) {
    element.writeAttribute('doing_animation', 'false');
   }
  });
 });
 element.observe('mouseout', function (event) {
  setTimeout(function () {
   element.down('.meta').morph('margin: 169px 0 0;', {
    duration: 0.25
   });
  }, 250);
 });
});

And here is the markup:

<div class="item">
 <div class="meta">
  <h3><a href="#">Space Kitty Needz Moar Balls</a></h3>
  <ul>
   <li>From: <a href="#">Jeffdoe</a></li>
   <li>Posted: 20 minutes ago</li>
   <li>Views: 249,209</li>
  </ul>
 </div>
 <img src="images/tmp/kitty.png" alt="" />
</div>

So with the code, I would like to hover .item OR .item .meta and the .meta div will still control focus of the .item div. I know jQuery does a better job with this, but I need to use Prototype.

Thanks!

A: 

The easiest solution is probably to add mouseover listener to .item. children and clear the mouseout timeout in it. Code below is for illustration only - it's untested and the variable should, of course, be appropriately scoped:

var timeout = null;

$$(".slide .item").each(function (element) {
    element.observe('mouseout', function (event) {
        timeout = setTimeout(function () {
            ...
        }, 250);
    });

    element.descendants().each(function (nested) { 
        nested.observe('mouseover', function (nestedEvent) {
            if (timeout) clearTimeout(timeout);
        });
    });
});
ChssPly76
+4  A: 

Here's how I'd do it:

$$(".slide .item").each(function (element) {
    element.observe('mouseover', function (event) {
     var relatedTarget = $(event.relatedTarget || event.fromElement);
     var target = Event.element(event);
     if ((target == element || Element.descendantOf(target, element))
      && !((relatedTarget == element) || Element.descendantOf(relatedTarget, element)))
     {
      element.writeAttribute('doing_animation', 'true');
      element.down('.meta').morph('margin: 103px 0 0;', {
       duration: 0.25,
       afterFinish: function (event) {
        element.writeAttribute('doing_animation', 'false'); 
       }
      });
     }
    });
    element.observe('mouseout', function (event) {
     var relatedTarget = $(event.relatedTarget || event.fromElement);
     var target = Event.element(event);
     if ((target == element || Element.descendantOf(target, element))
      && !((relatedTarget == element) || Element.descendantOf(relatedTarget, element)))
     {
      setTimeout(function () {
       element.down('.meta').morph('margin: 169px 0 0;', {
        duration: 0.25
       });
      }, 250);
     }
    });
});

You can see I've just added a wrapper

 var relatedTarget = $(event.relatedTarget || event.fromElement);
 var target = Event.element(event);
 if ((target == element || Element.descendantOf(target, element))
  && !((relatedTarget == element) || Element.descendantOf(relatedTarget, element)))
 {
  ...
 }

around your event handlers. So, only consider it a "real" mouse-in or mouse-out if we're really moving in or out of the parent container.

Hope that helps.

edsoverflow
This answer was really helpful for me, thanks!
Michael Robinson