Show:

File: ia\ui\CalloutBox.js

/** 
 * Creates a callout box.
 *
 * @author J Clare
 * @class ia.CalloutBox
 * @constructor
 * @param {String} id The element id.
 * @param {String} notchPosition "top-bottom" or "left-right" or "none".
 */
ia.CalloutBox = function(id, notchPosition)
{	
	this.id = id;
	this.notchPosition = notchPosition || "left-right";
	this.container = $j('<div id="'+id+'" class="callout"></div>');

	this._px = 0; 
	this._py = 0;
	this._isVisible = false;
	this._popup = false;

	this._notchBorder =  $j('<div class="callout-notch"></div>');
	this._notchBorder.addClass("callout-notch-"+this.notchPosition)
	this.container.append(this._notchBorder);
	
	this._notchFill =  $j('<div class="callout-notch"></div>');
	this._notchFill.addClass("callout-notch-"+this.notchPosition);
	this.container.append(this._notchFill);
	
	if (this.notchPosition === "none") 
	{
		this._notchBorder.css({display:"none"});
		this._notchFill.css({display:"none"});
	}

	// Btns.
	var btns = $j("<div>").addClass('ia-panel-btns').attr('id', id +"-btns");	
	this.container.append(btns);

	if (!ia.IS_TOUCH_DEVICE)
	{
		var overBtns = false;
		this.container.mouseenter(function(e) 
		{
			if (!overBtns)
			{
				btns.stop();
				btns.css({visibility: "visible"}).animate({opacity: 0.4});
			}
		});
		this.container.mouseleave(function(e) 
		{
			btns.stop();
			btns.animate({opacity: 0}, function() 
			{
				btns.css({visibility: "hidden"});
			});
		});
		btns.mouseenter(function(e) 
		{
			overBtns = true;
			btns.animate({opacity: 1.0});
		});
		btns.mouseleave(function(e) 
		{
			overBtns = false;
			btns.stop();
			btns.animate({opacity: 0.4});
		});
	}
	else 
	{
		var btnsTimeout;
		this.container.bind("touchstart", function(e) 
		{
			btns.stop();
			btns.css({visibility: "visible"}).animate({opacity: 1.0});
			
			clearTimeout(btnsTimeout);
			btnsTimeout = setTimeout(function()
			{
				clearTimeout(btnsTimeout);
				btns.stop();
				btns.animate({opacity: 0}, function() 
				{
					btns.css({visibility: "hidden"});
				});
			}, 5000);
		});
	}

	// Close button.	
	var me = this;			
	var closeBtn = $j("<div>").addClass('ia-panel-btn ia-panel-close-btn').attr('id', id +"-close");
	closeBtn.bind(ia.CLICK_TYPE, function(e) 
	{
		me.hide();
	});
	btns.append(closeBtn);
	
	var resizeTimeout;
	this.container.resize(function(e)
	{
		clearTimeout(resizeTimeout);
		resizeTimeout = setTimeout(function()
		{
			clearTimeout(resizeTimeout);
			if (me._isVisible) {me.position();}
		}, 300);
	});
};
	
/** 
 * The id.
 * 
 * @property id
 * @type String
 */
ia.CalloutBox.prototype.id;

/**
 * The container that holds the object.
 * 
 * @property container
 * @type {JQUERY Element}
 */
ia.CalloutBox.prototype.container;
	
/**
 * "top-bottom" or "left-right".
 * 
 * @property notchPosition
 * @type String
 * @default "left-right"
 */
ia.CalloutBox.prototype.notchPosition;

/** 
 * Positions the callout.
 * 
 * @method position
 * @param {Number} x The x position.
 * @param {Number} y The y position.
 */
ia.CalloutBox.prototype.position = function(x, y)
{
	if (this.container.parent() !== undefined)
	{
		// Position relative to parent container.
		if (x) 
		{
			x = x - this.container.parent().offset().left;
			this._px = x;
		}
		if (y) 
		{
			y = y - this.container.parent().offset().top;
			this._py = y;
		}

		
		// Clear styles.
		this._notchBorder.removeClass("callout-notch-left callout-notch-right callout-notch-border-left callout-notch-border-right");
		this._notchFill.removeClass("callout-notch-left callout-notch-right");
		this._notchBorder.css({left:"",right:"",top:"",bottom:""});
		this._notchFill.css({left:"",right:"",top:"",bottom:""});

		var cx = x || this._px;
		var cy = y || this._py;

		var parentWidth = this.container.parent().width();
		var parentHeight = this.container.parent().height();
		var calloutWidth = this.container.outerWidth();
		var calloutHeight = this.container.outerHeight();
		var xCentre = parentWidth / 2;
		var yCentre = parentHeight / 2;
	
		// Calculate notch offset.
		var notchSize = 10;
		var offset = 30;
		var xOffset, yOffset;
		if (this.notchPosition === "left-right")
		{
			xOffset = offset;
			yOffset = Math.min(offset, (calloutHeight/2));
			cy = cy - yOffset;
		}
		else
		{
			xOffset = Math.min(offset, (calloutWidth/2));
			yOffset = offset;
			cx = cx - xOffset;
		}
		
		// Position.
		if (this.notchPosition === "left-right")
		{
			if (cx < xCentre) // left
			{	
				if (this._notchBorder.hasClass("callout-notch-right"))
				{
					this._notchBorder.removeClass("callout-notch-right callout-notch-border-right");
					this._notchFill.removeClass("callout-notch-right");
				}
				cx = cx + xOffset;
				this._notchBorder.addClass("callout-notch-left callout-notch-border-left");
				this._notchFill.addClass("callout-notch-left");
				this._notchBorder.css({left: -notchSize-1 + "px"});
				this._notchFill.css({left: -notchSize + "px"});
			}
			else // right
			{
				if (this._notchBorder.hasClass("callout-notch-left"))
				{
					this._notchBorder.removeClass("callout-notch-left callout-notch-border-left");
					this._notchFill.removeClass("callout-notch-left");
				}
				cx = cx - calloutWidth - xOffset;
				this._notchBorder.addClass("callout-notch-right callout-notch-border-right");
				this._notchFill.addClass("callout-notch-right");
				this._notchBorder.css({right: -notchSize-1 + "px"});
				this._notchFill.css({right: -notchSize + "px"});
			}
		}
		else
		{
			if (cy < yCentre) // top
			{	
				if (this._notchBorder.hasClass("callout-notch-bottom"))
				{
					this._notchBorder.removeClass("callout-notch-bottom callout-notch-border-bottom");
					this._notchFill.removeClass("callout-notch-bottom");
				}
				cy = cy + yOffset;
				this._notchBorder.addClass("callout-notch-top callout-notch-border-top");
				this._notchFill.addClass("callout-notch-top");
				this._notchBorder.css({top: -notchSize-1 + "px"});
				this._notchFill.css({top: -notchSize + "px"});
			}
			else // bottom
			{
				if (this._notchBorder.hasClass("callout-notch-top"))
				{
					this._notchBorder.removeClass("callout-notch-top callout-notch-border-top");
					this._notchFill.removeClass("callout-notch-top");
				}
				cy = cy - calloutHeight - yOffset;
				this._notchBorder.addClass("callout-notch-bottom callout-notch-border-bottom");
				this._notchFill.addClass("callout-notch-bottom");
				this._notchBorder.css({bottom: -notchSize-1 + "px"});
				this._notchFill.css({bottom: -notchSize + "px"});
			}
		
		}
		
		// Reposition if near edge of window.
		var margin = 10;
			
		var xOffset = (cx + calloutWidth) - (parentWidth - margin);
		if (xOffset > 0) cx = cx - xOffset;
		if (cx < margin) cx = margin;

		var yOffset = (cy + calloutHeight) - (parentHeight - margin);
		if (yOffset > 0) cy = cy - yOffset;
		if (cy < margin) cy = margin;
		
		// Postion notch relative to box.
		var notchIndent;
		if (this.notchPosition === "left-right")
		{
			notchIndent = (this._py - cy) - (notchSize/2);
			this._notchBorder.css({top: notchIndent + "px"});
			this._notchFill.css({top: notchIndent + "px"});
		}
		else
		{
			notchIndent = (this._px - cx) - (notchSize/2);
			this._notchBorder.css({left: notchIndent + "px"});
			this._notchFill.css({left: notchIndent + "px"});
		}
				
		this.container.css({left: cx + "px",top: cy + "px"});
	}
};

/** 
 * Sets or gets if its a popup - closes on a click outside the callout.
 * 
 * @method popup
 * @param {Boolean} isPopup true/false.
 */
ia.CalloutBox.prototype.popup = function(isPopup)
{
	if (isPopup === true)
	{
		this._popup = true;

		var me = this;
		$j("body").bind(ia.CLICK_TYPE, function(e) 
		{
			me.hide();
		});
		this.container.bind(ia.CLICK_TYPE, function(e) 
		{
			e.stopPropagation();
		});
	}
	else if (isPopup === false)
	{
		this._popup = false;
	}
	else return this._popup
};

/** 
 * Appends an element.
 * 
 * @method append
 * @param {JQUERY Element} obj The jquery object.
 */
ia.CalloutBox.prototype.append = function(obj)
{
	this.container.append(obj);
};

/**
 * Toggles the visibility of the callout.
 *
 * @method toggle
 * @param {Boolean} visible true/false.
 */
ia.CalloutBox.prototype.toggle = function(visible)
{
	if (this._isVisible) this.hide();
	else this.show();
};

/**
 * Hide the callout.
 *
 * @method hide
 */
ia.CalloutBox.prototype.hide = function()
{	
	this._isVisible = false;
	this.container.hide();
};

/**
 * Show the callout.
 *
 * @method show
 */
ia.CalloutBox.prototype.show = function()
{
	this._isVisible = true;
	this.container.fadeIn();
};