// SpryTabbedPanels.js - version 0.6 - Spry Pre-Release 1.6.1

//

// 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.TabPanels = function(element, opts)

{

	this.element = this.getElement(element);

	this.defaultTab = 0; // Show the first panel by default.

	this.tabSelectedClass = "TabbedPanelsTabSelected1";

	this.tabHoverClass = "TabbedPanelsTabHover1";

	this.tabFocusedClass = "TabbedPanelsTabFocused1";

	this.panelVisibleClass = "TabbedPanelsContentVisible1";

	this.focusElement = null;

	this.hasFocus = false;

	this.currentTabIndex = 0;

	this.enableKeyboardNavigation = true;

	this.nextPanelKeyCode = Spry.Widget.TabPanels.KEY_RIGHT;

	this.previousPanelKeyCode = Spry.Widget.TabPanels.KEY_LEFT;



	Spry.Widget.TabPanels.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.TabPanels.prototype.getElement = function(ele)

{

	if (ele && typeof ele == "string")

		return document.getElementById(ele);

	return ele;

};



Spry.Widget.TabPanels.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.TabPanels.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.TabPanels.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.TabPanels.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.TabPanels.prototype.getTabGroup = function()

{

	if (this.element)

	{

		var children = this.getElementChildren(this.element);

		if (children.length)

			return children[0];

	}

	return null;

};



Spry.Widget.TabPanels.prototype.getTabs = function()

{

	var tabs = [];

	var tg = this.getTabGroup();

	if (tg)

		tabs = this.getElementChildren(tg);

	return tabs;

};



Spry.Widget.TabPanels.prototype.getContentPanelGroup = function()

{

	if (this.element)

	{

		var children = this.getElementChildren(this.element);

		if (children.length > 1)

			return children[1];

	}

	return null;

};



Spry.Widget.TabPanels.prototype.getContentPanels = function()

{

	var panels = [];

	var pg = this.getContentPanelGroup();

	if (pg)

		panels = this.getElementChildren(pg);

	return panels;

};



Spry.Widget.TabPanels.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.TabPanels.prototype.getTabIndex = function(ele)

{

	var i = this.getIndex(ele, this.getTabs());

	if (i < 0)

		i = this.getIndex(ele, this.getContentPanels());

	return i;

};



Spry.Widget.TabPanels.prototype.getCurrentTabIndex = function()

{

	return this.currentTabIndex;

};



Spry.Widget.TabPanels.prototype.getTabbedPanelCount = function(ele)

{

	return Math.min(this.getTabs().length, this.getContentPanels().length);

};



Spry.Widget.TabPanels.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.TabPanels.prototype.cancelEvent = function(e)

{

	if (e.preventDefault) e.preventDefault();

	else e.returnValue = false;

	if (e.stopPropagation) e.stopPropagation();

	else e.cancelBubble = true;



	return false;

};



Spry.Widget.TabPanels.prototype.onTabClick = function(e, tab)

{

	this.showPanel(tab);

	return this.cancelEvent(e);

};



Spry.Widget.TabPanels.prototype.onTabMouseOver = function(e, tab)

{

	this.addClassName(tab, this.tabHoverClass);

	return false;

};



Spry.Widget.TabPanels.prototype.onTabMouseOut = function(e, tab)

{

	this.removeClassName(tab, this.tabHoverClass);

	return false;

};



Spry.Widget.TabPanels.prototype.onTabFocus = function(e, tab)

{

	this.hasFocus = true;

	this.addClassName(tab, this.tabFocusedClass);

	return false;

};



Spry.Widget.TabPanels.prototype.onTabBlur = function(e, tab)

{

	this.hasFocus = false;

	this.removeClassName(tab, this.tabFocusedClass);

	return false;

};



Spry.Widget.TabPanels.KEY_UP = 38;

Spry.Widget.TabPanels.KEY_DOWN = 40;

Spry.Widget.TabPanels.KEY_LEFT = 37;

Spry.Widget.TabPanels.KEY_RIGHT = 39;







Spry.Widget.TabPanels.prototype.onTabKeyDown = function(e, tab)

{

	var key = e.keyCode;

	if (!this.hasFocus || (key != this.previousPanelKeyCode && key != this.nextPanelKeyCode))

		return true;



	var tabs = this.getTabs();

	for (var i =0; i < tabs.length; i++)

		if (tabs[i] == tab)

		{

			var el = false;

			if (key == this.previousPanelKeyCode && i > 0)

				el = tabs[i-1];

			else if (key == this.nextPanelKeyCode && i < tabs.length-1)

				el = tabs[i+1];



			if (el)

			{

				this.showPanel(el);

				el.focus();

				break;

			}

		}



	return this.cancelEvent(e);

};



Spry.Widget.TabPanels.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.TabPanels.prototype.addPanelEventListeners = function(tab, panel)

{

	var self = this;

	Spry.Widget.TabPanels.addEventListener(tab, "click", function(e) { return self.onTabClick(e, tab); }, false);

	Spry.Widget.TabPanels.addEventListener(tab, "mouseover", function(e) { return self.onTabMouseOver(e, tab); }, false);

	Spry.Widget.TabPanels.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.TabPanels.addEventListener(this.focusElement, "focus", function(e) { return self.onTabFocus(e, tab); }, false);

			Spry.Widget.TabPanels.addEventListener(this.focusElement, "blur", function(e) { return self.onTabBlur(e, tab); }, false);

			Spry.Widget.TabPanels.addEventListener(this.focusElement, "keydown", function(e) { return self.onTabKeyDown(e, tab); }, false);

		}

	}

};



Spry.Widget.TabPanels.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.TabPanels.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);

};

