I'd like some Javascript code to run when the mouse leaves the browser window. I only need to support Safari (WebKit.)
I tried putting a mouseout handler on window. That handler is reliably called when the mouse leaves the browser window. But because of bubbling it is also called when the mouse moves between elements in the document. I can't figure out how to determine when the mouse has actually left the window and when it has only moved between elements.
When the mouse leaves the window, exactly one event is generated, and the target element appears to be the element the mouse was actually over. So checking to see if the target element is window or document doesn't work. And wrapping the whole page in an invisible containing div doesn't work either: if the div is invisible, then the mouse will never be over it, so nothing changes.
(The same thing happens if I put the handler on document or document.body, except that surprisingly document.body does not get mouseover/mouseout events when the mouse enters or leaves an empty part of the window, such as the empty vertical space created by absolutely positioning an element with bottom:0. For that space, document and window will get mouseover/mouseout events with the target being <html>, but document.body will not.)
Some ideas I had:
We use prototype.js so ideally I'd like to express the solution in terms of prototype's Event.observe, but I can figure that part out.
Thanks for any suggestions!
The mouseout event is fired at an Element when a pointing device (usually a mouse) is used to move the cursor so that it is no longer contained within the element or one of its children.
The mouseover event triggers when the mouse pointer enters the div element, and its child elements. The mouseenter event is only triggered when the mouse pointer enters the div element.
The mouseover event occurs when a mouse pointer comes over an element, and mouseout – when it leaves. These events are special, because they have property relatedTarget .
SUMMARY: This can be done cleanly by checking the relatedTarget property during the mouseout event. If relatedTarget is not a child of document, then the mouse just left the window. It's easy to do yourself, but if you don't want to, some libraries (Mootools, future Prototype..) have baked-in functionality, and others (current Prototype) have extensions available. On IE, you could instead use mouseleave, which is a non-bubbling version of mouseout.
Details:
IE has events called mouseenter and mouseleave that are non-bubbling versions of mouseover and mouseout. Other browsers do not, but if they did, setting a mouseleave listener on window or document would do the trick.
A gentleman named Ken Snyder comes to the rescue:
On a mouseover, the relatedTarget property references the node from which the pointer came. On a mouseout, the relatedTarget property references the node to which the pointer went.On any event, the scope is the node to which the event is attached.When the relatedTarget is a not child of the currentTarget, a mouseover event is equivalent to a mouseenter event and a mouseout event is equivalent to a mouseleave event.
-- http://kendsnyder.com/archives/6-MouseEnter-and-MouseLeave.html
This makes it possible to implement mouseenter and mouseleave in other browsers. In fact, Ken provides same Prototype code to do so: http://kendsnyder.com/sandbox/enterleave/MouseEnterLeave.js
Duroth pointed out in comments that MooTools already includes something similar. (Thanks Duroth.) It sounds like the upcoming Prototype release (1.6.2) may include this functionality, but I can't find anything definite.
Using only javascript, no prototype or jquery etc.
<html>
<head>
<script type="text/javascript">
var mouseX = 0;
var mouseY = 0;
var counter = 0;
var mouseIsIn = true;
function wireEvent() {
window.addEventListener("mouseout",
function(e){
mouseX = e.pageX;
mouseY = e.pageY;
if ((mouseY >= 0 && mouseY <= window.innerHeight)
&& (mouseX >= 0 && mouseX <= window.innerWidth))
return;
//do something for mouse out
counter++;
mouseIsIn = false;
document.getElementById('in_out').innerHTML='out' + counter;
},
false);
window.addEventListener("mouseover",
function(e){
if(mouseIsIn)
return;
//do something for mouse over
counter++;
mouseIsIn = true;
document.getElementById('in_out').innerHTML='in' + counter;
},
false);
}
</script>
</head>
<body onload="wireEvent();">
<div id="in_out"> </div>
<div style="width:300px; height: 200px; background: red;">Dummy element</div>
</body>
</html>
UPDATE:
Added check for mouse position on mouseout
triggered when moving in/out elements within the body. If it's within the window, mouseout
event is not triggered.
Also introduced a flag for current status of mouse 'in' or 'out' using mouseIsIn
. If it is true
, mouseover
will not trigger too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With