// SpryTabbedPanels.js - version 0.5 - Spry Pre-Release 1.6

//

// 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.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);

 

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

            else e.returnValue = false;

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

            else e.cancelBubble = true;

 

            return false;

};

 

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

{

            this.addClassName(tab, this.tabHoverClass);

            return false;

};

 

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

{

            this.removeClassName(tab, this.tabHoverClass);

            return false;

};

 

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

{

            this.hasFocus = true;

            this.addClassName(tab, this.tabFocusedClass);

            return false;

};

 

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

{

            this.hasFocus = false;

            this.removeClassName(tab, this.tabFocusedClass);

            return false;

};

 

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.preventDefault) e.preventDefault();

            else e.returnValue = false;

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

            else e.cancelBubble = true;

 

            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);

};
