// iceBox by Aaron Gough 2008. http://aarongough.com
// Development sponsored in part by Walden http://waldendesign.com

// This work is licensed under the Creative Commons Attribution-Share Alike 3.0 License. 
// To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ 



// This object implements an effect similar to the 'lightbox' script
// that has found common use around the 'net. Main advantages of this script being
// that it doesn't pollute the global namespace, that it is lightweight, AJAX capable, 
// automatically resizes the enlared image to fit the browser window if it is too big,
// and doesn't rely on any javascript libraries to operate. Although it will automatically
// detect the jQuery library and make use of it's advanced animation and event registration
// functions if they are available
function iceBox2 ( closeButton, loadingImage, defaultWidth, defaultHeight )
	{
	// *************************************************
	// this function sets up the object properties and methods required to
	// run the object.
	this.init = function ()
		{
		// first we need to create the div that provides the background overlay
		this.overlay = document.createElement("div");
		this.overlay.id = "icebox_overlay";
		this.overlay.style.display = "none";
		this.overlay.style.position = "fixed";
		this.overlay.style.top = "0px";
		this.overlay.style.left = "0px";
		this.overlay.style.width = "100%";
		this.overlay.style.zIndex = "9998";
		this.overlay.onclick = this.hideIceBox;
		document.getElementsByTagName("body")[0].appendChild( this.overlay );
		
		// now we need to create the iceBox container
		this.iceBoxDiv = document.createElement( "div" );
		this.iceBoxDiv.id = "icebox2";
		this.iceBoxDiv.style.display = "none";
		this.iceBoxDiv.style.zIndex = 9999;
		this.iceBoxDiv.style.position = "absolute";
		this.iceBoxDiv.onclick = this.hideIceBox;
		document.body.appendChild( this.iceBoxDiv );
		
		// now create the close button that goes in the iceBox
		this.closeButton = document.createElement("img");
		this.closeButton.src = closeButton;
		this.closeButton.id = "icebox_close_button";
		this.closeButton.onclick = this.hideIceBox;
		this.iceBoxDiv.appendChild( this.closeButton );
		
		// add the blank image that we will dynamically load the images into later
		this.image = document.createElement("img");
		this.image.id = "icebox_image";
		this.image.style.display = "none";
		this.iceBoxDiv.appendChild( this.image);
		
		// add an empty frame that we will dynamically add content to later if it is needed
		this.frame = document.createElement("iframe");
		this.frame.id = "icebox_frame";
		this.frame.style.display = "none";
		this.iceBoxDiv.appendChild( this.frame );
		
		// and now we will add a loading indicator
		this.busyImage = document.createElement( "img" );
		this.busyImage.id = "icebox_loading";
		this.busyImage.src = loadingImage;
		this.busyImage.style.display = "none";
		this.busyImage.style.zIndex = 9999;
		document.body.appendChild( this.busyImage );
		
		// now we need to give the browser a bit of a wake up call to make sure that 
		// it updates the DOM tree properly ( Safari 2 requires this special attention )
		this.overlay.innerHTML += " ";
		
		// next we need to check for any browsers that support position:fixed
		// basically we are checking for versions of IE older than 6.0 SP2
		// if it is found that the browser doesn't support fixed positioning
		// then we need to calculate the iceBox's position differently
		browser = navigator.appName;
		b_version = navigator.appVersion;
		version = parseFloat(b_version);
		if( browser == "Microsoft Internet Explorer" && version < 7 ) 
			{
			this.oldBrowser = true;
			this.overlay.style.position = "absolute";
			}
		else 
			{
			this.iceBoxDiv.style.position = "fixed";
			}
			
		// store the defaultWidth and defaultHeight as properties of this object
		this.defaultHeight = defaultHeight;
		this.defaultWidth = defaultWidth;
		}
		
	// *************************************************
	// this function looks for links that have a class of 'icebox' and assigns
	// the required event handlers to them
	this.assignHandlers = function ()
		{
		// get all the anchors from the document
		links = document.getElementsByTagName( "area" );
		
		// now loop through them and find any that have a class that contains the
		// word 'icebox', when one is found then we attach the event handler to it
		for ( x = 0; x < links.length; x++)
			{
			anchorClass = links[x].getAttribute("class");
			if( anchorClass == null ) 
				{
				anchorClass = links[x].className;
				}
			if( anchorClass.indexOf("icebox2") != -1) links[x].onclick = this.showIceBox;
			} 
			
		// now we need to register the center() method to several events
		// so that the iceBox will always automatically re-size with the
		// window that contains it. If jQuery is available then we will
		// us it's event registration models.
		if( typeof(jQuery) == "function" )
			{
			jQuery( window ).scroll( this.center );
			jQuery( window ).resize( this.center );
			}
		// if the jQuery object is not available then we need to fall back on traditional
		// event registration techniques
		else
			{
			// Here we will attach the event handlers to the onscroll and onresize events
			var oldOnScroll = window.onscroll;
			if( typeof( oldOnScroll ) == 'function' ) window.onscroll = function() 
				{ 
				oldOnScroll(); 
				this.center(true); 
				}
			else window.onscroll = this.center;
				
			var oldOnResize = window.onresize;
			if( typeof( oldOnResize ) == 'function' ) window.onresize = function() 
				{ 
				oldOnResize(); 
				this.center(); 
				}
			else window.onresize = this.center;
			}
		}
		
	// *************************************************
	// this function centers the iceBox div and re-sizes both the content image and the background overlay
	this.center = function ()
		{	
		// first we need to find out whether the window has been scrolled at all
		// in either the X or Y direction
		var xOffset = yOffset = 0;
		if (self.pageYOffset) 
			{
			// most browsers
			yOffset = self.pageYOffset;
			xOffset = self.pageXOffset;
			} 
		else if (document.documentElement && document.documentElement.scrollTop)
			{	 
			// Explorer 6 Strict
			yOffset = document.documentElement.scrollTop;
			xOffset = document.documentElement.scrollLeft;
			} 
		else if (document.body) 
			{
			// all other Explorers
			yOffset = document.body.scrollTop;
			xOffset = document.body.scrollLeft;	
			}
		
		/////////////////// DANGER CODE: This code does not work in the expected way and is therefore dangerous
		/////////////////// every effort must be made in order to understand / fix this code
		/////////////////// The 'correct' code that should go here causes IE6 to crash
		
		// now we need to find out what the rendered height and width of the entire page is
		var ScrollHeight, ScrollWidth;
		if (window.innerHeight && window.scrollMaxY) 
			{	
			ScrollHeight = window.innerWidth + window.scrollMaxX;
			ScrollWidth = window.innerHeight + window.scrollMaxY;
			} 
		else if (document.body.scrollHeight > document.body.offsetHeight)
			{ 
			// all but Explorer Mac
			ScrollHeight = document.body.scrollWidth;
			ScrollWidth = document.body.scrollHeight;
			} 
		else 
			{ 
			// Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
			ScrollHeight = document.body.offsetWidth;
			ScrollWidth = document.body.offsetHeight;
			}
			
		//////////////////// END DANGER CODE
	
		// now we need to get the dimensions of the browser viewport so that we can
		// center the iceBox within it
		var windowWidth = windowHeight = 0;
		if (self.innerHeight) 
			{	
			// all except Explorer
			windowWidth = (document.documentElement.clientWidth) ? document.documentElement.clientWidth : self.innerWidth; 
			windowHeight = self.innerHeight;
			} 
		else if (document.documentElement && document.documentElement.clientHeight) 
			{ 
			// Explorer 6 Strict Mode
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
			} 
		else if (document.body) 
			{ 
			// other Explorers
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
			}	
		
		// if the document width or height is less than the viewport width or height then we adjust accordingly
		pageHeight = (ScrollHeight < windowHeight) ? windowHeight : ScrollHeight;
		pageWidth = (ScrollWidth < windowWidth) ? windowWidth : ScrollWidth;
		
		if( thisObj.overlay )
			{
			thisObj.overlay.style.height = pageHeight + "px";
			}
		
		// check to see if the user supplied a default width and height
		if( thisObj.defaultHeight && thisObj.defaultWidth )
			{
			maxwidth = thisObj.defaultWidth;
			maxheight = thisObj.defaultHeight;
			}
		else
			{
			// set the popup maximum width & height according to how big the window is
			maxwidth = windowWidth - 100;
			maxheight = windowHeight - 100;
			}
	
		// now resize and center the popup to match the size of the browser window
		// check to see if the iceBox contains an image
		if( thisObj.showImage )
			{
			// first resize the image to fit within the browser viewport
			thisObj.resizeImage( thisObj.image, maxwidth, maxheight );
			
			// now resize the popup to fit around the image
			thisObj.iceBoxDiv.style.width = (thisObj.image.width + 32 ) + "px";
			thisObj.iceBoxDiv.style.height = ( thisObj.image.height + 32 ) + "px";
			
			// now update the object properties so that it knows how big the icebox is
			thisObj.width = (thisObj.image.width + 32 );
			thisObj.height = (thisObj.image.height + 32 );
			}
		// else if the iceBox contains a frame then resize the frame to the maximum permissable size
		else
			{
			thisObj.frame.width = maxwidth;
			thisObj.frame.height = maxheight;
			thisObj.iceBoxDiv.style.width = ( maxwidth + 32 ) + "px";
			thisObj.iceBoxDiv.style.height = ( maxheight + 32 ) + "px";
			
			// now update the object properties so that it knows how big the icebox is
			thisObj.width = (maxwidth + 32 );
			thisObj.height = (maxheight + 32 );
			}
		
		// now calculate where the iceBox needs to be positioned in order to be centered
		var left = (( windowWidth / 2) - ( thisObj.width / 2) + xOffset);
		if ( !this.oldBrowser ) var top = ((windowHeight / 2) - ( thisObj.height / 2));
		else var top = ((windowHeight / 2) - ( thisObj.height / 2) + yOffset );
		

		// now assign the iceBox the calculated position. if the position is negative
		// ( off the screen ) then simply position the iceBox at 0px instead
		thisObj.iceBoxDiv.style.top = ( top < 0 ) ? "0px": top + "px";
		thisObj.iceBoxDiv.style.left = ( left < 0 ) ? "0px" : left + "px";	
		}
		
	// *************************************************
	// this function displays the iceBox container and the background overlay
	// it is also responsible for actually loading the content based on the element that 
	// called the function ( it is normally assigned as an event handler )
	this.showIceBox = function ( src)
		{
		// here we need to track down the object that was clicked on to launch this event
		if( (!src) || (typeof src == 'object') )
			{
			// setup a null variable for the target element
			var targ;
			
			// if the event object was not supplied ( courtesy of explorer )
			// then we need to retrieve it from the window.event object
			if (!src) var src = window.event;
			
			// if we have been provided with the event target as the W3C says whe should
			// be then we assign it to our blank targ variable
			if (src.target) targ = src.target;
			
			// if we are having to work with IE then we retrieve the target element from
			// the window.event object
			else if (src.srcElement) targ = src.srcElement;
			
			// defeat Safari bug that give us a text node instead an element
			if (targ.nodeType == 3) targ = targ.parentNode;
			
			// check to see if we are recieving the event from a child element of
			// the icebox link. If we are then we need to change our target so that 
			// it points at the parent link element
			if( targ.parentNode.tagName == "A" && targ.parentNode.className.indexOf( "icebox2") != -1)
				{
				targ = targ.parentNode;	
				}
			
			// now try to grab the link's src element the proper W3C way
			src = targ.src;
			
			// if that doesn't work then we fal back on an older method
			if( !src ) src = targ.getAttribute("href");
			
			// if we still don't have a src attribute to play with then we exit the method
			if( !src ) return;
			}
			
		// now we need to find out whether the link points to an image that we can load
		// dynamically by itself or to an HTML page that we need to create a frame for
		var extension = src.substring( src.length -3 );
		extension = extension.toLowerCase();
		
		// if the link points to an image then we need to dynamically load that image
		if( extension == "jpg" || extension == "gif" || extension == "png" || extension == "peg" )
			{
			// display the loading animation so that the user realized something is happening
			thisObj.loading();
			
			// change the source of the icebox_image to the target of the 
			// link that initiated this event
			thisObj.image.src = src;
			
			// make sure the icebox_frame is hidden
			thisObj.frame.style.display = "none";
			
			// show the icebox_image
			thisObj.image.style.display = "block";
			
			// set the object's showImage property
			thisObj.showImage = true;
			
			// add an event to the image so that it automatically hides the loading
			// graphic when it finishes loading
			thisObj.image.onload = function ()
				{
				thisObj.notLoading();
				
				// check to see if jQuery is available, if it is then we will use it's
				// animation functions to show the iceBox
				if( typeof( jQuery ) == "function" && !thisObj.oldBrwoser )
					{
					thisObj.overlay.style.display = "block";
					jQuery("#icebox2").fadeIn("normal");
					}
				// if the jQuery object is not available ther we will show the icebox simply
				// by manipulating it's CSS properties
				else
					{
					thisObj.overlay.style.display = "block";
					thisObj.iceBoxDiv.style.display = "block";
					}
				thisObj.center();
				}
			}
			
		// else if the link points to a HTML page then we need to create a frame and then
		// direct the frame  to load the target document
		else
			{
			// direct the frame to load the document pointed to by the link that
			// activated this event
			thisObj.frame.src = src;
			
			// make sure the icebox_image is hidden
			thisObj.image.style.display = "none";
			
			// show the icebox_frame
			thisObj.frame.style.display = "block";
			
			// set the object's showImage property
			thisObj.showImage = false;
			
			// check to see if jQuery is available, if it is then we will use it's
			// animation functions to show the iceBox
			if( typeof( jQuery ) == "function" && !thisObj.oldBrwoser )
				{
				thisObj.overlay.style.display = "block";
				jQuery("#icebox2").fadeIn("normal");
				}
			// if the jQuery object is not available ther we will show the icebox simply
			// by manipulating it's CSS properties
			else
				{
				thisObj.iceBoxDiv.style.display = "block";
				thisObj.overlay.style.display = "block";
				}
			}
			
		// call the center() method of this object so that the overlay will be resized
		thisObj.center();
		
		// return false so that the default action of the browser will be overridden
		// if we don't do this then the browser will follow the link the user just clicked on
		return false;	
		}
		
	// *************************************************
	// this function simply hides the iceBox container and the background overlay
	this.hideIceBox = function ()
		{			
		// first we check to see if the jQuery object is available
		// if it is then we will use it's animation functions to hide the iceBox
		if( typeof(jQuery) == "function" && !thisObj.oldBrwoser )
			{
			jQuery("#icebox2").fadeOut("fast", function () 
				{ 
				thisObj.overlay.style.display = "none"; 
				
				// make sure both of the individual content containers are hidden for IE
				thisObj.image.style.display = "none";
				thisObj.frame.style.display = "none";
				thisObj.image.src = false;
				thisObj.frame.src = false;
				})	
			thisObj.notLoading();
			}
		// if jQuery is not available then we simply set the CSS styles of the overlay
		// and the container to display:hidden;
		else
			{
			thisObj.iceBoxDiv.style.display = "none";
			thisObj.overlay.style.display = "none";
			thisObj.notLoading();
			
			// make sure both of the individual content containers are hidden for IE
			thisObj.image.style.display = "none";
			thisObj.frame.style.display = "none";
			thisObj.image.src = false;
			thisObj.frame.src = false;
			}	
			
		
		
		// now call the center() method of this object to make sure the overlay
		// show up the right size next time iceBox is used
		thisObj.center();
		}
		
	// *************************************************
	// this function shows a loading animation so that the user knows that the script is 
	// actually doing something and has not stalled
	this.loading = function ()
		{
		thisObj.busyImage.style.display = "block";
		}
		
	// *************************************************
	// this function hides the loading animation
	this.notLoading = function ()
		{
		thisObj.busyImage.style.display = "none";
		}
		
	// *************************************************
	// this function resizes any images passed to it to the maximum sizes provided.
	// it is designed to ensure that the images aspect ratio does not change or become distorted
	this.resizeImage = function ( image, maxwidth, maxheight )
		{
		// if the image identifier supplied is a string instead of an object 
		// then we assume that the string is the image's ID and we fetch the object accordingly
		if( typeof( image ) == "string" )
			{
			image = document.getElementById( image );	
			}
		// now we need to reset the image to it's original size prior to re-sizing it within the constraints provided
		if( image.src )
			{
			var tempImage = document.createElement("img");	
			tempImage.src = image.src;
			width = tempImage.width;
			height = tempImage.height;
			}
		else
			{
			width = image.width;
			height = image.height;
			}
		// check to see if the height of the image is larger than the maximum allowable height
		// if so then proportionally scale the image to fit within the maximum height
		if( height > maxheight && maxheight > 0)
			{
			scale = height / maxheight;
			height = height / scale;
			width = width / scale;
			}
		// check to see if the width of the image is larger than the maximum allowable width
		// if so then proportionally scale the image to fit within the maximum width
		if ( width > maxwidth && maxwidth > 0 )
			{
			scale = width / maxwidth;
			width = width / scale;
			height = height / scale;
			}
		// now that the appropriate width & height have been calculated we need to apply them to the image
		image.height = height ;
		image.style.height = height + "px";
		image.width = width ;
		image.style.width = width + "px";
		}
	
	// assign a static instance of the THIS keyword for later use in creating closures
	var thisObj = this;
	
	// initialize the object
	this.init();
	
	// assign the proper event handlers to any links that have a class of "icebox"
	this.assignHandlers();	
	
	// setup all the default sizes and center the overlay and container
	this.center();
	}
	

// *************************************************
// this function creates a new iceBox object and passes it the parameters
// it requires to function as we'd like it to...
function initIceBox ()
	{
	newIceBox = new iceBox2 ( "http://waldendesign.com/images/closebutton.png", "http://waldendesign.com/images/loading.gif", 440, 610);	
	}

// *************************************************
// here we need to setup the page so that it initializes the iceBox object
// once the DOM has loaded ( if jQuery is available ) or once the page has loaded

// if the jQuery object is available then we will use it's event registration method
if( typeof(jQuery) == "function" )
	{
	jQuery( document ).ready( initIceBox );
	}
// if jQuery is not available then we will us the standard method of assigning 
// on onload event to the window
else
	{
	// check to see whether another script has already assigned an event
	// to winodw.onload
	if( window.onload )
		{
		// if there is already an event registered to window.onload then we need
		// to store a copy of it and call it after we launch our own init function
		var oldOnLoad = window.onload;
		window.onload = function ()
			{
			initIceBox();
			oldOnLoad();
			}
		}
	// if there are no events already registered then we simply register
	// our init function and relax!
	else
		{
		window.onload = initIceBox;	
		}
	}
	
	
// CHANGELOG:
// Changes before the 7th August 2007 were not noted and are therefore undocumented... oops

// 7th August 2007:
// Converted all indenting to tabs instead of spaces & added basic commenting
// Stopped the page from returning to the top when a popup is created
// fixed bug where uppercase image file extensions would stop the image from being displayed correctly

// 8th August 2007:
// Fixed issue in safari 2 where page heights etc were not being detected properly
// Added loading indicated

// 2nd November 2007:
// The script now detects the jQuery object and if it is found then 
// it uses the jQuery animations to fade elements in and out.
// All event handlers now support at least one other event having been 
// attached to an object before hand. The old handler is saved and fired after the new one
// All the variable names are now camelCase as opposed to underscored_names

// 25th February 2008:
// Updated script so that the popup is automatically resized ( including 
// the image it conatins ) to fit within the browser window

// 21 May 2008:
// Started initial work on porting old code to new object-based script

// 22 May 2008:
// completed porting old code. working through bugs to get complete working version

// 23 MAY 2008:
// fixed issue in IE where iframe didn't hide properly after being shown
// fixed bug where image links displayed the image you clicked instead of the link

// 10 JUNE 2008:
// Fixed Critical Bug that only affected IE6. Icebox caused browser and sometimes OS to crash
