Techniques - DevSource
DevSource: Microsoft Developer Resource DevSource Home Sponsored by Microsoft Home Add Ons Architecture Languages Techniques Using VS Forums
Home arrow Techniques arrow Page 3 - Draggable, Collapsible, Dynamic DIV windows with JavaScript
Draggable, Collapsible, Dynamic DIV windows with JavaScript
By Jeff Cogswell

Rate This Article: Add This Article To:

Draggable, Collapsible, Dynamic DIV windows with JavaScript - ' Event'
( Page 3 of 3 )

-Handling functions">

Rather than explain in detail every single line, I'll discuss in general what these functions do, and you can look at the code in the download.

The contentMouseDown function executes in response to the mouse button being pressed while over a content DIV. The purpose of this is to bring that content DIV (and its associated title bar DIV) to the front, as is normal behavior in a windowing environment.

ADVERTISEMENT

To bring the window to the front, I increment the topZ variable, and then set the Z-Order for these two DIVs to that value. Each time a window moves forward, I increment the topZ value, so the window is assured of being on top. (Don't worry about going to high; JavaScript internally stores integers as double-precision floating-point variables, which allows for integers up to around 9 quadrillion. It would take a very long time to outclick the topZ variable!)

The mouseDown function is for dragging the title bars. The code starts by bringing the current window to the front (just like the contentMouseDown function), and then saving away the title bar object into the dragObjTitle variable for later. The code then calculates the difference in position between the mouse position and the title bar's upper left corner. (When you move the title bar, you want to move it by how much the mouse moved; you don't want to snap its upper-left corner to the current mouse position.)

The mouseMove function checks whether a drag operation is taking place by simply checking whether the dragObjTitle variable has anything in it. If so, then a drag is taking place. This part is easy; the code just moves the title DIV and the content DIV by the offset of how far the mouse has moved.

The mouseUp function is short; it just checks whether a drag is taking place, and then calls finishDrag.

The finishDrag function ends the drag and cleans everything up. It moves the window to its final position, and then clears out the dragObjTitle variable. However, to get the final position, this function checks if the window was dragged outside and above the browser document or to the left of the browser document. If so, the code adjusts the position to snap the window to the edge rather than drop it off the document. (Dropping the window to the right or below the browser document is okay, however, as the browser will adjust its scroll bars and you can scroll the window into view. If you drop it off view above or to the left, you'll lose it from view and won't be able to scroll to it.)

addDocumentHandlers function

The event handlers the addDocumentHandlers function add are important because when you're dragging an element around, it's possible to move the mouse quickly and skip ahead several pixels on the screen, off of the element you're dragging. When you do so, the next MouseMove events will come in to the document, and not the element you're dragging. Thus we need to capture these events as well, which is why I set them up in the addDocumentHandlers function.

This function gets called when the drag starts (to activate the handlers), and when the drag ends (to clear the handlers).

Browser Issues

If you write a lot of JavaScript code, it won't take long before you get frustrated having to deal with the differences between browsers. In general, you can expect two types of browsers: Those that are standards compliant, and Microsoft Internet Explorer. Microsoft implements many of the standards, but not all. If you write for the standards, in general your code will run on Firefox and Opera and others, but may need fixes for Internet Explorer. Thus, in this code, I had to have several if statements to handle browser-specific issues. However, many programmers (myself included) don't like to write code that first detects the browser name. Instead, the best bet is to simply determine if the object you're working with is available, and if not, use alternative code, wrapping it all in an if statement.

I took that approach for most of this code except in one notable place where (I admit) I cheated, which I discuss shortly.

Many of the issues are in the events. When adding an event handler, Firefox and Opera use the addEventListener method, like so:

document.addEventListener("mousedown", 
function(e) { return mouseDown(e) }, true);

IE, however, doesn't have this function, and as such you need to use an older approach, such as saving the function name to an event property, such as document.onmousedown.

I used this approach; however, in the case of the document properties in IE, the event parameter doesn't get set. Thus, I used code like this to set the document event handlers in IE:

document.onmousedown = function() { mouseDown(window.event) } ;

where I specifically pass the window.event object.

One problem I had was in IE when you quickly move the mouse out of the window and let up the mouse button, there's a good chance the JavaScript code won't receive the MouseUp event, which can be a major problem. If this happens, when you return to the window to work, even though you no longer have the button down, the code will still think you're in a drag, and the window will follow the mouse around.

That's not good. So to handle this, in the case of IE, I need to check inside the handler for the MouseMove event if the mouse button is still down. If not, I end the drag by calling my finishDrag function, and then leave the handler.

This is where I test whether IE is running, and this is the part where I cheated. I don't really test for IE; instead I know that IE doesn't have a method called preventDefault in its event objects, whereas the other browsers do. Thus I test whether the event object has that method. If not, I know I have IE. (I admit, this is a bit of a kludge, and if you're not happy about it, feel free to change the code and actually test which browser is present here.)

Once I know I have IE, I then check if the mouse button is still pressed, like so:

if (!e.preventDefault) {
if (e.button == 0) {
finishDrag(e);
return;
}
}

And this fixed the problem. (The problem didn't occur in Firefox or Opera, as these two browsers capture the mouse events while you're holding down the mouse button. Then if you move outside the window, the browser will still receive the MouseMove and MouseUp events.)

Another browser issue is the event objects (passed as parameters to the event handlers) have a different set of members. To keep the code simple, when possible I used code like this:

var dragContent = e.srcElement || e.currentTarget;

IE has an e.srcElement, but no e.currentTarget. Conversely, Firefox and Opera have e.currentTarget but not e.srcElement. With JavaScript, if you try to access a member that doesn't exist, you'll get back null rather than an error. Thus you can simply combine the two with a logical OR, obtaining the member you want.

Conclusion

The code and samples for this article are available in the download. Feel free to play with it and add it and enhance it any way you like. If you have some cool enhancements, go ahead and share them with others in our forums. We'd love to hear from you!



 
 
>>> More Techniques Articles          >>> More By Jeff Cogswell
 



Microsoft's Future: A Chat With Their CTO, Barry Briggs

Play Video >

All Videos >

Julia explores the Robotics Studio!

Read now >

Messages to Bill Gates!

Read now >

View Now
DevSource RSS FEEDS
XML Want an easy way to keep up with breaking tech news? And the Get DevSource headlines delivered to your desktop with RSS.