/*! Sonar v2 */
/*
	An object for determining if an object is within a certain 
	distance from the edge above or below the screen, and attaching
	a function to execute once the object is in view.
	
	General Usage:
	
	*	Place the library anywhere in your JavaScript code before you 
		intend to call the function.
	
	* 	Modify sonar.d to set a new default distance for 
		the detection if desired.
	
	
	sonar.detect() Usage
	
	*	Use sonar.detect(object, distance) to check if the 
		object is within screen boundaries.
		
		@object - The object you want to detect visibility.
		@distance - The distance from the screen edge that should
		count in the check.

	*	Note: sonar.detect() adds a property to 
		ojbects called __top. Test to ensure there
		aren't any conflicts with your code. If there
		are, rename __top to something else in the code.

	*	sonar.detect() returns:
		true if the object is within the screen boundaries
		false if th object is out of the screen boundaries
	
	Example:
	
	Here's how to check if an advertisment is visible on a 
	page that has the id, "ad".
	
	if (sonar.detect(document.getElementById("ad")))
	{
		alert('The ad is visible on screen!');
	}
	else
	{
		alert ('The ad is not on screen!);
	}

	sonar.add() Usage
	
	*	This method stores objects that are then polled 
		on user scroll by the Sonar.detect() method.

	*	Polling initializes once the sonar.add() method is passed
		an object with the following properties:

		obj : A reference to the object to observe until it is within
		      the specified distance (px).

		call: 	The function to call when the object is within the 
		    	specified distance (px). The @object argument will 
				include the object that triggered the callback.
			   

		px : The specified distance to include as being visible on 
		     screen. This property is optional (default is 0).

	Example: 

	sonar.add(
	{	
		obj: document.getElementById("0026-get-out-the-way"), 
		call: function(object) // object will include the object that triggered the function.
		{ 
			swfobject.embedSWF("../player.swf", "0026-get-out-the-way", "640", "500", "9.0.0", 
			{}, {file: "0026-get-out-the-way.flv", fullscreen: true}, 
			{allowfullscreen: true, allowscriptaccess: "always"});
		},
		px: 400
	});

	Notes:

	* Setting the body or html of your page to 100% will cause sonar to have
	  an invalid height calculation in Firefox. It is recommended that you 
	  do not set this CSS property.
	  
	  Example:
	  
	  html, body {
		height:100%;  // Do not do this.
	  }
	
	* If you want to set the default distance to something other 
	  than 0, either update the property directly in the code or 
	  you can do this:

	  sonar.d = 100;  // Where 100 = 100 pixels above and below the screen edge.

	* Sleep well at night knowing Sonar automatically cleans up the 
	  event listeners on the scroll event once all calls have executed.
	  
	Code History:

	v2 :: 3/24/2009 - David Artz (david.artz@corp.aol.com)
	* Added support for IE 8.
	* Updated the way scroll top and screen height are detected, now 
	  works in IE/FF/Safari quirks mode.
	* Added null check for IE, it was polling for an object that had recently
	  been spliced out of the array. Nasty.
	* Modified for loop to use standard syntax. for (i in x) is known to be 
	  buggy with JS frameworks that override arrays.
	* Added sonar.b property to cache the body element (improving lookup time).
	
	v1 :: 11/18/2008 - David Artz (david.artz@corp.aol.com)
	* Officially released code for general use.

*/
sonar = 
{
	// Version number.
	v : 2,
	
	// Default above or below the screen to return true 
	// if object is visible on the screen.
	d : 0,
	
	ae : function (object, event, method)
	{
		if (object.addEventListener) object.addEventListener(event, method, false);
		else if (object.attachEvent) object.attachEvent('on' + event, method);
	},
	
	re : function (object, event, method)
	{
		if (object.removeEventListener) object.removeEventListener(event, method, false);
		else if (object.detachEvent) object.detachEvent('on' + event, method);
	},
	
	detect : function(object, distance)
	{
		if (!sonar.b)
		{
			sonar.b = document.getElementsByTagName('body')[0]; // Cache the body object.
		}
		
		var	d = document,
			w = window,
			instance = object, // Clone the object for use in our loop.
			object_top = 0, // The resets the calculated object top to 0.
			body_height = sonar.b.offsetHeight, // Used to recalculate object.__top if body height changes.
			screen_height = w.innerHeight || d.documentElement.clientHeight || d.body.clientHeight || 0, // Height of the screen.
			scroll_top = d.documentElement.scrollTop || w.pageYOffset || d.body.scrollTop || 0, // How far the user scrolled down.
			object_height = object.offsetHeight || 0; // Height of the object.

		distance = distance || sonar.d;

		// If our custom __top variable is undefined, or the document body
		// height has changed since the last time we ran sonar.detect()...
		//
		if (!object.__top || object.__bh != body_height)
		{
			// Loop through the offsetParents to calculate it.
			//
			if (instance.offsetParent)
			{
				do
				{
					object_top += instance.offsetTop;
				}
				while (instance = instance.offsetParent);
			}
			// Set the custom property (__top) to avoid future attempts to calculate
			// the distance on this object from the top of the page.
			//
			object.__top = object_top;
			
			// Along the same lines, store the body height when we calculated 
			// the object's top.
			//
			object.__bh = body_height;
		}

		// 	If object bottom is above the screen top and 
		//	the object top is below the screen bottom, it's false.
		//
		//	Note: Partially visible objects will be return true,
		//	which may be undesirable. Consider returning true only
		//	if the object is fully visible.
		//
		// log.write(object.id + ': object top ('+ object.__top + ') + object height (' + object_height + ') ['+(object.__top + object_height)+'] < ['+(scroll_top - distance)+'] scroll top (' + scroll_top + ') - distance (' + distance + ') OR ' +
		// 'object top ('+object.__top+') > ['+(scroll_top + screen_height + distance)+'] scroll top ('+scroll_top+') + screen height ('+screen_height+') + distance ('+distance+')<br />');
		
		// log.write('window.pageYOffset: ' + window.pageYOffset + ' documentElement.scrollTop: ' + d.documentElement.scrollTop + ' document.body.scrollTop: ' + document.body.scrollTop);
		if ((object.__top + object_height) < (scroll_top - distance) ||
			(object.__top) > (scroll_top + screen_height + distance))
		{
			return false;
		}
		
		// Any other scenario, return true.
		//
		// log.write('Sonar detect = true<br />');
		return true;
	},

	// Container for added objects.
	c : [],

	// Add function used to add objects with a callback
	// function to be polled on user scroll.
	add : function(config)
	{
		if (typeof config === "undefined")
		{
			return;
		}
		else
		{
			if (config.id)
			{
				config.obj = document.getElementById(config.id);
			}
			
			if (typeof config.obj == "object" && typeof config.call == "function")
			{
				if (sonar.detect(config.obj, (config.px || sonar.d)))
				{
				//	console.log(config.obj.id + ': Detected, executing callback.');
				// log.write('detected, executing callback');
					config.call(config.obj);
					return;
				}
				else
				{
					if (!window.__sonarBlip)
					{
						sonar.ae(window, "scroll", sonar._poll);
						window.__sonarBlip = 1;
					}
					// log.write('adding to poll<br />');
				//	console.log(config.obj.id + ': Not detected, adding to poll.');
					sonar.c.push(config);
				}
			}
		}
	},
	
	// Poll function, called as the user scrolls to run
	// through all objects added.
	_poll : function()
	{
		var blip, blips = sonar.c, i, l = blips.length, distance;
		
		// Loop through all the added blip objects...
		for (i=0; i<l; i++)
		{
			blip = blips[i]; 
			
			// This ensures that if we happen to be polling, and 
			// the object was recently spliced, we don't call it.
			if (!blip) continue;

			// If there are pixels specified, use that as our distance,
			// otherwise use the default setting.
			distance = blip.px || sonar.d;

			// If there is a valid object, and it is detected...
			if (sonar.detect(blip.obj, distance))
			{
			//	console.log(blip.obj.id + ': Detected! Executing callback.');
				// Call the callback function.
				blip.call(blip.obj);

				// Remove this object from the blip poll container.
				sonar.c.splice(i, 1);

				// If the blip array is empty, let's clean up our
				// event listener so it no longer loops.
				if (sonar.c.length == 0)
				{
				//	console.log('That\'s it! Removing Sonar Poll.');
					sonar.re(window, "scroll", sonar._poll);
					window.__sonarBlip = 0;
				}
			}	
		}
	}
};

/*! Sonar Ion v2 */
/*
 	Ion (Images on Need) is a JavaScript function that  loops
	through images on a page and stops their download if they are
	not visible on screen using the sonar library. The images 
	are added to the Sonar object, which handles all the polling
	and fires the callback function to update the image src.
	
	Usage:
	
	* 	Place sonar.ion() in an inline script block at the very 
		bottom of the document before the body close </body>.
		You may also initialize it on DOMReady if you swing
		that way.

	*	You can update the default distance for the screen
		check by sending it on initialization.
		
		Example: sonar.ion(1440); // Initializes Ion and sets the distance to 1440 pixels
		
	Notes:
	
	*	Ion is tested to work as designed in IE6+, and FF2+

	*	Ion does not work in Safari or Opera, though we tried 
		and we tried. Even ripping the image elements out of the 
		DOM does not stop Safari from downloading the images.

	Code History:

	v2 :: 3/24/2009 - David Artz (david.artz@corp.aol.com)
	* Moved to standard for loop, more compatible with JS 
	  frameworks that extend the Array object (cough, Moo Tools).
	* Removed check to see if image was already on screen, 
	  now exists in main sonar function.

	v1 :: 11/18/2008 - David Artz (david.artz@corp.aol.com)
	* Officially released code for general use.

*/

sonar.ion = function(distance)
{
	// Grab all the images on the page.
	var	default_distance = 0, // Default distance.
		images = document.getElementsByTagName('img'), 
		transparent_pixel = "http://o.aolcdn.com/js/x.gif", // Needed for Firefox. 
		i, l = images.length;

	distance = distance || default_distance;

	// Loop through all the images.
	//
	for (i=0; i<l; i++)
	{	
		// This check will ensure that only images with class name 
		// of "ion" will be rigged with ondemand loading.
		//
		// if (!/ion/.test(images[i].className)) continue;

		// If this image is already on the screen, proceed to the next image.
		if (sonar.detect(images[i], distance)) continue;

		// Temporarily store the true source as a temporary
		// property (__src) of this object. 
		images[i].__src = images[i].src;

		// Replace the source with a blank image.
		images[i].src = transparent_pixel;

		// Add the image to the sonar object, where it will then 
		// be polled as the user scrolls and execute the callback
		// function once it is within range.
		sonar.add({
			obj : images[i], 
			px : distance, 
			call : function(object)
			{
				// Set the blank image source to the true value.
				object.src = object.__src;

				// Set the temporary property to undefined so
				// the sonar.detect() function is no longer run on it.
				object.__src = undefined;
			}
			});
	}
};
/*
var log = {
	write : function(string)
	{
		var str = document.getElementById('log');
		if (!str)
		{
			var log_div = document.createElement('div');
			log_div.id = 'log';
			log_div.style.position = 'absolute';
			log_div.style.top = 0;
			log_div.style.left = 0;
			log_div.style.backgroundColor = '#000';
			log_div.style.color = '#fff';
			document.body.appendChild(log_div);
		}	
		else
		{
			str.innerHTML = str.innerHTML + string;	
		}
	}
}
*/