/*
 * Flyout menus for the University of Washington Home Page
 * University of Washington / Computing and Communications
 * April, 2003
 * Documentation can be found at
 *     http://www.washington.edu/webinfo/case/flyout/
 * $Id: flyout.js,v 1.44 2003/04/25 00:17:27 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 (/^ +/, '');	// left trim
			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="left"';		// TS 4.29.03
		
		if (fd.titlebackground)
	    titleargs += ' bgcolor="' + fd.titlebackground + '"';

		d.write ('<tr>' + buildCell (title, fd.titleclass ? fd.titleclass : fd.useclass, titleargs, false) + '<\/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, true) + '<\/tr>' + "\n");
  }
  
  d.write ('<\/table><\/td><\/tr><\/table><\/div>' + "\n");
  
  new FlyLyr (id, 1);
}

function buildCell (str, fc, args, subnav) 
{
	var eqpos = str.indexOf ('=');
	var atpos = str.indexOf ('@');
	var retstr = '<td class="' + fc + '"';

  if (args)
		retstr += ' ' + args;
  retstr += '>';

	if (eqpos > 0) 
	{
		if (subnav)
		{
			if (atpos > eqpos)
				retstr += '<a class="SubNav" href="' + str.substr (eqpos + 1, atpos - eqpos - 1) + '" target="' + str.substr (atpos + 1) + '">';
			else
				retstr += '<a class="SubNav" href="' + str.substr (eqpos + 1) + '">';
		}
		else
		{
			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) - 4;		// TS 4.29.03
  ypos = posInWindow (ypos, this.lyr.offsetHeight, window.pageYOffset, window.innerHeight) + 20;	// TS 4.29.03
  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') 
    {
			oObj.flyX = oObj.clientLeft;
			oObj.flyY = oObj.clientTop;
			return;
    }

    for (; obj; obj = obj.offsetParent) 
    {
			if (! FlyLyr.noCpos[obj.tagName] && (! FlyLyr.isMac || obj != oObj) && ! FlyLyr.isOpera) 
			{
				oObj.flyX += getInt (obj.clientLeft);
				oObj.flyY += getInt (obj.clientTop);
			}
			
			if (! FlyLyr.noOpos[obj.tagName]) 
			{
				oObj.flyX += getInt (obj.offsetLeft);
				oObj.flyY += getInt (obj.offsetTop);
			}
			
			if (FlyLyr.isMac && obj.tagName == 'TABLE')
		    if (seenTable++)
					oObj.flyY += getInt (obj.cellSpacing);
    }
}

function getObjMetricsDOM (obj) 
{
	var oObj = obj;
  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 ();
		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 Defs defined */
  FlyLyr.lyrs = new Object ();
  FlyLyr.defs = 
  {
		background: '#979384',
		titlebackground: '#7e383a',
		border: '#7e383a',
		useclass: 'navlink',
		titleclass: 'barlink',
		overimg: '/Images/Clear.gif',
		outimg: '/Images/Clear.gif',
		pause: 250,
		timeout: 500,
		positionleft: 0,
		alignright: 0,
		hpad: 0,
		vpad: -2,
		position: ''
  }
  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.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';
		}; /* add ; - ts 4.27.03*/
		
		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;
}

// based on MM_findObj v3.0 from Macromedia Dreamweaver
function findObj (n, od) 
{ 
	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 ();
}

