/*
DynamicLayer Object Library
Revised to support Netscape4, IE4, IE5, and Netscape6 (M16+)
Michael Masumoto
michael@michaelmasumoto.com
On the web at: http://www.michaelmasumoto.com/

mmmObjectLib.js

All code for this library is copyright 1998-2000 Michael Masumoto
except where otherwise stated. This code may be freely
used and distributed as long as this
citation and all accompanying acknowledgements are credited.
Updated: June 20, 2000

Acknowledgements:
Some of my Dynamic HTML code fragments are based on the work of other people.
Dan Steinman's DHTML tutorial (http://www.dansteinman.com/dynduo/) provided the
animation methods for the DynamicLayer object (moveTo, moveBy, slideTo, slideBy, slide).
My DynamicLayer object was also heavily influenced by his dynLayerObject coding style.
I am also indebted to Matthew Zandstra, for his work in "Dynamic HTML Unleashed" from
Sams.net Publishing (creating cross-browser compatible code using argument arrays and
for loops).
I would also like to thank my DHTML students at San Francisco State University's Multimedia
Studies Program, especially Rob Cole for his research into JavaScript's object prototype
inheritance hierarchy.
Netscape provided the javascript browser sniffer code (copyright 1999 Netscape Communications).
Reference Books:
"JavaScript: the Definitive Guide, Third Edition", David Flanagan, O'Reilly & Associates.
"Dynamic HTML: the Definitive Reference", Danny Goodman, O'Reilly & Associates.
*/

// This is a simplified version of the JavaScript Client Sniffer code 
// found at http://developer.nextscape.com/docs/examples/javascript/browser_type.html

function Is() {
	// convert all characters to lowercase to simplify testing
    var agt=navigator.userAgent.toLowerCase();

    // *** BROWSER VERSION ***
    // Note: On IE5, these return 4, so use is.ie5up to detect IE5.
    this.major = parseInt(navigator.appVersion);
    this.minor = parseFloat(navigator.appVersion);

    this.nav  = ((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1) && (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1) && (agt.indexOf('webtv')==-1));
    this.nav3 = (this.nav && (this.major == 3));
    this.nav4 = (this.nav && (this.major == 4));
    this.nav4up = (this.nav && (this.major >= 4));
    this.navonly  = (this.nav && ((agt.indexOf(";nav") != -1) || (agt.indexOf("; nav") != -1)));
    this.nav5 = (this.nav && (this.major == 5));
    this.nav5up = (this.nav && (this.major >= 5));

    this.ie   = (agt.indexOf("msie") != -1);
    this.ie3  = (this.ie && (this.major < 4));
    this.ie4  = (this.ie && (this.major == 4) && (agt.indexOf("msie 5.0")==-1) );
    this.ie4up  = (this.ie  && (this.major >= 4));
    this.ie5  = (this.ie && (this.major == 4) && (agt.indexOf("msie 5.0")!=-1) );
    this.ie5up  = (this.ie  && !this.ie3 && !this.ie4);

    this.aol   = (agt.indexOf("aol") != -1);
    this.aol3  = (this.aol && this.ie3);
    this.aol4  = (this.aol && this.ie4);

    this.opera = (agt.indexOf("opera") != -1);
    this.webtv = (agt.indexOf("webtv") != -1);

    // *** PLATFORM ***
    this.win = ( (agt.indexOf("win")!=-1) || (agt.indexOf("16bit")!=-1) );
    this.mac = (agt.indexOf("mac")!=-1);
};

var is;
var isIE3Mac = false;
// this section is designed specifically for IE3 for the Mac
if ((navigator.appVersion.indexOf("Mac")!=-1) && (navigator.userAgent.indexOf("MSIE")!=-1) && (parseInt(navigator.appVersion)==3)) {
	isIE3Mac = true;
} else {
	is = new Is();
};


// Constructor for the DynamicLayer Object

function DynamicLayer() {
	
	// properties:
	
	// NB: all properties for a layer will be initialized using
	// the initialize() method for the DynamicLayer object.
	// Values initialized here are merely placeholders.
	// This is to allow the DynamicLayer object to be used
	// as a base class for the purposes of creating child
	// classes of the DynamicLayer object. See section 8.5.7,
	// "Superclasses and Subclasses" of "JavaScript: The Definitive Guide"
	// for more information.
	
	// The css and ref properties of the DynamicLayer object are the
	// real workhorses for this object. Once initialized, each contains a browser-specific
	// reference to the DOM for the DIV layer, whether nested or not nested.
	
	// The css property refers to CSS-specific calls to the DOM
	// (such as references to top, left, visibility, z-index, clip, etc).
	// Here are examples of what the DOM references for the css property are 
	// actually comprised of:
	// Netscape4: document.divLayerName OR document.parentDiv.document.childDiv (nested syntax)
	// IE: document.all.divLayerName.style
	// Netscape6: document.getElementById("divLayerName").style
	// The css property allows you to use a consistent syntax when referring to the
	// layer, such as:
	// divLayerName.css.left = 10; (to move the divLayerName DIV to a point 10 pixels from
	// the left of the browser window).
	
	// The ref property refers to the DIV layer itself, and is used primarily
	// for the write() method of the DynamicLayer object.
	// Here are the actual calls to the DOM that the ref property uses:
	// Netscape4: document.divLayerName OR
	// document.parentDiv.document.childDiv (nested syntax)
	// (this can be used to call document.write() and document.close() for the layer
	// using the following syntax: divLayerName.ref.document.write();
	// divLayerName.ref.document.close(); This is also used for the switchImage() method)
	// IE: document.all.divLayerName
	// (again, used for writing to a divLayer, which requires setting of the innerHTML
	// property for the DIV tag, for example:
	// divLayerName.ref.innerHTML = "Text String";)
	// Netscape6: (Mozilla build M16 and greater)
	// Like recombinant IE and Netscape, following the W3C specifications:
	// divLayerName.ref.innerHTML = "Text String"; (which is equal to...)
	// document.getElementById("divLayerName").innerHTML = "Text String";
	
	this.css = 0;
	this.ref = 0;
	
	// The following x and y properties for the DynamicLayer object are
	// integer values. They can be referenced by your code to determine the current
	// x and y coordinates for the layer in question.
	// Example: var current_x = divLayerName.x;
	// Example: if (divLayerName.x == 10) divLayerName.moveTo(20,40);
	
	// The home_x and home_y properties remain constant
	// throughout the operation of the program. Their purpose is to provide a means
	// of returning a layer to its initial starting position, assuming that
	// the DIV layer has been moved around at some point.
	
	// Again, all initialization for the DynamicLayer objects is done utilizing
	// the initialize() method for each instance of the DynamicLayer object;
	// the values set below are placeholders only.
	
	this.x = 0;
	this.y = 0;
	this.home_x = 0;
	this.home_y = 0;
	
	// more properties:
	
	// layerID and obj
	// these properties are required for the slide methods to operate.
	// Both need to be initialized using the initialize() method for the
	// DynamicLayer object.
	// layerID is a string representing the ID of the DIV layer.
	// The DynamicLayer object name and the DIV ID must NOT be the same.
	
	this.layerID = "";
	this.obj = "";
	
	// defaultZindex
	// This property contains the initial z-index of the DynamicLayer object.
	// If we have caused our DIV layer to jump forward and backward, we
	// can look at this property to find out what the original z-index was.
	// This property will be set by the initialize() method for the DynamicLayer object.
	
	this.defaultZindex = 0;
	
	// isVisible
	// this property is a boolean stating current visibility.
	// if true, the layer is visible.
	// if false, the layer is hidden.
	
	this.isVisible = false;
	
	// methods:
	
	this.initialize = initDynamicLayer;
	this.setZindex = setZindex;
	this.resetZindex = resetZindex;
	this.hide = hideLayer;
	this.show = showLayer;
	this.switchImage = switchImage;
};

// prototype methods for DynamicLayer object
// these methods are only accessed by a DynamicLayer object as needed.
// they are invoked in the same manner that regular DynamicLayer object methods are invoked,
// i.e. singleDiv.moveTo(1,2)

DynamicLayer.prototype.moveTo = moveTo;
DynamicLayer.prototype.moveBy = moveBy;
DynamicLayer.prototype.slideTo = dynLayerSlideTo;
DynamicLayer.prototype.slideBy = dynLayerSlideBy;
DynamicLayer.prototype.slide = dynLayerSlide;
DynamicLayer.prototype.write = writeLayer;

/* BEGIN DynamicLayer METHOD DEFINITIONS */

// initDynamicLayer()
// DynamicLayer object method: initialize()
// xpos (int) (initial left property for layer; must always be first argument passed)
// ypos (int) (initial top property for layer; must always be second argument passed)
// zpos (int) (initial z-index for layer; must always be third argument passed)
// myVisible (boolean) (initial visibility for layer; must always be fourth argument passed)
// (false = hidden, true = visible)
// pass string representing the DIV ID.
// i.e. singleDiv.initialize(10, 10, 0, true, "singleDIV")
// If DIV is nested, pass the parent DIV ID, then the child DIV ID.
// i.e. childDiv.initialize(10, 10, 0, true, "parentDIV", "childDIV")
// Theoretically, this method can handle any number of levels of nesting,
// by passing parent - child - child of child - child of child of child, etc,
// but in reality, IE and Netscape can only handle one level of nesting
// before diverging so wildly in implementation that things get messed up.

// Remember: initialize a global variable for each instance of the DynamicLayer
// object at the beginning of your JavaScript for a DHTML page, i.e.:
// var singleDiv = new DynamicLayer();
// Then, initialize the DynamicLayer objects that you have created from
// a custom init() routine which is called from the onLoad handler of
// the BODY tag, i.e. <BODY onLoad="init()">
// In your init() handler, you would need code similar to the following:
// singleDiv.initialize(10, 10, 0, true, "singleDiv");
// You must always pass the left, top, z-index, and isVisible boolean for the layer first,
// then the strings representing DIV IDs.

// The initialize() method must ONLY be called after the HTML page is fully loaded,
// as it refers to DIV tags which do not exist before the page is loaded.
// Also, remember that you must initialize a style property for a layer
// before you can see it in javascript; that is the implementation for IE5 and Netscape6.
// Refer to mmmObjectLibInstruct.txt for further information.

/*
	Remember: to support latest browser implementations, you must ALWAYS
	initialize a style property before you can look at it in javascript.
*/

function initDynamicLayer(xpos, ypos, zpos, myVisible) {
	if (is.nav4) {
	
		// the following code pulls information from the argument array for the function,
		// and creates Netscape-safe DIV references, even for nested DIV tags.
		// i.e. document.myDiv OR document.parentDiv.document.childDiv
		// It then sets the css and ref properties for the instance of the DynamicLayer
		// object to their correct values.
		// css property: document.myDiv
		// ref property: document.myDiv
		
		var value = "";
		for (var x=4;x<arguments.length;x++) {
			value += "document." + arguments[x];
			if (x!=arguments.length-1) {
				value += ".";
			};
		};
		
		// properties
		this.css = eval(value);
		this.ref = eval(value);
	
	} else if (is.nav5up) {
		// gets the last DIV ID name in the arguments array, and
		// creates W3C standard DOM syntax, which is also supported
		// by IE5, but inconsistently (???)
		// css property: document.getElementById("divID").style;
		// ref property: document.getElementById("divID");
		
		// properties
		this.css = document.getElementById(arguments[arguments.length-1]).style;
		this.ref = document.getElementById(arguments[arguments.length-1]);
	
	} else if (is.ie4up) {
	
		// the following code looks at all the DIV ID names passed into the function,
		// and pulls just the last one to create dHTML-appropriate syntax for IE4.
		// This is also supported by IE5.
		// css property: document.all.myDiv.style
		// ref property: document.all.myDiv
	
		var cssValue = "document.all." + arguments[arguments.length-1] + ".style";
		var refValue = "document.all." + arguments[arguments.length-1];
		
		// properties
		this.css = eval(cssValue);
		this.ref = eval(refValue);
	};
	
	// more property initialization:
	
	this.css.left = xpos;
	this.x = xpos;
	this.css.top = ypos;
	this.y = ypos;
	this.home_x = xpos;
	this.home_y = ypos;
	
	this.layerID = arguments[arguments.length-1];
	this.obj = this.layerID + "Object";
	eval(this.obj + "=this");
	
	this.css.zIndex = zpos;
	this.defaultZindex = zpos;
	
	if (myVisible) {
		if (is.nav4) {
			this.css.visibility = "show";
		} else {
			this.css.visibility = "visible";
		};
	} else {
		if (is.nav4) {
			this.css.visibility = "hide";
		} else {
			this.css.visibility = "hidden";
		};
	};
	this.isVisible = myVisible;
	
};

// DynamicLayer object method: setZindex() 
// sets a DynamicLayer object to a new z-index position.
// pass z (int) representing new z-index position for layer.

function setZindex(zpos) {

	this.css.zIndex = zpos;
};

// DynamicLayer object method: resetZindex()
// returns a DynamicLayer object to its default z-index position.

function resetZindex() {

	this.css.zIndex = this.defaultZindex;
};

// hideLayer()
// DynamicLayer object method: hide()
// hides an instance of a DynamicLayer.

function hideLayer() {

	if (is.nav4) {
		this.css.visibility = "hide";
	} else if (is.nav5up || is.ie4up) {
		this.css.visibility = "hidden";
	};
	
	this.isVisible = false;
};

// showLayer()
// DynamicLayer object method: show()
// makes an instance of a DynamicLayer visible.

function showLayer() {

	if (is.nav4) {
		this.css.visibility = "show";
	} else if (is.nav5up || is.ie4up) {
		this.css.visibility = "visible";
	};
	
	this.isVisible = true;
};


function moveTo(x,y) {

	this.x = x;
	this.css.left = this.x;
	this.y = y;
	this.css.top = this.y;
};

function moveBy(x,y) {

	this.x += x;
	this.css.left = this.x;
	this.y += y;
	this.css.top = this.y;
};

// OK, I didn't write these methods. My understanding is:
// pass distx (int representing how far x you want to go), disty (int representing
// how far y you want to go), inc (int representing increments of pixels (???)),
// speed (int representing how fast it should go (the smaller the number, the faster???)),
// fn (javascript code to be executed at the end of the animation)

function dynLayerSlideBy(distx,disty,inc,speed,fn) {
	if (!this.slideActive) {
		var endx = this.x + distx;
		var endy = this.y + disty;
		var num = Math.sqrt(Math.pow(distx,2) + Math.pow(disty,2))/inc;
		var dx = distx/num;
		var dy = disty/num;
		this.slideActive = 1;
		this.slide(dx,dy,endx,endy,speed,fn);
	};
};

// this slideTo method is very similar to the previous method, except you need
// to tell it the ending x,y coordinates for the animation instead of the relative distance.

function dynLayerSlideTo(endx,endy,inc,speed,fn) {
	if (!this.slideActive) {
		var distx = endx - this.x;
		var disty = endy - this.y;
		var num = Math.sqrt(Math.pow(distx,2) + Math.pow(disty,2))/inc;
		var dx = distx/num;
		var dy = disty/num;
		this.slideActive = 1;
		this.slide(dx,dy,endx,endy,speed,fn);
	};
};

// this slide method runs the show for the animation for all three methods.
// You won't use this method by itself, just slideTo() and slideBy() above.

function dynLayerSlide(dx,dy,endx,endy,speed,fn) {
	if (!fn) fn = null;
	if (this.slideActive && (Math.floor(Math.abs(dx))<Math.floor(Math.abs(endx-this.x)) || Math.floor(Math.abs(dy))<Math.floor(Math.abs(endy-this.y)))) {
		this.moveBy(dx,dy);
		setTimeout(this.obj+".slide("+dx+","+dy+","+endx+","+endy+","+speed+",\""+fn+"\")",speed);
	} else {
		this.slideActive = 0;
		this.moveTo(endx,endy);
		eval(fn);
	};
};

// this DynamicLayer method writes over the current contents of the DIV,
// replacing it with fresh HTML code.
// pass text (string)

function writeLayer(myText) {

	if (is.nav4) {
		this.ref.document.write(myText);
		this.ref.document.close();
	} else if (is.nav5up || is.ie4up) {
		this.ref.innerHTML = myText;
	};
};

// switchImage()
// DynamicLayer object method: imageSwitch()
// pass myImgName (string) -- the NAME attribute of the IMG tag you want to switch.
// pass myImgObj2Switch2 (image) -- the javascript image object you wish to switch to.

function switchImage(myImgName, myImgObj2Switch2) {
	
	// declare variable which is to act as reference to
	// the IMG tag nested in the DynamicLayer.
	// This IMG tag is the one upon which we will perform
	// the image switch.
	
	var myIMG = "";
	
	// Now, we have to conditionalize, because the manner in which
	// Netscape refers to the image is significantly different
	// than the way that IE refers to the image.
	// If "imgName" is the name of the image tag in question:
	// Netscape 4 follows its tree hierarchy, i.e.
	// document.singleDiv.document.imgName
	// OR in the case of a nested DIV tag:
	// document.parentDiv.document.childDiv.document.imgName
	// IE follows the node structure for image switching, referring
	// directly to the IMG tag by name, accessed via the document.all property:
	// document.all.imgName
	// Netscape 6 follows the W3C node structure for accessing the image:
	// document.getElementById("imgName")
	// (this syntax can also be used by IE5, but I'm not sure if it's consistent or not)
	
	// Hey, don't blame me... I'm not making this up, you know!
	
	if (is.nav4) {
		myIMG = eval("this.ref.document." + myImgName);
	} else if (is.nav5up) {
		myIMG = document.getElementById(myImgName);
	} else if (is.ie4up) {
		myIMG = eval("document.all." + myImgName);
	};
	
	// switch image:
	
	myIMG.src = myImgObj2Switch2.src;
};

/* END OF DynamicLayer METHOD DEFINITIONS */
