(2001-12-04) Updated the behaviors to work inside frames and framesets.

Introduction

The other day I got an email with the question how to drag a window using a div element. And in my eternal struggle to create new useful scripts I accepted the challenge.

After getting the basic scripts to both move and resize a window by dragging any element on the page I converted the scripts to two behaviors.

Usage

To use these behaviors you need to attach the behavior to an element in the normal way. For the resize behavior you also need to add a custom attribute called resizedirection. This can can be set to any of the following values; e, w, s, n, se, sw, ne or nw, representing the direction to resize the window.

<style type="text/css">

.winmove {
   behavior: url("winmove.htc");
}

.winresize {
   behavior: url("winresize.htc");
}

</style>

...

<span class="winmove">Move</span>
<span class="winresize" resizedirection="se">Resize</span>

Implementation

Even though drag and drop scripts are fairly straight forward, there are some issues when an actual window is supposed to be moved.

Capturing the Events

If you want to drag a window it is very likely that the mouse leaves the actual document container and therefore you would not receive any mouse move events. The solution to this is to use capturing. This is done by calling the method setCapture() on an actual element. Once this is called all mouse events are captured by this element and therefore you will be able to receive mouse move (and mouse up) events even when the mouse pointer is outside the actual element.

function startMove() {
   _dx = event.screenX - getLeft();
   _dy = event.screenY - getTop();
   element.attachEvent("onmousemove", doMove);
   element.attachEvent("onmouseup", endMove);
   element.attachEvent("onlosecapture", endMove);
   element.setCapture();

   event.cancelBubble = true;
}

The function startMove is called when the mouse is pressed down on the element and as you can see we attach event listeners to onmousemove, onmouseup and onlosecapture before we actually set the capture. The event onlosecapture is called if something interferes with the capture forcing it to lose the capture (for example a call to window.alert()).

Getting the Window Position

IE does not provide any DOM interface to actually read the position of a window. It only provides a method to set it (window.moveTo(x, y).However all is not lost because there are two properties called window.screenLeft and window.screenTop. These returns the position of the upper left corner of the document container so what we need to do is to figure out the distance between the upper left corner of the window and the upper left corner of the document (this is usually known as the insets). This can be done by moving the window to a known position and calculate the difference of the window position and the document position. After this we can move back the window to the original place because we now know the insets and the previous location of the document.

function getInsets() {
   // Store the old document position
   var oldScreenLeft = window.top.screenLeft;
   var oldScreenTop = window.top.screenTop;

   // if no previous inset calculated assume one
   if (window.top._insets == null)
      window.top._insets = {left: 5, top: 80};
   
   // move to a known position
   window.top.moveTo(oldScreenLeft - window.top._insets.left,
                 oldScreenTop - window.top._insets.top);
   
   // Measure the new document position
   var newScreenLeft = window.top.screenLeft;
   var newScreenTop = window.top.screenTop;
   
   // ... and store the insets result
   var res = {
      left:   newScreenLeft - oldScreenLeft + window.top._insets.left,
      top:   newScreenTop - oldScreenTop + window.top._insets.top
   };
   
   // move back the window to its original place
   window.top.moveTo(oldScreenLeft - res.left, oldScreenTop - res.top);
   
   // and backup the insets for next time
   window.top._insets = res;
   
   return res;
}

Now that we can get the insets we can easily define the functions getLeft() and getTop().

function getLeft() {
   return window.top.screenLeft - getInsets().left;
}

function getTop() {
   return window.top.screenTop - getInsets().top;
}

Getting the Window Size

The same problem as with the position applies to the size of the window. One can only set the size using window.resizeTo(w, h). The solution to find the window size is the same as for getting the position but we use the document size and resize the window instead. To get the size we return the clientWidth and clientHeight of the topmost (visual) element in the document. Notice that this is different in IE6 if it is put in CSS1 compatible mode.

function getInnerSize() {
   var el = window.top.document.compatMode == "CSS1Compat" ?
               window.top.document.documentElement :
               window.top.document.body;
   return {
      width:   el.clientWidth,
      height:  el.clientHeight
   };
}

Now we can create the getSize() function. The algorithm for this is very similar to the earlier one for the position.

function getSize() {
   // Store old size
   var oldInnerSize = getInnerSize();
   
   // if no previous diff assume one
   if (window.top._diff == null)
      window.top._diff = {width: 10, height: 90};
   
   // resize to known size
   window.top.resizeTo(oldInnerSize.width + window.top._diff.width,                       oldInnerSize.height + window.top._diff.height);
   
   // calculate inner size again
   var newInnerSize = getInnerSize();
   
   // store diff result
   var diff = {
      width:   oldInnerSize.width - newInnerSize.width + window.top._diff.width,
      height:  oldInnerSize.height - newInnerSize.height + window.top._diff.height
   };
   
   // restore size to old size
   window.top.resizeTo(oldInnerSize.width + diff.width, oldInnerSize.height + diff.height);
   
   // backup diff for future calculations
   window.top._diff = diff;
   
   return {
      width:   oldInnerSize.width + diff.width,
      height:  oldInnerSize.height + diff.height
   };
}

For the complete code download the archive.

Window Controls
Demo
Chromeless Demo
Frame Demo
Download

Author: Erik Arvidsson