views:

1054

answers:

2

In Internet Explorer 7 body onmousemove or document.onmousemove events only seem to fire while the mouse is inside the browser window, not when it's outside. Yet in Firefox the onmousemove event is called correctly when I move outside of the browser window.

How can I setup an event to be called outside of the browser window in IE?

Google Maps does this in IE. If you hold the mouse button down and move the mouse outside of the browser window you can see that the map still moves.

+1  A: 

You can look at the code here, as it seems to work in IE8 and FF3.5. If you can understand his code great. http://www.walterzorn.com/dragdrop/dragdrop_e.htm

James Black
Thanks. It's pretty criptic code, but he seems to be using document.onmousemove too, I wonder what the secret is?
Matthew Lock
I don't know, I haven't examined the code too much, but you may want to use Firebug on Firefox, or the Web Developer toolkit on IE to watch what is happening as you move the mouse outside the browser.
James Black
Thanks. How would I watch what is happening in Firebug or the Web Developer toolkit on IE while I move the mouse? I've looked all over both of those but don't see any way to watch events.
Matthew Lock
Also I notice that in walterzorn.com/dragdrop/dragdrop_e.htm only the images can be moved with the mouse out of the window and not the div example at the bottom. Similarly with Google Maps you are actually dragging an image around, not a HTML element.Maybe it's a limitation of IE that only the image drag event or something can work outside of the page?
Matthew Lock
You can try this, and watch it in the console: console.info("y is greater than x")
James Black
+9  A: 

(Note: this answer refers exclusively to the "standard" drag implementation of mousedown -> mousemove -> mouseup. It is not applicable to the HTML5 drag specification).

Allowing dragging outside the browser window is an old problem that different browsers have solved in two ways.

With the exception of IE, when a user initiates a drag operation via mousedown browsers have done something neat (and this is all just from observation): a kind of statemachine kicks in to handle the special case of mouse movements outside the window:

  1. User triggers mousedown event inside the document
  2. User triggers mousemove event. Event fires even when triggered from outside the document (i.e. the window)
  3. User triggers mouseup event (inside or outside the document). mousemove events triggered from outside the document no longer fire

IE and older versions of Firefox [as late as 2.0.20] don't exhibit this behavior. Dragging outside the window just doesn't work1.

The problem for IE and FF2 actually lies in whether an element is "selectable" or not (See here and here). If a dragging implementation does nothing (thereby allowing selection by the mouse), then said implementation does not have to account for movements outside the window; the browser will go ahead and fire mousemove properly and the user is allowed to drag freely outside the window. Nice.

However by letting the browser decide what to do on mousemove you get this effect where the browser thinks the user is trying to "select" something (eg the element), as opposed to moving it, and proceeds to frantically try to highlight the element or text therein as the mouse crosses in or out of the element during the drag.

Most drag implementations I've seen do a little trick to make the element being dragged "unselectable", thereby taking full control of mousemove to simulate dragging:

elementToDrag.unselectable = "on";
elementToDrag.onselectstart = function(){return false};
elementToDrag.style.userSelect = "none"; // w3c standard
elementToDrag.style.MozUserSelect = "none"; // Firefox

This works nicely, but breaks dragging outside the window. 2

Anyway, to answer your question, to get IE (all versions) to allow dragging outside the window, use setCapture (and inversely releaseCapture when the mouse is released).

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml"&gt;
<head>
<title>Simple drag demo</title>
<style>
#dragme {
  position:absolute;
  cursor:move;
  background:#eee;
  border:1px solid #333;
  padding:10px;
}
</style>

<script>
function makeDraggable(element) {

  /* Simple drag implementation */
  element.onmousedown = function(event) {

    document.onmousemove = function(event) {
      event = event || window.event;
      element.style.left = event.clientX + 'px';
      element.style.top = event.clientY + 'px';
    };

    document.onmouseup = function() {
      document.onmousemove = null;

      if(element.releaseCapture) { element.releaseCapture(); }
    };

    if(element.setCapture) { element.setCapture(); }
  };

  /* These 3 lines are helpful for the browser to not accidentally 
   * think the user is trying to "text select" the draggable object
   * when drag initiation happens on text nodes.
   * Unfortunately they also break draggability outside the window.
   */
  element.unselectable = "on";
  element.onselectstart = function(){return false};
  element.style.userSelect = element.style.MozUserSelect = "none";
}
</script>
</head>
<body onload="makeDraggable(document.getElementById('dragme'))">

<div id="dragme">Drag me (outside window)</div>

</body>
</html>

Demo can be seen here.

This is exactly what Google maps does (as I discovered since reverse engineering google maps back in 2004 when it was first released).


1I believe it actually only breaks when initiating a drag operation (i.e. mousedown) on a textnode. Element/container nodes do not exhibit the same behavior and can be dragged around inside or outside the document, provided the user moused down on an "empty " portion of the element

2Again, for drag initiations on textnodes.

Crescent Fresh
brilliant answer!
Matthew Lock