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 2 - 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 - ' Understanding the Code'
( Page 2 of 3 )

Probably the hardest part about writing this code was making it work with the different browsers, while keeping it fully XHTML and CSS compliant. To help me in writing the code, I reused a handy strprintf function that I created sometime back. You're free to use this code anywhere you want. (I'll be talking about how it works in another article soon. To give you a hint, it uses regular expressions, which allowed me to write it with very little code.) I called the function jstrprintf (for JavaScript printf). You pass a format string followed by expressions to be inserted into the string. I won't go into the details here, but I will show you a quick example. This code:

jstrprintf('Abc $1 def $2 ghi $3', 'xyz', 123)

will return this string:

"Abc xyz def 123 ghi $3"
ADVERTISEMENT

The two instances of $1 in the format string are replaced with 'xyz' and the one instance of $2 is replaced by the number 123 to get the final string.

I also included a couple helper functions in the code, one called AddPx, which simply appends px to a string version of a number. And I included a couple functions that help me walk up the tree of parent elements to find one of my draggable elements.

After these functions comes the heart of the code, which consists of eight functions:

CreateDropdownWindow: This is the main function that creates the draggable window. (I originally called it DropDown because it can be collapsed and then dropped back down.)

toggleContentWin: This function collapses or expands the dropdown window. It is called when the button in the upper-right of a window is clicked.

contentMouseDown: This is an event-handling function that runs when you click on the main part of a window. Its purpose is to bring the window to the front.

mouseDown: This event-handling function serves two purposes; one is to bring a window to the front, and two, to initiate dragging.

mouseMove: This event-handling function handles the actual moving of a window as the mouse is moving during a drag.

mouseUp: This event-handling function calls the finishDrag function.

finishDrag: This function completes the drag by placing the window in its final position and cleaning up.

addDocumentHandlers: This function sets up the event handlers for the document and later clears them out. It's called by mouseDown and finishDrag.

CreateDropdownWindow function

This function creates the needed DIV tags that will make up the draggable windows. To create the tags, I call document.createElement, passing the string div. This function returns the new DIV element; I then set several of the element's properties, including its style class name, size, and position. I also set the element's ID to a unique name and number:

function CreateDropdownWindow(caption, theWidth, canMove, contentSource) {
var newdiv;
newdiv = document.createElement("div");
newdiv.id = "dragTitle" + String(nextID);
newdiv.className = "divDragTitle";
newdiv.style.width = theWidth;
newdiv.style.left = AddPx(startX);
newdiv.style.top = AddPx(startY);
newdiv.style.zIndex = topZ;

I want this DIV to appear in front of the other windows created, so I give it a Z-Order. For that I also use a unique number that I increment each time I create a new window and each time a window is moved to the front.

This new DIV element will be the title bar, and so I give it some HTML that contains the text to appear in the title, and the button to appear to it's right.

To create this HTML, instead of making numerous calls to createElement, I just construct some HTML on the fly (using the jstrprintf function), and then save this HTML in the element's innerHTML property:

newdiv.innerHTML = jstrprintf(
'<table><tr><td>$1</td>' +
'<td style="text-align:right">' +
'<img src="buttontop.gif" class="divTitleButton" id="dragButton$2" ' +
'onmousedown="javascript:toggleContentWin($2)" /></td>' +
'</tr></table>',
caption, nextID);

Next, if the window is draggable, I set up the event handlers for this element. You can drag windows from the title bars; and so I set up the three needed events, MouseDown, MouseMove, and MouseUp:

if (canMove) {
if (newdiv.addEventListener) {
// firefox, etc.
newdiv.addEventListener("mousemove", function(e)
{ return mouseMove(e) }, true);
newdiv.addEventListener("mousedown", function(e)
{ return mouseDown(e) }, true);
newdiv.addEventListener("mouseup", function(e)
{ return mouseUp(e) }, true);
}
else {
// IE
newdiv.attachEvent("onmousemove", function(e)
{ return mouseMove(e) });
newdiv.attachEvent("onmousedown", function(e)
{ return mouseDown(e) });
newdiv.attachEvent("onmouseup", function(e)
{ return mouseUp(e) });
}
}

(Towards the end of this article, I discuss the different types of events for the browsers, hence the inner if statement here.) I then add the new element to the document with the following code:

document.body.appendChild(newdiv);

After that, I create another element; this will also be a DIV and will be the main content area of the screen. To create this DIV, I follow the same procedure as before:

var newdiv2;
newdiv2 = document.createElement("div");
newdiv2.id = "dragContent" + String(nextID);
newdiv2.className = "divDragContent";
newdiv2.style.width = theWidth;
newdiv2.style.left = AddPx(startX);
newdiv2.style.top = AddPx(startY + 20);
newdiv2.style.zIndex = topZ;

(This DIV elements shares the same number in its ID as the previous other DIV element I just created; I use a different name to go with the number. That way I can relate the two DIV elements.)

Also this time, to create the HTML, I locate the element whose ID was passed in as the fourth parameter to CreateDropdownWindow. I then grab that element's content (from its innerHTML member) and save the content into this new element's innerHTML member, effectively copying it over. (For that reason, you need to be careful if you use IDs in the HTML and want the same HTML copied to several windows. In that case you'll want to enhance this code, perhaps using the jstrprintf function to add a unique number to each ID in your HTML.) Here's the code that copies the HTML over:

if (contentSource) {
newdiv2.innerHTML = document.
getElementById(contentSource).innerHTML;
}

(Notice this if statement means if you pass a null for the CreateDropdownWindow function's contentSource parameter, the window will be empty with no HTML.)

After this second element is created, I set its handlers (if the window is draggable), and I add the element to the document:

if (canMove) {
if (newdiv2.addEventListener) {
// firefox, etc.
newdiv2.addEventListener("mousedown", function(e)
{ return contentMouseDown(e) }, true);
}
else {
// IE
newdiv2.attachEvent("onmousedown", function(e)
{ return contentMouseDown(e) });
}
}
document.body.appendChild(newdiv2);

Then I give each element a reference to the other element:

newdiv.content = newdiv2;
newdiv2.titlediv = newdiv;

That way, given one element, I have another way to locate the other element.

Finally, I clean up by incrementing some variables:

 topZ += 1;
startX += 25;
startY += 25;

nextID++;
}

toggletoggleContentWin function

This function is easy. It takes a parameter representing the unique number that goes with a window. (That unique number was the nextID variable used in CreateDropdownWindow.)

function toggleContentWin(id) {
var elem = document.getElementById("dragContent" + String(id));
var img = document.getElementById("dragButton" + String(id));

Using this number, the code locates two elements, the DIV representing the lower DIV for the window (the content), and the image in the upper-right of the window (the button image). I then check whether the content DIV is visible or not, like so:

if (elem.style.display == "none") {

If display is "none", then the content DIV is not visible. In that case, I make the DIV visible:

 elem.style.display = "block";

and then I change the image:

 img.src = "buttontop.gif";
}

However, if the DIV is already visible, I do the reverse. I make the DIV invisible and toggle the image back:

 else {
// showing, so hide
elem.style.display = "none";

// Change the button's image
img.src = "buttonbottom.gif";
}
}



 
 
>>> 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.