/*
 * Flyout menus for the University of Washington Home Page
 * University of Washington / Computing and Communications
 * October, 2002
 * Documentation can be found at
 *     http://www.washington.edu/webinfo/case/flyout/
 * $Id: flyout.js,v 1.34 2002/12/20 01:36:58 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;
var isOpera = 0;
var versIE = 0;

if (d.layers || d.all || d.getElementById) {
    var vers = navigator.appVersion.split ("MSIE ");
    vers = vers[vers.length - 1];
    versIE = parseInt (vers);
    if (navigator.appVersion.indexOf ("MSIE") < 0 ||
	    vers.indexOf ("Mac") < 0 || versIE >= 5) {
	doDHTML = 1;
	isOpera = navigator.userAgent.indexOf (" Opera ") >= 0;

	initFlyLyr ();
	initToShow ();
	initDelay ();

	d.write ("<style type='text/css'>" +
		    ".flyout { visibility: hidden; position: absolute; " +
		    "left: 0; top: 0; }" +
		    ".flyoutindent {font-size: xx-small; }<\/style>");
    }
}

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);
}

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.x + FlyLyr.usepos['startX'];
    var ypos = img.y + this.vpad + FlyLyr.usepos['startY'];
    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.x, obj.width);
		mpos = targetPos (posstr.substr (cmp + 1), xpos, this.lyr.offsetWidth);
	    } else {
		opos = targetPos (posstr.substr (0, cmp ), obj.y, 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 origObj = obj;
    origObj.width = obj.offsetWidth || obj.width;
    origObj.height = obj.offsetHeight || obj.height;
    origObj.x = origObj.y = 0;
    for (; obj && obj.parentElement; obj = obj.parentElement) {
	if (! FlyLyr.usepos[obj.tagName])
	    continue;
	origObj.x += obj.offsetLeft;
	origObj.y += obj.offsetTop;
	if (FlyLyr.unmacOffset)
	    continue;
	for (i = 0; i < d.styleSheets.length; ++i)
	    for (j = 0; j < d.styleSheets[i].rules.length; ++j) {
		r = d.styleSheets[i].rules[j];
		if (r.selectorText == obj.tagName) {
		    origObj.x += parseInt (r.style['paddingLeft']) +
				    parseInt (r.style['marginLeft']);
		    origObj.y += parseInt (r.style['paddingTop']) +
				    parseInt (r.style['marginTop']);
		}
	    }
    }
}

function targetPos (wherestr, start, len) {
    var where = wherestr.substr (0, 1);
    var adj = parseInt (wherestr.substr (1));
    if (isNaN (adj))
    	adj = 0;
    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;
    if (! d.all)
	move += FlyLyr.unmacOffset;
    if (move > 0)
	loc -= move;
    if (loc < scroll)
	loc = scroll;
    return loc;
}

function FlyLyr (id) {
    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 (this.lyr.children && FlyLyr.unmacOffset)
	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 ();
	this.image.src = this.outimg;
	FlyLyr.showing = null;
    };
    FlyLyr.prototype.doShow = function () {
	if (! this.image && ! (this.image = findObj (this.id)))
	    return;
	this.positionLayer ();
	this.realShow ();
	this.image.src = this.overimg;
	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: '#aaaaaa',
	border: '#000000',
	useclass: 'navlink',
	titleclass: 'barlink',
	overimg: '/images/arrow.gif',
	outimg: '/images/noarrow.gif',
	pause: 250,
	timeout: 1000,
	positionleft: 0,
	alignright: 0,
	hpad: 2,
	vpad: -2,
	position: ''
    }
    FlyLyr.unmacOffset = navigator.platform.indexOf ("Mac") != -1 ? 0 : 16;
    FlyLyr.prototype.positionLayer = positionLayer;

    if (d.all) {
	FlyLyr.prototype.realHide = function () {
	    this.lyr.style.visibility = 'hidden';
	};
	FlyLyr.prototype.realShow = function () {
	    this.lyr.style.visibility = 'visible';
	};
	FlyLyr.prototype.getObjMetrics = getObjMetricsIE;
	FlyLyr.prototype.normalizeVars = function () {
	    if (! isOpera) {
		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.usepos = {
	    'BODY': 1,
	    'IMG': 1,
	    'TABLE': 1,
	    'TD': 1,
	    'startX': 0,
	    'startY': 0
	};
	if (isOpera) {
	    FlyLyr.usepos['TR'] = 1;
	    FlyLyr.usepos['A'] = 1;
	} else if (versIE < 5) {
	    FlyLyr.usepos['TR'] = 1;
	} else if (! FlyLyr.unmacOffset) {
	    FlyLyr.usepos['startX'] = 2;
	    FlyLyr.usepos['startY'] = 6;
	    FlyLyr.usepos['TBODY'] = 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 = function (obj) {};
	FlyLyr.prototype.normalizeVars = function () {};
	FlyLyr.prototype.moveTo = function (x, y) {
	    this.lyr.style.left = x + 'px';
	    this.lyr.style.top = y + 'px';
	};
	FlyLyr.usepos = {
	    'startX': 0,
	    'startY': 0
	};
    } else {
	FlyLyr.prototype.realHide = function () {
	    this.lyr.visibility = 'hide';
	};
	FlyLyr.prototype.realShow = function () {
	    this.lyr.visibility = 'show';
	};
	FlyLyr.prototype.getObjMetrics = function (obj) {};
	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.usepos = {
	    'startX': 0,
	    'startY': 0
	};
    }
}

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)
	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 ();
}
