
/* $Id: sharkfin.js,v 1.3 2006/01/26 21:04:15 sharkey Exp $ */

function Sharkfin ( finId, sharkId )
{

/*---------------------------------------------------------------------------*/
/*                                                                PROPERTIES */

	// For event and iterator binding
	var _this = this;
	
	// Element ids
	this.finId = finId;
	this.sharkId = sharkId;
	
	// Monitor iteration interval
	this.monitorInterval = 10; // Higher if supportsPositionFixed?
	
	// Window state cache
	this.viewX = -1;
	this.viewY = -1;
	this.scrollX = -1;
	this.scrollY = -1;
	this.sharkX = -1;
	this.sharkY = -1;
	
	// Current state of shark
	this.submerged = -1;
	
/*---------------------------------------------------------------------------*/
/*                                                            INITIALIZATION */

	this.initialize = function () {
		_this.startMonitor();
	}
	if (window.addEventListener) window.addEventListener('load', this.initialize, false);
	else if (window.attachEvent) window.attachEvent('onload', this.initialize);
	

/*---------------------------------------------------------------------------*/
/*                                                           ELEMENT HANDLES */

	this.fin = function () { return document.getElementById(this.finId); }
	this.shark = function () { return document.getElementById(this.sharkId); }

	
/*---------------------------------------------------------------------------*/
/*                                                        ELEMENT POSITIONER */

	this.once = true;
	this.position = function () {
	
		// Check for existence of elements
		if (!this.fin() || !this.shark()) return false;
		
		// Is this the first positioning attempt?
		var firstTime = this.submerged==-1;
		
		// Is shark element below the fold?
		var submerged = this.sharkY > (this.viewY + this.scrollY);
		
		// If below the fold...
		if (submerged) {
			if (!this.submerged || firstTime) {
				this.fin().style.display = 'block';
				if (this.supportsPositionFixed()) {
					this.fin().style.position = 'fixed';
					this.fin().style.bottom = '0px';
				}
			}
			if (!this.supportsPositionFixed()) {
				this.fin().style.position = 'absolute';
				this.fin().style.left = this.sharkX+'px';
				this.fin().style.top = (this.viewY+this.scrollY-this.fin().offsetHeight)+'px';
			}
		}
		
		// Otherwise...
		else if (this.submerged || firstTime) {
			this.fin().style.display = 'none';
		}
		
		// Update submerged state
		this.submerged = submerged;
	}

/*---------------------------------------------------------------------------*/
/*                                                DETECT WINDOW STATE CHANGE */

	this.stateChange = function () {
	
		// Get window state
		var viewX = this.viewableWidth();
		var viewY = this.viewableHeight();
		var scrollX = this.scrollWidth();
		var scrollY = this.scrollHeight();
		if (this.shark()) {
			//var sharkX = this.shark().offsetLeft;
			var sharkX = this.fullOffsetLeft(this.shark());
			//var sharkY = this.shark().offsetTop;
			var sharkY = this.fullOffsetTop(this.shark());
		}
		
		// State change?
		var stateChange = viewX!==this.viewX || viewY!==this.viewY ||
						  scrollX!==this.scrollX || scrollY!==this.scrollY ||
						  sharkX!==this.sharkX || sharkY!==this.sharkY;
		
		// Update cache properties on state change
		if (stateChange) {
			this.viewX = viewX;
			this.viewY = viewY;
			this.scrollX = scrollX;
			this.scrollY = scrollY;
			this.sharkX = sharkX;
			this.sharkY = sharkY;
		}
		
		// Return state change
		return stateChange;
	}
	
	this.checkState = function () {
		// Called by iterator, use _this
		if (_this.stateChange()) _this.position();
	}

/*---------------------------------------------------------------------------*/
/*                                                          MONITOR ITERATOR */

	this.monitor = null;
	this.startMonitor = function () {
		this.monitor = setInterval(this.checkState, this.monitorInterval);
	}
	this.stopMonitor = function () {
		clearInterval(this.monitor);
	}
	
/*---------------------------------------------------------------------------*/
/*                                                        WINDOW INFORMATION */

	// Get the viewable width and height
	this.viewableWidth = function () {
	    if (window.innerWidth) return top.window.innerWidth;
	    else if (document.body.parentElement.clientWidth) return top.document.body.parentElement.clientWidth;
	    else if (document.body && document.body.clientWidth) return top.document.body.clientWidth;
	}
	this.viewableHeight = function () {
	    if (window.innerHeight) return top.window.innerHeight;
	    else if (document.body.parentElement.clientHeight) return top.document.body.parentElement.clientHeight;
	    else if (document.body && document.body.clientHeight) return top.document.body.clientHeight;
	}
	
	// Get scroll amount
	this.scrollWidth = function () {
		if (top.document.body.parentNode.scrollLeft) return top.document.body.parentNode.scrollLeft;
		else if (top.document.body.scrollLeft) return top.document.body.scrollLeft;
		else if (top.window.pageXOffset) return top.window.pageXOffset;
		else if (top.window.scrollX) return top.window.scrollX;
		else return 0;
	}
	this.scrollHeight = function () {
		if (top.document.body.parentNode.scrollTop) return top.document.body.parentNode.scrollTop;
		else if (top.document.body.scrollTop) return top.document.body.scrollTop;
		else if (top.window.pageYOffset) return top.window.pageYOffset;
		else if (top.window.scrollY) return top.window.scrollY;
		else return 0;
	}
	
	// Full offset position
	this.fullOffsetLeft = function (element) {
		var offset = 0;
		do { offset = offset + element.offsetLeft; element = element.offsetParent } while (element);
		return offset;
	}
	this.fullOffsetTop = function (element) {
		var offset = 0;
		do { offset = offset + element.offsetTop; element = element.offsetParent } while (element);
		return offset;
	}

/*---------------------------------------------------------------------------*/
/*                                           SUPPORT FOR CSS POSITION: FIXED */

	this.supportsPositionFixed = function () {
	
		/*	JAN 26 2006: Tested in:
			Win: IE (6.0.29 SP2), Firefox (1.5), Opera (8.51), Netscape (7.1)
			Mac: Safari (2.0.3), Firefox (1.0.7, 1.5), OmniWeb (5.1.2),
				Opera (8.5), Camino (0.8.4), IE (5.2) */
		
		// Opera identifies itself as MSIE, but also as Opera
		var isOpera = navigator.userAgent.indexOf('Opera') > -1;
		
		var isIE = navigator.userAgent.indexOf('MSIE') > -1 && !isOpera;

		/*	Will have to add a check for version >= 7 when IE 7 (which
			will reportedly support position: fixed) is released */
		
		return !isIE;
	}

}
