﻿
(function($) 
{

 /**
  * elementPopper is a jquery plugin that will popup an element next to another element that is in mouseover
	* @constructor
	* @returns a jQuery object
	*/
	$.fn.elementPopper = function(options) 
	{ 
		// extend our default options with those passed in
		var opts = $.extend({}, $.fn.elementPopper.defaults, options);
		
		// iterate over selector and assign events
		return this.each(
			function() 
			{
				$this = $(this);
				
				var targetObject = {};
				var popupObject = {};
				
				if (opts.removeFromDOM)
				{
					$('#' + $(this).attr('rel')).appendTo($(document.body));
				}

				$this.mouseover(function(e)
					{
						if (popupObject.jQueryElement == null)
						{
							ensureElements($('#' + $(this).attr('rel')), $(e.target));
						}
					
						popupObject.jQueryElement = $('#' + $(this).attr('rel'));
						popupObject.jQueryElement.css({position:'absolute'});
						popupObject.jQueryElement.show();
						popupObject.elementDimensions = getElementDimensions(popupObject.jQueryElement);
						
						targetObject.jQueryElement = $(e.target);
						targetObject.elementDimensions = getElementDimensions(targetObject.jQueryElement);
						
					} // end mouseover()
				).mouseout(function(e)
					{
						if (popupObject.jQueryElement == null)
						{
							ensureElements($('#' + $(this).attr('rel')), $(e.target));
						}
						
						popupObject.jQueryElement.hide();
						popupObject.jQueryElement = null;
						targetObject = {};
						
					} // end mouseout()
				).mousemove(function(e)
					{
						if (popupObject.jQueryElement == null)
						{
							ensureElements($('#' + $(this).attr('rel')), $(e.target));
						}
						
						var mouseCoords = getMouseCoords(e);
						var popupCoords = getPopupDestinationCoords(mouseCoords, targetObject, popupObject.jQueryElement, opts);
						popupObject.jQueryElement.css({left:popupCoords.x + 'px', top:popupCoords.y + 'px'});
						
					} // end mousemove()
				); 

			 /**
			  * function to make sure our elements are created... this is needed because IE fires mousemove first, then mouseover.
			  * @param {jQuery object} popupElement 
			  * @param {jQuery object} targetElement
			  */ 
				function ensureElements(popupElement, targetElement)
				{
					popupObject.jQueryElement = popupElement;
					targetObject.jQueryElement = targetElement;
					popupObject.elementDimensions = getElementDimensions(popupObject.jQueryElement);
					targetObject.elementDimensions = getElementDimensions(targetObject.jQueryElement);
				} // ensureElements

			} 
		); // end return this.each()
	}; // end $.fn.elementPopper
	
	

	
 /**
  * Gets an extended list of dimensions for any element
  *
  * @param {jQuery object of a DOM element} element This is a jQuery object containing the DOM element to get dimensions for 
  * @returns JavaScript object with the following properties: 
  *		top - top css property relative to viewport
  *		left - left css property relative to viewport
  *   width - width
  *   height - height
  *   halfHeight - half of the height
  *   halfWidth  - half of the width
  *   middleY - Y coord representing the halfHeight
  *   middleX - X coord representing the halfWidth
  *   bottom - Y coord representing the bottom
  *   right - X coord representign the right
  */	
	function getElementDimensions(element)
	{
		var dims = element.offset(); // this gets x,y
		
		dims.width = element.width();
		dims.height = element.height();

		dims.halfHeight = Math.floor(dims.height / 2);
		dims.middleWidth = Math.floor(dims.width / 2);

		dims.middleY = dims.top + dims.halfHeight;
		dims.middleX = dims.left + dims.middleWidth;
		
		dims.bottom = dims.top + dims.height;
		dims.right = dims.left + dims.width;
	
		return dims;
	}	// getElementDimensions
	
 /**
  * calculates the position to place an element relative to the target being moused over
  * @param {object} mouseCoords - an object representing the point location of the mouse
  * @param {object} targetObject - custom object containing a jQuery reference to the target element, as well as the dimensions of the element
  * @param {jQuery object} popupElement - jQuery object containing the DOM element that will be positioned next to the targetElement
  * @param {object} elementPopperOptions - Options object of this jQuery plugin
  * @returns Object with a x,y coordinates for the destination of the popup
  */
	function getPopupDestinationCoords(mouseCoords, targetObject, popupElement, elementPopperOptions)
	{
		
		var targetDimensions = targetObject.elementDimensions;
		var popupDimensions  = getElementDimensions(popupElement);
		
		var XPosition = mouseCoords.x + elementPopperOptions.offsetX;
		var YPosition = targetDimensions.middleY - popupDimensions.halfHeight;
		
		var windowJQuery = $(window);
		
		var viewportLeft = windowJQuery.width() + windowJQuery.scrollLeft();
		var viewportTop  = windowJQuery.height() + windowJQuery.scrollTop()

		if ((XPosition + popupDimensions.width) > viewportLeft)
		{
			XPosition = mouseCoords.x - elementPopperOptions.offsetX - popupDimensions.width;
		}
	  
		if ((YPosition + popupDimensions.height) > viewportTop)
		{
			YPosition = viewportTop - popupDimensions.height - elementPopperOptions.offsetY;
		}
		else if (YPosition < windowJQuery.scrollTop()) 
		{
			YPosition = windowJQuery.scrollTop() + elementPopperOptions.offsetY;
		}
		
		var popupCoords =
		{ 
			x: XPosition, 
			y: YPosition
		};
	
		return popupCoords;
	}	// getPopupDestinationCoords
	
	
 /**
  * gets the position of the mouse
  * @param {event} e - the event that triggered this action to take place
  * @returns Object with the x,y coordinates of the mouse
  */
	function getMouseCoords(e)
	{
		var mousePosition = 
		{ 
			x: e.pageX, 
			y: e.pageY
		};
		
		return mousePosition;
	}	// end getMouseCoords()
	
	
	// plugin defaults - added as a property on our plugin function
	$.fn.elementPopper.defaults = 
	{
		offsetX: 10,
		offsetY: 10,
		removeFromDOM:false
	}; // $.fn.elementPopper.defaults

})(jQuery);


