/* SpryTabbedPanels.js - Revision: Spry Preview Release 1.4 */

// Copyright (c) 2006. Adobe Systems Incorporated.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of Adobe Systems Incorporated nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

var Spry;
if (!Spry) Spry={};
if (!Spry.Widget) Spry.Widget={};

Spry.Widget.TabbedPanels=function(element, opts)
{
	this.element=this.getElement(element);
	this.defaultTab=0; // Show the first panel by default.
	this.bindings=[];
	this.tabSelectedClass="TabbedPanelsTabSelected";
	this.tabHoverClass="TabbedPanelsTabHover";
	this.tabFocusedClass="TabbedPanelsTabFocused";
	this.panelVisibleClass="TabbedPanelsContentVisible";
	this.focusElement=null;
	this.hasFocus=false;
	this.currentTabIndex=0;
	this.enableKeyboardNavigation=true;

	Spry.Widget.TabbedPanels.setOptions(this, opts);

	// If the defaultTab is expressed as a number/index, convert
	// it to an element.

	if (typeof (this.defaultTab)=="number")
	{
		if (this.defaultTab < 0)
			this.defaultTab=0;
		else
		{
			var count=this.getTabbedPanelCount();
			if (this.defaultTab >=count)
				this.defaultTab=(count > 1) ? (count - 1) : 0;
		}

		this.defaultTab=this.getTabs()[this.defaultTab];
	}

	// The defaultTab property is supposed to be the tab element for the tab content
	// to show by default. The caller is allowed to pass in the element itself or the
	// element's id, so we need to convert the current value to an element if necessary.

	if (this.defaultTab)
		this.defaultTab=this.getElement(this.defaultTab);

	this.attachBehaviors();
};

Spry.Widget.TabbedPanels.prototype.getElement=function(ele)
{
	if (ele && typeof ele=="string")
		return document.getElementById(ele);
	return ele;
}

Spry.Widget.TabbedPanels.prototype.getElementChildren=function(element)
{
	var children=[];
	var child=element.firstChild;
	while (child)
	{
		if (child.nodeType==1 /* Node.ELEMENT_NODE */)
			children.push(child);
		child=child.nextSibling;
	}
	return children;
};

Spry.Widget.TabbedPanels.prototype.addClassName=function(ele, className)
{
	if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) !=-1))
		return;
	ele.className +=(ele.className ? " " : "") + className;
};

Spry.Widget.TabbedPanels.prototype.removeClassName=function(ele, className)
{
	if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b"))==-1))
		return;
	ele.className=ele.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), "");
};

Spry.Widget.TabbedPanels.setOptions=function(obj, optionsObj, ignoreUndefinedProps)
{
	if (!optionsObj)
		return;
	for (var optionName in optionsObj)
	{
		if (ignoreUndefinedProps && optionsObj[optionName]==undefined)
			continue;
		obj[optionName]=optionsObj[optionName];
	}
};

Spry.Widget.TabbedPanels.prototype.getTabGroup=function()
{
	if (this.element)
	{
		var children=this.getElementChildren(this.element);
		if (children.length)
			return children[0];
	}
	return null;
};

Spry.Widget.TabbedPanels.prototype.getTabs=function()
{
	var tabs=[];
	var tg=this.getTabGroup();
	if (tg)
		tabs=this.getElementChildren(tg);
	return tabs;
};

Spry.Widget.TabbedPanels.prototype.getContentPanelGroup=function()
{
	if (this.element)
	{
		var children=this.getElementChildren(this.element);
		if (children.length > 1)
			return children[1];
	}
	return null;
};

Spry.Widget.TabbedPanels.prototype.getContentPanels=function()
{
	var panels=[];
	var pg=this.getContentPanelGroup();
	if (pg)
		panels=this.getElementChildren(pg);
	return panels;
};

Spry.Widget.TabbedPanels.prototype.getIndex=function(ele, arr)
{
	ele=this.getElement(ele);
	if (ele && arr && arr.length)
	{
		for (var i=0; i < arr.length; i++)
		{
			if (ele==arr[i])
				return i;
		}
	}
	return -1;
};

Spry.Widget.TabbedPanels.prototype.getTabIndex=function(ele)
{
	var i=this.getIndex(ele, this.getTabs());
	if (i < 0)
		i=this.getIndex(ele, this.getContentPanels());
	return i;
};

Spry.Widget.TabbedPanels.prototype.getCurrentTabIndex=function()
{
	return this.currentTabIndex;
};

Spry.Widget.TabbedPanels.prototype.getTabbedPanelCount=function(ele)
{
	return Math.min(this.getTabs().length, this.getContentPanels().length);
};

Spry.Widget.TabbedPanels.addEventListener=function(element, eventType, handler, capture)
{
	try
	{
		if (element.addEventListener)
			element.addEventListener(eventType, handler, capture);
		else if (element.attachEvent)
			element.attachEvent("on" + eventType, handler);
	}
	catch (e) {}
};

Spry.Widget.TabbedPanels.prototype.onTabClick=function(e, tab)
{
	this.showPanel(tab);
};

Spry.Widget.TabbedPanels.prototype.onTabMouseOver=function(e, tab)
{
	this.addClassName(tab, this.tabHoverClass);
};

Spry.Widget.TabbedPanels.prototype.onTabMouseOut=function(e, tab)
{
	this.removeClassName(tab, this.tabHoverClass);
};

Spry.Widget.TabbedPanels.prototype.onTabFocus=function(e, tab)
{
	this.hasFocus=true;
	this.addClassName(this.element, this.tabFocusedClass);
};

Spry.Widget.TabbedPanels.prototype.onTabBlur=function(e, tab)
{
	this.hasFocus=false;
	this.removeClassName(this.element, this.tabFocusedClass);
};

Spry.Widget.TabbedPanels.ENTER_KEY=13;
Spry.Widget.TabbedPanels.SPACE_KEY=32;

Spry.Widget.TabbedPanels.prototype.onTabKeyDown=function(e, tab)
{
	var key=e.keyCode;
	if (!this.hasFocus || (key !=Spry.Widget.TabbedPanels.ENTER_KEY && key !=Spry.Widget.TabbedPanels.SPACE_KEY))
		return true;

	this.showPanel(tab);

	if (e.stopPropagation)
		e.stopPropagation();
	if (e.preventDefault)
		e.preventDefault();

	return false;
};

Spry.Widget.TabbedPanels.prototype.preorderTraversal=function(root, func)
{
	var stopTraversal=false;
	if (root)
	{
		stopTraversal=func(root);
		if (root.hasChildNodes())
		{
			var child=root.firstChild;
			while (!stopTraversal && child)
			{
				stopTraversal=this.preorderTraversal(child, func);
				try { child=child.nextSibling; } catch (e) { child=null; }
			}
		}
	}
	return stopTraversal;
};

Spry.Widget.TabbedPanels.prototype.addPanelEventListeners=function(tab, panel)
{
	var self=this;
	Spry.Widget.TabbedPanels.addEventListener(tab, "click", function(e) { return self.onTabClick(e, tab); }, false);
	Spry.Widget.TabbedPanels.addEventListener(tab, "mouseover", function(e) { return self.onTabMouseOver(e, tab); }, false);
	Spry.Widget.TabbedPanels.addEventListener(tab, "mouseout", function(e) { return self.onTabMouseOut(e, tab); }, false);

	if (this.enableKeyboardNavigation)
	{
		// XXX: IE doesn't allow the setting of tabindex dynamically. This means we can't
		// rely on adding the tabindex attribute if it is missing to enable keyboard navigation
		// by default.

		// Find the first element within the tab container that has a tabindex or the first
		// anchor tag.
		
		var tabIndexEle=null;
		var tabAnchorEle=null;

		this.preorderTraversal(tab, function(node) {
			if (node.nodeType==1 /* NODE.ELEMENT_NODE */)
			{
				var tabIndexAttr=tab.attributes.getNamedItem("tabindex");
				if (tabIndexAttr)
				{
					tabIndexEle=node;
					return true;
				}
				if (!tabAnchorEle && node.nodeName.toLowerCase()=="a")
					tabAnchorEle=node;
			}
			return false;
		});

		if (tabIndexEle)
			this.focusElement=tabIndexEle;
		else if (tabAnchorEle)
			this.focusElement=tabAnchorEle;

		if (this.focusElement)
		{
			Spry.Widget.TabbedPanels.addEventListener(this.focusElement, "focus", function(e) { return self.onTabFocus(e, tab); }, false);
			Spry.Widget.TabbedPanels.addEventListener(this.focusElement, "blur", function(e) { return self.onTabBlur(e, tab); }, false);
			Spry.Widget.TabbedPanels.addEventListener(this.focusElement, "keydown", function(e) { return self.onTabKeyDown(e, tab); }, false);
		}
	}
};

Spry.Widget.TabbedPanels.prototype.showPanel=function(elementOrIndex)
{
	var tpIndex=-1;
	
	if (typeof elementOrIndex=="number")
		tpIndex=elementOrIndex;
	else // Must be the element for the tab or content panel.
		tpIndex=this.getTabIndex(elementOrIndex);
	
	if (!tpIndex < 0 || tpIndex >=this.getTabbedPanelCount())
		return;

	var tabs=this.getTabs();
	var panels=this.getContentPanels();

	var numTabbedPanels=Math.max(tabs.length, panels.length);

	for (var i=0; i < numTabbedPanels; i++)
	{
		if (i !=tpIndex)
		{
			if (tabs[i])
				this.removeClassName(tabs[i], this.tabSelectedClass);
			if (panels[i])
			{
				this.removeClassName(panels[i], this.panelVisibleClass);
				panels[i].style.display="none";
			}
		}
	}

	this.addClassName(tabs[tpIndex], this.tabSelectedClass);
	this.addClassName(panels[tpIndex], this.panelVisibleClass);
	panels[tpIndex].style.display="block";

	this.currentTabIndex=tpIndex;
};

Spry.Widget.TabbedPanels.prototype.attachBehaviors=function(element)
{
	var tabs=this.getTabs();
	var panels=this.getContentPanels();
	var panelCount=this.getTabbedPanelCount();

	for (var i=0; i < panelCount; i++)
		this.addPanelEventListeners(tabs[i], panels[i]);

	this.showPanel(this.defaultTab);
};
