/*
 * Flyout menus for the University of Washington Home Page
 * University of Washington / Computing and Communications
 * May, 2003
 * Documentation can be found at
 *     http://www.washington.edu/webinfo/case/flyout/
 * $Id: flyout.js,v 1.52 2003/05/13 17:38:08 fmf Exp $
 *
 * You are free to copy and/or use these flyout menus (or
 * derivative works) but please make sure this comment block
 * remains intact and in its entirety at the top of the file.
 */

var d = document;
var doDHTML = 0;
d.versIE = 0;

if ((! d.cssonly && d.layers) || d.all || d.getElementById) {
    var vers = navigator.appVersion.split ('MSIE ');
    vers = vers[vers.length - 1];
    d.versIE = parseInt (vers);
    FlyLyr.isMac = navigator.platform.indexOf ('Mac') >= 0;
    if (navigator.appVersion.indexOf ('MSIE') < 0 || ! FlyLyr.isMac || d.versIE >= 5) {
	doDHTML = 1;
	FlyLyr.isOpera = navigator.userAgent.indexOf (' Opera ') >= 0;
	FlyLyr.isKonq = navigator.userAgent.indexOf (' Konqueror') >= 0;

	initFlyLyr ();
	initToShow ();
	initDelay ();

	d.write ('<style type="text/css">' +
		    '.flyout { visibility: hidden; position: absolute; ' +
		    'left: 0; top: 0; margin-right: -15px; margin-bottom: -15px; }' +
		    '.flyoutindent {font-size: xx-small; }<\/style>');
    }
}

function useLayer (id) {
    if (! doDHTML || ! d.body.appendChild)
	return;
    var elem = findObj ('l_' + id);
    if (! elem)
	return;
    if (FlyLyr.defs.preDetach)
	FlyLyr.defs.preDetach (elem);
    if (elem.parentNode.tagName != 'BODY')
	d.body.appendChild (elem.parentNode.removeChild (elem));
    new FlyLyr (id, 0);
}

function makeLayer (id, title) {
    if (! doDHTML)
	return;
    var a = arguments;
    var numsp = new Array;
    numsp.max = new Array;
    var pos = 0;
    numsp.max[0] = 0;
    for (var j = 2; j < a.length; ++j) {
	numsp[j] = a[j].length;
	if (numsp[j]) {
	    a[j] = a[j].replace (/^ +/, '');
	    numsp[j] -= a[j].length;
	    numsp.max[pos] = Math.max (numsp[j], numsp.max[pos]);
	} else
	    numsp.max[++pos] = 0;
    }
    var fd = FlyLyr.defs;
    d.write ('<div id="l_' + id + '" class="flyout">' +  
		'<table cellpadding="2" cellspacing="0" border="1" bgcolor="' +
		fd.background + '" bordercolor="' + fd.border + '">');
    if (title) {
	var titleargs = 'align="center"';
	if (fd.titlebackground)
	    titleargs += ' bgcolor="' + fd.titlebackground + '"';
	d.write ('<tr>' +
		    buildCell (title,
				fd.titleclass ? fd.titleclass : fd.useclass,
				titleargs) + '<\/tr>');
    }
    var divstart = '<tr><td><table cellpadding="1" cellspacing="0" ' +
		    'border="0">' + "\n";
    d.write (divstart);
    pos = 0;
    for (j = 2; j < a.length; ++j) {
	if (! a[j]) {
	    d.write ('<\/table><\/td><\/tr>' + divstart);
	    ++pos;
	    continue;
	}
	var args = null;
	var i = numsp[j];
	if (i < numsp.max[pos])
	    args = 'colspan="' + (numsp.max[pos] - i + 1) + '"';
	if (fd.alignright)
	    args += ' align="right"';
	d.write ('<tr>');
	while (i-- > 0)
	    d.write ('<td class="flyoutindent">&nbsp;&nbsp;<\/td>');
	d.write (buildCell (a[j], fd.useclass, args) + '<\/tr>' + "\n");
    }
    d.write ('<\/table><\/td><\/tr><\/table><\/div>' + "\n");
    new FlyLyr (id, 1);
}

function buildCell (str, fc, args) {
    var retstr = '<td class="' + fc + '"';
    if (args)
	retstr += ' ' + args;
    retstr += '>';
    var eqpos = str.indexOf ('=');
    var atpos = str.indexOf ('@');
    if (eqpos > 0) {
	if (atpos > eqpos)
	    retstr += '<a href="' + str.substr (eqpos + 1, atpos - eqpos - 1)
			+ '" target="' + str.substr (atpos + 1) + '">';
	else
	    retstr += '<a href="' + str.substr (eqpos + 1) + '">';
	retstr += str.substr (0, eqpos) + '<\/a>';
    } else
	retstr += str;
    return retstr + '<\/td>';
}

function positionLayer () {
    var img = this.image;
    this.getObjMetrics (img);
    this.normalizeVars ();
    var xpos = img.width + this.hpad;
    if (this.positionleft)
	xpos = -this.lyr.offsetWidth - this.hpad;
    xpos += img.flyX;
    var ypos = img.flyY + this.vpad;
    if (this.position) {
	var strs = this.position.split (';');
	for (var i = 0; i < strs.length; ++i) {
	    var str = strs[i];
	    if ((pos = str.search (/[-|]/)) <= 0)
		continue;
	    var direct = str.substr (pos, 1);
	    var obj = img;
	    if (str.substr (0, pos) != 'IMG') {
		if (! (obj = findObj (str.substr (0, pos), d)))
		    continue;
		this.getObjMetrics (obj);
	    }
	    var posstr = str.substr (pos + 1);
	    var cmp = posstr.search (/[<=>]/);
	    if (cmp <= 0)
		continue;
	    var opos, mpos;
	    if (direct == '-') {
		opos = targetPos (posstr.substr (0, cmp), obj.flyX, obj.width);
		mpos = targetPos (posstr.substr (cmp + 1), xpos, this.lyr.offsetWidth);
	    } else {
		opos = targetPos (posstr.substr (0, cmp ), obj.flyY, obj.height);
		mpos = targetPos (posstr.substr (cmp + 1), ypos, this.lyr.offsetHeight);
	    }
	    var rel = posstr.substr (cmp, 1);
	    if ((rel == '<' && mpos < opos) || (rel == '>' && mpos > opos) || rel == '=') {
		if (direct == '-')
		    xpos += opos - mpos;
		else
		    ypos += opos - mpos;
	    }
	}
    }
    xpos = posInWindow (xpos, this.lyr.offsetWidth, window.pageXOffset, window.innerWidth);
    ypos = posInWindow (ypos, this.lyr.offsetHeight, window.pageYOffset, window.innerHeight);
    this.moveTo (xpos, ypos);
    if (this.tbl)
	this.lyr.style.clip = 'rect ( 0px ' + this.tbl.offsetWidth + 'px ' +
				this.tbl.offsetHeight + 'px 0px )';
}

function getObjMetricsIE (obj) {
    var oObj = obj;
    oObj.width = obj.offsetWidth || obj.width;
    oObj.height = obj.offsetHeight || obj.height;
    oObj.flyX = oObj.flyY = 0;
    var seenTable = 0;
    if (FlyLyr.isMac && oObj.offsetParent.tagName == 'BODY') {
	if (getInt (oObj.clientLeft) + getInt (oObj.clientTop)) {
	    oObj.flyX = oObj.clientLeft;
	    oObj.flyY = oObj.clientTop;
	} else {
	    oObj.flyX = oObj.offsetLeft;
	    oObj.flyY = oObj.offsetTop;
	}
	return;
    }
    for (; obj; obj = obj.offsetParent) {
	var tag = obj.tagName;
	if (! FlyLyr.noCpos[tag] && (! FlyLyr.isMac || obj != oObj) &&
		! FlyLyr.isOpera) {
	    oObj.flyX += getInt (obj.clientLeft);
	    oObj.flyY += getInt (obj.clientTop);
	}
	var noOent = FlyLyr.noOpos[tag];
	if (! noOent || (noOent < 0 && obj.currentStyle &&
		obj.currentStyle.display != 'block')) {
	    oObj.flyX += getInt (obj.offsetLeft);
	    oObj.flyY += getInt (obj.offsetTop);
	}
	if (FlyLyr.isMac && tag == 'TABLE')
	    if (seenTable++)
		oObj.flyY += getInt (obj.cellSpacing);
    }
}

function getObjMetricsDOM (obj) {
    var oObj = obj;
    obj.width = obj.width || obj.offsetWidth;
    obj.height = obj.height || obj.offsetHeight;
    oObj.flyX = oObj.flyY = 0;
    for (; obj; obj = obj.offsetParent) {
	if (obj.tagName == 'TABLE') {
	    var bord = parseInt (obj.border);
	    if (isNaN (bord)) {
		if (obj.getAttribute ('frame')) {
		    ++oObj.flyX;
		    ++oObj.flyY;
		}
	    } else if (bord > 0) {
		oObj.flyX += bord;
		oObj.flyY += bord;
	    }
	}
	oObj.flyX += obj.offsetLeft;
	oObj.flyY += obj.offsetTop;
    }
}

function getInt (n) {
    n = parseInt (n);
    if (isNaN (n))
	return 0;
    return n;
}

function targetPos (wherestr, start, len) {
    var where = wherestr.substr (0, 1);
    var adj = getInt (wherestr.substr (1));
    if (where == 'l' || where == 't')
	return start + adj;
    if (where == 'r' || where == 'b')
	return start + len + adj;
    return start + len / 2 + adj;
}

function posInWindow (loc, objSize, scroll, winSize) {
    var move = loc + objSize - scroll - winSize;
    move += FlyLyr.nsOffset;
    if (move > 0)
	loc -= move;
    if (loc < scroll)
	loc = scroll;
    return loc;
}

function FlyLyr (id, doclip) {
    this.lyr = findObj ('l_' + id);
    if (! d.all && ! d.getElementById) {
	this.lyr.captureEvents (Event.MOUSEOUT | Event.MOUSEOVER);
	this.lyr.bgColor = FlyLyr.defs.background;
    }
    this.lyr.onmouseover = function () {
	FlyLyr.showing.stopdelay ()
	ToShow.stopdelay ();
    };
    this.lyr.onmouseout = function () { mOut () };
    this.id = id;
    if (doclip && this.lyr.children && ! FlyLyr.isMac)
	this.tbl = this.lyr.children[0];
    FlyLyr.lyrs[id] = this;
    for (var a in FlyLyr.defs)
	this[a] = FlyLyr.defs[a];
}

function flyDefs (defs) {
    if (! defs)
	return;
    for (var d in defs)
	FlyLyr.defs[d] = defs[d];
}

function initFlyLyr () {
    FlyLyr.prototype.doHide = function () {
	this.stopdelay ();
	this.realHide ();
	if (this.hideImage)
	    this.hideImage (this.image, this.lyr);
	else if (this.outimg && this.image.tagName == 'IMG')
	    this.image.src = this.outimg;
	FlyLyr.showing = null;
    };
    FlyLyr.prototype.doShow = function () {
	if (! this.image && ! (this.image = findObj (this.id)))
	    return;
	this.positionLayer ();
	if (! this.outimg && this.image.tagName == 'IMG')
	    this.outimg = this.image.src;
	if (this.showImage)
	    this.showImage (this.image, this.lyr);
	else if (this.overimg && this.image.tagName == 'IMG')
	    this.image.src = this.overimg;
	this.realShow ();
	FlyLyr.showing = this;
    };
    FlyLyr.prototype.delayCallback = function () {
	if (this == FlyLyr.showing)
	    this.doHide ();
    };
    FlyLyr.prototype.setdelay = function () {
	this.delay = new Delay (this.timeout, this);
    };
    FlyLyr.prototype.stopdelay = function () {
	if (this.delay)
	    this.delay.stop ();
	return this.delay;
    };

    FlyLyr.lyrs = new Object ();
    FlyLyr.defs = {
	background: '#ffffff',
	titlebackground: '#333399',
	border: '#333399',
	useclass: 'navlink',
	titleclass: 'barlink',
	overimg: '/home/graphics/mo/arrow.gif',
	outimg: null,
	pause: 250,
	timeout: 1000,
	positionleft: 0,
	alignright: 0,
	hpad: 2,
	vpad: -2,
	position: '',
	preDetach: null,
	showImage: null,
	hideImage: null
    }
    FlyLyr.prototype.positionLayer = positionLayer;
    FlyLyr.nsOffset = 0;

    if (d.all && ! FlyLyr.isKonq) {
	FlyLyr.prototype.realHide = function () {
	    this.lyr.style.visibility = 'hidden';
	};
	FlyLyr.prototype.realShow = function () {
	    this.lyr.style.visibility = 'visible';
	};
	FlyLyr.prototype.getObjMetrics = getObjMetricsIE;
	if (FlyLyr.isOpera)
	    FlyLyr.prototype.normalizeVars = function () {};
	else
	    FlyLyr.prototype.normalizeVars = function () {
		window.innerWidth = d.body.clientWidth;
		window.innerHeight = d.body.clientHeight;
		window.pageXOffset = d.body.scrollLeft;
		window.pageYOffset = d.body.scrollTop;
	    };
	FlyLyr.prototype.moveTo = function (x, y) {
	    this.lyr.style.pixelLeft = x;
	    this.lyr.style.pixelTop = y;
	};
	FlyLyr.noCpos = {
	    'BODY': 1,
	    'TABLE': 1
	};
	FlyLyr.noOpos = {};
	if (! FlyLyr.isOpera)
	    FlyLyr.noOpos['A'] = -1;
	if (FlyLyr.isMac && ! FlyLyr.isOpera) {
	    FlyLyr.noOpos = FlyLyr.noCpos;
	    FlyLyr.noCpos = {
		'DIV': 1,
		'TD': 1,
		'TH': 1
	    };
	}
    } else if (d.getElementById) {
	FlyLyr.prototype.realHide = function () {
	    this.lyr.style.visibility =  'hidden';
	};
	FlyLyr.prototype.realShow = function () {
	    this.lyr.style.visibility = 'visible';
	}
	FlyLyr.prototype.getObjMetrics = getObjMetricsDOM;
	FlyLyr.prototype.normalizeVars = function () {};
	FlyLyr.prototype.moveTo = function (x, y) {
	    this.lyr.style.left = x + 'px';
	    this.lyr.style.top = y + 'px';
	};
    } else {
	FlyLyr.prototype.realHide = function () {
	    this.lyr.visibility = 'hide';
	};
	FlyLyr.prototype.realShow = function () {
	    this.lyr.visibility = 'show';
	};
	FlyLyr.prototype.getObjMetrics = function (obj) {
	    obj.flyX = obj.x;
	    obj.flyY = obj.y;
	};
	FlyLyr.prototype.normalizeVars = function () {
	    this.lyr.offsetHeight = this.lyr.clip.bottom;
	    this.lyr.offsetWidth = this.lyr.clip.right;
	};
	FlyLyr.prototype.moveTo = function (x, y) {
	    this.lyr.moveTo (x, y);
	};
	FlyLyr.nsOffset = 16;
    }
}

function ToShow (lyr) {
    if (! lyr || lyr == FlyLyr.showing)
	return;
    this.lyr = lyr;
    ToShow.stopdelay ();
    ToShow.queued = this;
    this.delay = new Delay (FlyLyr.defs.pause, this);
}

function initToShow () {
    ToShow.stopdelay = function () {
	var q = ToShow.queued;
	if (q) {
	    q.delay.stop ();
	    ToShow.queued = null;
	}
	return q;
    };
    ToShow.prototype.delayCallback = function () {
	ToShow.queued = null;
	if (FlyLyr.showing)
	    FlyLyr.showing.doHide ();
	if (this.lyr)
	    this.lyr.doShow ();
    };
}

function Delay (delay, obj) {
    this.obj = obj;
    var uid = ++Delay.nuid;
    this.timeoutid = setTimeout ('Delay.dispatch (' + uid + ')', delay);
    this.uid = uid;
    Delay.disparr[uid] = this;
}

function initDelay () {
    Delay.prototype.stop = function () {
	clearTimeout (this.timerid);
	delete Delay.disparr[this.uid];
    };
    Delay.dispatch = function (uid) {
	var item = Delay.disparr[uid];
	if (! item)
	    return;
	item.obj.delayCallback ();
	item.stop ();
    };
    Delay.nuid = 0;
    Delay.disparr = new Object;
}

function findObj (n, od) { // based on MM_findObj v3.0 from Macromedia Dreamweaver
    var p, i, x;
    if (! od)
	od = d;
    if ((p = n.indexOf ('?')) > 0 && parent.frames.length) {
	od = parent.frames[n.substring (p + 1)].document;
	n = n.substring (0, p);
    }
    if (! (x = od[n]) && d.all)
	x = od.all[n];
    if (! x && d.getElementById)
	x = d.getElementById (n);
    for (i = 0; ! x && i < od.forms.length; i++)
	x = od.forms[i][n];
    for (i = 0; ! x && od.layers && i < od.layers.length; i++)
	x = findObj (n, od.layers[i].document);
    return x;
}

function mIn (id) {
    if (! doDHTML)
	return;
    var lyr = FlyLyr.lyrs[id];
    if (! lyr) {
	if (findObj ('l_' + id))
	    useLayer (id);
	lyr = FlyLyr.lyrs[id];
	if (! lyr)
	    return;
    }
    if (lyr == FlyLyr.showing)
	lyr.stopdelay ();
    else
	new ToShow (lyr);
}

function mOut () {
    if (! doDHTML)
	return;
    var lyr = FlyLyr.showing;
    if (! ToShow.stopdelay () && lyr)
	lyr.setdelay ();
}
