-->
Bookmark and Share

Bride of Windows

See the demo page for the finished version of the code.

Initialization Code

The script first defines two global variables: winList, for the array of Window objects, and winCtrl which is used to hold various data values used throughout the code.

var winList = new Array();
var winCtrl = new Object();

winCtrl is defined as a generic JavaScript Object. By adding user-defined properties to this object, several values can be made globally accessible using only a single variable.

The script also sets the window.onload event to run its initialization function once the page has finished loading.

window.onload = winInit;

The winInit() functions first sets some values in the winCtrl variable including the colors to be used for inactive windows, constants and flags used during the move and resize drag operations.

  // Initialize window control object.

  winCtrl.maxzIndex                        =   0;
  winCtrl.resizeCornerSize                 =  16;
  winCtrl.minimizedTextWidth               = 100;
  winCtrl.inactiveFrameBackgroundColor     = "#c0c0c0";
  winCtrl.inactiveFrameBorderColor         =
    "#f0f0f0 #505050 #404040 #e0e0e0";
  winCtrl.inactiveTitleBarColor            = "#808080";
  winCtrl.inactiveTitleTextColor           = "#c0c0c0";
  winCtrl.inactiveClientAreaBorderColor    =
    "#404040 #e0e0e0 #f0f0f0 #505050";
  winCtrl.inactiveClientAreaScrollbarColor = "";
  winCtrl.inMoveDrag                       = false;
  winCtrl.inResizeDrag                     = false;

The property maxzIndex is used for the z-index property of the currently active window. It will simply be incremented every time the active window changes so it can be placed at the top of the stacking order. The initial value can be changed if other positioned elements are used on the page.

The resizeCornerSize property determines how close the cursor must be to a corner of a window to set off a diagonal resize drag (i.e., a resize in both the horizontal or vertical directions).

The minimizedTextWidth determines how wide minimized windows will be.

Other properties are defined for winCtrl as well, but these are added dynamically as needed. They will be noted as the relevant code section is discussed.

Identifying the Windows

The next step in winInit() is to find all the windows defined on the page and create Window objects for them.

  var elList;

  // Initialize windows and build list.

  elList = document.getElementsByTagName("DIV");
  for (var i = 0; i < elList.length; i++)
    if (elList[i].className == "window")
      winList[elList[i].id] = new Window(elList[i]);

Calling document.getElementsByTagName("DIV") gives a list of all the DIV elements on the page. The script then loops through these and looks for any that use the window CSS class. When such and element is found, it creates a new Window object for it and then adds it to the global winList array.

The Window Constructor

The Window() function takes one argument, the DOM node corresponding to outer, window-class DIV element of the window. The first thing it does is locate the sub elements of that DIV which make up the window components, like the title bar, client area, etc. These are saved as properties of the object so that they can be easily referenced later.

  // Get window components.

  this.frame           = el;
  this.titleBar        = winFindByClassName(el, "titleBar");
  this.titleBarText    = winFindByClassName(el, "titleBarText");
  this.titleBarButtons = winFindByClassName(el, "titleBarButtons");
  this.clientArea      = winFindByClassName(el, "clientArea");

The function winFindByClassName() is a utility function that searches the child nodes of a given element to find one that is assigned a given CSS class. Since all of the window components use a specific style class, this can be used to locate the various window elements

function winFindByClassName(el, className) {

  var i, tmp;

  if (el.className == className)
    return el;

  // Search for a descendant element assigned the given class.

  for (i = 0; i < el.childNodes.length; i++) {
    tmp = winFindByClassName(el.childNodes[i], className);
    if (tmp != null)
      return tmp;
  }

  return null;
}

The function is recursive, so it will not only search the element's child nodes, but any child nodes they have as well. As soon as it finds a match, it returns that element node.

The next step is to find the image map assigned to the window's control buttons.

  // Find matching button image map.

  mapName = this.titleBarButtons.useMap.substr(1);
  mapList = document.getElementsByTagName("MAP");
  for (i = 0; i < mapList.length; i++)
    if (mapList[i].name == mapName)
      this.titleBarMap = mapList[i];

Again, document.getElementsByTagName() is used to find all the MAP elements on the page. It then checks them to find one whose name matches the USEMAP attribute value on the button image tag.

The Window() function then saves the original element colors that will be altered whenever the window is inactivated so that they can be properly restored whenever it becomes active again.

  // Save colors.

  this.activeFrameBackgroundColor  = this.frame.style.backgroundColor;
  this.activeFrameBorderColor      = this.frame.style.borderColor;
  this.activeTitleBarColor         = this.titleBar.style.backgroundColor;
  this.activeTitleTextColor        = this.titleBar.style.color;
  this.activeClientAreaBorderColor = this.clientArea.style.borderColor;
  if (browser.isIE)
    this.activeClientAreaScrollbarColor =
      this.clientArea.style.scrollbarBaseColor;

It also saves the button image SRC and LONGDESC values so these can be easily referenced when switching between active to inactive states.

  // Save images.

  this.activeButtonsImage   = this.titleBarButtons.src;
  this.inactiveButtonsImage = this.titleBarButtons.longDesc;

Next it sets up a couple of flags and assigns the window methods.

  // Set flags.

  this.isOpen      = false;
  this.isMinimized = false;

  // Set methods.

  this.open       = winOpen;
  this.close      = winClose;
  this.minimize   = winMinimize;
  this.restore    = winRestore;
  this.makeActive = winMakeActive;

These flags are used by several functions to track the window's current state.