Bride of Windows
See the demo page for the finished version of the code.Event Handling
Several events are set up for capture either in the Window()
constructor function or in the HTML code of the each window. As shown
earlier, every window element that is assigned an event handler also has a
parentWindow
property defined for it. This allows the handler
functions to directly reference the window object that the element belongs
to.
Like the window methods, almost all the event handlers include a call to the
makeActive()
method, either directly or indirectly. This is done
so that when the user clicks anywhere on a window, or starts a drag operation
on it, that window becomes the active one.
Window Button Events
For the buttons, an onclick
event handler is specified for each
one in the HTML itself, within the corresponding image map AREA tag.
<img class="titleBarButtons" alt="" src="graphics/buttons.gif" usemap="#myMap" /> <map id="myMap" name="myMap"> <area shape="rect" coords="0,0,15,13" href="" title="Minimize" onclick="this.parentWindow.minimize();return false;" /> <area shape="rect" coords="16,0,31,13" href="" title="Restore" onclick="this.parentWindow.restore();return false;" /> <area shape="rect" coords="34,0,49,13" href="" title="Close" onclick="this.parentWindow.close();return false;" /> </map>
Each event handler calls the appropriate window method directly to either minimize, restore or close the window.
Window Client Area Events
When Window()
is called to create a new window object, the
window's client area is assigned an onclick
event handler that
points to the function winClientAreaClick().
function winClientAreaClick(event) { // Make this window the active one. this.parentWindow.makeActive(); }
All this function does is call makeActive()
for the parent
window. But combined with the calls to makeActive()
in most of the
other event handlers, the user can now select an inactive window and make it
active by clicking just about anywhere on it.
Next we'll look at the event handlers that allow the user to move or resize a window via dragging.
Event Handling For Drag Operations
The remaining event handlers are a little more complicated as they deal with the drag operations to either move or resize a window. Multiple events are involved for each.
Internet Explorer, as of version 6, still doesn't follow the standard DOM event model, so some browser-dependent coding is required. Fortunately, however, these differences are relatively minor, as can be seen in the source code.
Both drag operations rely on the fact that there is one active window on the
page at any time. So the move and resize operations are always applied to this
window. Likewise, the winCtrl
object is used to store information
related to the current drag operation, such as the cursor position.
Moving a Window
To enable the user move a window by dragging its titlebar, the
mousedown
event is captured for that element. When it fires, the
winMoveDragStart()
function is called.
The function first checks to see if the cursor is on a button and, if so, exits. This prevents it from interfering with the window button events.
if (browser.isIE) target = window.event.srcElement.tagName; if (browser.isNS) target = event.target.tagName; if (target == "AREA") return;
Otherwise, it continues on to set up the drag operation.
To initialize the drag operation, makeActive()
is called first.
Then the function calculates the offset of the cursor relative to the window
frame, storing the values in the winCtrl
object. These offsets
will be used to move the window as the cursor is moved around the page.
this.parentWindow.makeActive(); // Get cursor offset from window frame. if (browser.isIE) { x = window.event.x; y = window.event.y; } if (browser.isNS) { x = event.pageX; y = event.pageY; } winCtrl.xOffset = winCtrl.active.frame.offsetLeft - x; winCtrl.yOffset = winCtrl.active.frame.offsetTop - y;
Next it sets up event capturing for mousemove
and
mouseup
events at the document level so it can reposition the
window as the mouse is moved around and end the drag when the mouse button
is released.
// Set document to capture mousemove and mouseup events. if (browser.isIE) { document.onmousemove = winMoveDragGo; document.onmouseup = winMoveDragStop; } if (browser.isNS) { document.addEventListener("mousemove", winMoveDragGo, true); document.addEventListener("mouseup", winMoveDragStop, true); event.preventDefault(); } winCtrl.inMoveDrag = true;
The final act is to set a flag in winCtrl
to indicate that a
move drag has started.
The winMoveDragGo()
function will now execute as the mouse
is dragged around the browser window. It simply takes the current cursor
position, adds the offset values saved earlier and uses those sums to change
the left
and top
positions of the window frame. The
window will appear to move with the cursor, as though it were attached to it at
the point where the mouse button was first depressed.
function winMoveDragGo(event) { var x, y; if (!winCtrl.inMoveDrag) return; // Get cursor position. if (browser.isIE) { x = window.event.x; y = window.event.y; window.event.cancelBubble = true; window.event.returnValue = false; } if (browser.isNS) { x = event.pageX; y = event.pageY; event.preventDefault(); } // Move window frame based on offset from cursor. winCtrl.active.frame.style.left = (x + winCtrl.xOffset) + "px"; winCtrl.active.frame.style.top = (y + winCtrl.yOffset) + "px"; }
Event bubbling is canceled to prevent the browser's normal action of creating and highlighting a selection on the page.
When the user releases the mouse button, winMoveDragStop()
is
called. The function clears the move drag flag in winCtrl
and
removes the mousemove
and mouseup
event capturing
for the document, ending the drag operation.
function winMoveDragStop(event) { winCtrl.inMoveDrag = false; // Remove mousemove and mouseup event captures on document. if (browser.isIE) { document.onmousemove = null; document.onmouseup = null; } if (browser.isNS) { document.removeEventListener("mousemove", winMoveDragGo, true); document.removeEventListener("mouseup", winMoveDragStop, true); } }