﻿/**
* hoverIntent is currently available for use in all personal or commercial 
* projects under both MIT and GPL licenses. This means that you can choose 
* the license that best suits your project, and use it accordingly.
* 
* hoverIntent r2 (bug fixes, ability to override default options, mouseout timer)
* <http://cherne.net/brian/resources/jquery.hoverIntent.html>
* 
* // basic usage (just like .hover) receives onMouseOver and onMouseOut functions
* $("ul li").hoverIntent( showNav , hideNav );
* 
* // advanced usage receives configuration object only
* $("ul li").hoverIntent({
*	sensitivity: 1, // number = sensitivity threshold (must be 1 or higher)
*	interval: 133,  // number = milliseconds of polling interval
*	over: showNav,  // function = onMouseOver callback (required)
*	timeout: 0,     // number = milliseconds delay before onMouseOut function call
*	out: hideNav    // function = onMouseOut callback (required)
* });
* 
* @param  f  onMouseOver function || An object with configuration options
* @param  g  onMouseOut function  || Nothing (use configuration options object)
* @return    The object (this) that called hoverIntent, and the event object
* @author    Brian Cherne <brian@cherne.net>
*/
(function($) {
	$.fn.hoverIntent = function(f,g) {
		var cfg = {
			sensitivity: 1,
			interval: 133,
			timeout: 0
		};
		cfg = $.extend(cfg, g ? { over: f, out: g } : f );
	
		var cX = null;   // currentX
		var cY = null;   // currentY
		var pX = null;   // previousX
		var pY = null;   // previousY
	
		// A private function for getting mouse position
		function getMousePosition(ev) {
			cX = ev.pageX;
			cY = ev.pageY;
		}
	
		// A private function for comparing current and previous mouse position
		function compareMouseCoordinates( ev, ob ) {
			// compare x and y positions to see if they've both crossed the threshold
			if ( ( Math.abs(pX-cX) + Math.abs(pY-cY) ) < cfg.sensitivity ) {
				$(ob).unbind("mousemove",getMousePosition);
				if (ob.hoverIntentInterval) { clearInterval(ob.hoverIntentInterval); ob.hoverIntentInterval = null; }
				return cfg.over.apply(ob, [ev]);
			}
			pX = cX;
			pY = cY;
		}
	
		// A private function for delaying the onMouseOut function
		function delayMouseOut( ev, ob ) {
			ob.hoverIntentTimeout = null;
			return cfg.out.apply(ob, [ev]);
		}
		
		// A private function for handling mouse 'hovering'
		function handleHover(e) {
			var p = (e.type == "mouseover" ? e.fromElement : e.toElement) || e.relatedTarget;
			while ( p && p != this ) { try { p = p.parentNode; } catch(e) { p = this; } }
			if ( p == this ) { return false; }
	
			// copy event object to another object to be passed into t (for IE)
			var ev = jQuery.extend({},e);
			var ob = this;
			if (ob.hoverIntentTimeout) { clearTimeout(ob.hoverIntentTimeout); ob.hoverIntentTimeout = null; }
	
			// else e.type == "onmouseover"
			if (e.type == "mouseover") {
				pX = e.pageX;
				pY = e.pageY;
				$(this).bind("mousemove",getMousePosition);
	
				// store this in variable to be passed into t
				ob.hoverIntentInterval = setInterval( function(){compareMouseCoordinates(ev, ob);} , cfg.interval );
	
			// else e.type == "onmouseout"
			} else {
				$(this).unbind("mousemove",getMousePosition);
				if (ob.hoverIntentInterval) { clearInterval(ob.hoverIntentInterval); ob.hoverIntentInterval = null; }
				ob.hoverIntentTimeout = setTimeout( function(){delayMouseOut(ev, ob);} , cfg.timeout );
			}
		}
	
		// Bind the function to the two event listeners
		return this.mouseover(handleHover).mouseout(handleHover);
	};
})(jQuery);