Opened 11 years ago

Closed 8 years ago

Last modified 8 years ago

#6362 closed defect (fixed)

mouseenter/mouseleave target doesn't match connected node

Reported by: guest Owned by: sjmiles
Priority: high Milestone: 1.7
Component: Events Version: 1.0
Keywords: Cc: ole.ersoy@…, Eugene Lazutkin, Kris Zyp
Blocked By: Blocking:

Description (last modified by bill)

Hi,

I hooked up a "fading" event handlers for onmouseenter and onmouseleave on a div element element in firefox 2.0. I'm expecting the element, and all child elements to fadeIn when the when onmouseenter is fired, and fade out when onmouseleave is fired.

The result is mixed, depending on what angle the mouse enters and leaves from. I think that means there's a bug, unless I misunderstood onmouseenter and onmouseleave, as written up here:

http://www.quirksmode.org/js/events_mouse.html

Here's the test that shows this:

    <script type="text/javascript">
        dojo.require("doh.runner");

        dojo.addOnLoad(function()
        {
            doh.register("Tests",
                [
                    {
                        setUp: function()
                        {
                        },
                        name: "Test OnMouseEnter And Leave",
                        runTest: function()
                        {
                           var handleMouseLeaveEvent = function(mouseLeaveEvent)
                           {
                               var node = mouseLeaveEvent.target;
                                
                                   dojo._fade(
                                   {
                                       node: node, 
                                       duration: 500, 
                                       end: 0.6
                                   }).play(5);
                                   mouseLeaveEvent.stopPropagation();
                           }

                           var handleMouseEnterEvent = function(mouseEnterEvent)
                           {
                               var node = mouseEnterEvent.target;
                                
                                   dojo._fade(
                                   {
                                       node: node, 
                                       duration: 500, 
                                       end: 1
                                   }).play(5);
                               mouseEnterEvent.stopPropagation();
                           }

                           dojo.connect(dojo.byId('item4'),
                                   'onmouseenter',
                                   handleMouseEnterEvent);

                           dojo.connect(dojo.byId('item4'),
                                   'onmouseleave',
                                   handleMouseLeaveEvent);
                        }
                    },
                ]
            );
            doh.run();
        });
    </script>
</head>
<body id="body">
        <div id="item4" 
             style="opacity: 0.5">
             This should fade in  
             <p>And this should fade In Too 
             <i>together with this</i> 
             and this, and we should all fade out at the same time</p>
        </div>
</body>
</html>

As can be seen the fading behavior is different depending on where the mouse enters and leaves. I think it's supposed to be the same. Another interesting thing is that if the div element is setup like this:

        <div id="item4" 
             style="opacity: 0.5">
             This should fade in  
             <p>And this should fade In Too 
             <i>together with this</i> 
             and this, and we should all fade out at the same time</p>
             And if I add some more text outside of the paragraph element, this is true.
        </div>

The test works as expected...except for when the cursor exits the node area to the right...

Thoughts?

Cheers,

  • Ole

Attachments (1)

mouseenter.html (1.2 KB) - added by bill 8 years ago.
working test case

Download all attachments as: .zip

Change History (11)

comment:1 Changed 11 years ago by guest

Actually scratch the last comment that goes like this:

"...except for when the cursor exits the node area to the right..."

The element extends all the way across my screen, so I the cursor never exited.

comment:2 Changed 11 years ago by guest

I did a little more research on this, and found the following link which I think does a good job of explaining this a little further:

http://blog.stchur.com/2007/03/15/mouseenter-and-mouseleave-events-for-firefox-and-other-non-ie-browsers/

I hooked up the event handlers to parent elements containing child elements and expected the parent and child elements to fade in when the mouse goes over the parent or children of the parent, and fade out when the mouse leaves.

This is because any event bubbling up from the kids should be ignored by the event handlers. However as the test shows, the event handler is acting on nodes that corresponding to the child elements. This means that the event handler is catching bubbled events. It is also not catching mouseleave events, depending on how the mouse exists the parent element. It seems that if the child element overlaps with the parent element, then mouseleave event is not handled.

comment:3 Changed 11 years ago by guest

I tried implementing an event handler for onmouseleave events manually. The way I did it is check whether the mouse is inside the element receiving the event, and if it is, then the event should be ignored. So I have a method like this:

isMouseInsideElementNode: function(mouseOutEvent, component) {

var boxDimensions = dojo.coords(component.domNode); var absoluteCoordinates = dojo._abs(component.domNode); var mouseX = mouseOutEvent.pageX; var mouseY = mouseOutEvent.pageY;

var boxBottomCoordinate = absoluteCoordinates.y + boxDimensions.h; var boxRightCoordinate = absoluteCoordinates.x + boxDimensions.w;

var belowTopOfBox = mouseY > boxDimensions.t; var aboveBottomOfBox = mouseY < boxBottomCoordinate; var leftOfRightBoxSide = mouseX < boxRightCoordinate; var rightOfLeftBoxSide = mouseX > boxDimensions.l;

if (

belowTopOfBox && aboveBottomOfBox && leftOfRightBoxSide && rightOfLeftBoxSide) {

return true;

}

console.debug("Box TOP: " + boxDimensions.t); console.debug("Box BOTTOM: " + boxBottomCoordinate); console.debug("Box LEFT: " + boxDimensions.l); console.debug("Box RIGHT: " + boxRightCoordinate); console.debug("MOUSE X: " + mouseX); console.debug("MOUSE Y " + mouseY);

return false;

}

It works when there is only a single element inside the body. When the target element receiving the event is nested inside several other elements, it stops working. So it seems like dojo_abs must be off in calculating the absolute top and left coordinates of the element. If these are off slightly the event notification will not happen in certain cases because the browser it no longer notifying the element of mouse out events, so these don't get a chance to be interpreted as mouseleave events. I'm assuming this is the core issue with the mouseleaveevent support.

comment:4 Changed 11 years ago by guest

Well - Scratch that last thought about dojo._abs being off. I tried reimplementing it like this:

calculateOffset: function(/*DOMNode*/ node) {

var calculatedLeft = 0; var calculatedTop = 0;

if (node.offsetParent) {

do {

calculatedLeft += node.offsetLeft; calculatedTop += node.offsetTop;

} while (node = node.offsetParent)

} var offset = new Object(); offset.x = calculatedLeft; offset.y = calculatedTop; return offset;

}

And both return the same result.

I even tried narrowing the box that I'm checking to see whether the mouse is in, in order to determine if the mouse has left the node like this:

var belowTopOfBox = mouseY > boxDimensions.t + 50; var aboveBottomOfBox = mouseY < boxBottomCoordinate - 50; var leftOfRightBoxSide = mouseX < boxRightCoordinate - 50; var rightOfLeftBoxSide = mouseX > boxDimensions.l + 50;

if (

belowTopOfBox && aboveBottomOfBox && leftOfRightBoxSide && rightOfLeftBoxSide) {

return true;

}

The event notification still does not succeed when the node contains other elements that are within it, but on top of it in certain areas. So if the mouse leaves where no other element is occupying real estate, then the event notification takes place, but if another element is sitting on top of the path the mouse is taking when it leaves, the event notification does not succeed. Strange.

comment:5 Changed 11 years ago by guest

Few more notes:

For the last test "Experiment" I also had an image contained inside the element that I wanted to trigger onmouseover and onmouseout events on. Firefox behaves differently when there is an image present.

I tested this by removing the image and seeing whether I would still get a mouse out if the containing elmenet was completely covered by a child element. Mouse outs do get triggered still. However if the containing element contain an image, the image blocks mouse out events. In my case I set the padding-top of the containing element to 20px and so the image was indented 20px from the top of the element. When moving the mouse over the image and out toward the top of the browser, the mouse out never gets triggered. THe presence of the image seems to have "Infected" how firefox behaves with respect to mouse out dispatching WRT text contained in the same node as the node containing the image.

So, right now I'd say that the original comment with the fade in and out behavior is a valid bug for dojo to consider, and the other comments are for firefox to consider....

Cheers,

  • Ole

comment:6 Changed 11 years ago by dylan

Milestone: future

comment:7 Changed 11 years ago by bill

Component: GeneralEvents
Description: modified (diff)
Owner: changed from anonymous to sjmiles

Just fixing formatting. FYI in the future please attach testcases using "attach file" button.

comment:8 Changed 11 years ago by Eugene Lazutkin

Cc: Eugene Lazutkin added

comment:9 Changed 8 years ago by bill

Cc: Kris Zyp added
Milestone: future1.7
Resolution: fixed
Status: newclosed
Summary: Event: onmouseenter and onmouseleave support bug?mouseenter/mouseleave target doesn't match connected node

I checked against the new event code. evt.target often does not match the connected node, and also the targets of the mouse.enter and mouse.leave events don't match each other.

But, that's what the "this" pointer in your event callback is for, to tell you which node matched the selector. So I believe this is how Kris intended it to work.

See attached testcase where this is working using the this pointer in the handler to get the node.

Marking this as fixed with the new dojo/on module.

Changed 8 years ago by bill

Attachment: mouseenter.html added

working test case

comment:10 Changed 8 years ago by bill

#7504 is a duplicate of this ticket.

Note: See TracTickets for help on using tickets.