// SpryCollapsiblePanel.js - version 0.7 - 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.CollapsiblePanel = function(element, opts){this.element = this.getElement(element);this.focusElement = null;this.hoverClass = "CollapsiblePanelTabHover";this.openClass = "CollapsiblePanelOpen";this.closedClass = "CollapsiblePanelClosed";this.focusedClass = "CollapsiblePanelFocused";this.enableAnimation = true;this.enableKeyboardNavigation = true;this.animator = null;this.hasFocus = false;this.contentIsOpen = true;this.openPanelKeyCode = Spry.Widget.CollapsiblePanel.KEY_DOWN;this.closePanelKeyCode = Spry.Widget.CollapsiblePanel.KEY_UP;Spry.Widget.CollapsiblePanel.setOptions(this, opts);this.attachBehaviors();};Spry.Widget.CollapsiblePanel.prototype.getElement = function(ele){if (ele && typeof ele == "string")return document.getElementById(ele);return ele;};Spry.Widget.CollapsiblePanel.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.CollapsiblePanel.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.CollapsiblePanel.prototype.hasClassName = function(ele, className){if (!ele || !className || !ele.className || ele.className.search(new RegExp("\\b" + className + "\\b")) == -1)return false;return true;};Spry.Widget.CollapsiblePanel.prototype.setDisplay = function(ele, display){if( ele )ele.style.display = display;};Spry.Widget.CollapsiblePanel.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.CollapsiblePanel.prototype.onTabMouseOver = function(e){this.addClassName(this.getTab(), this.hoverClass);return false;};Spry.Widget.CollapsiblePanel.prototype.onTabMouseOut = function(e){this.removeClassName(this.getTab(), this.hoverClass);return false;};Spry.Widget.CollapsiblePanel.prototype.open = function(){this.contentIsOpen = true;if (this.enableAnimation){if (this.animator)this.animator.stop();this.animator = new Spry.Widget.CollapsiblePanel.PanelAnimator(this, true, { duration: this.duration, fps: this.fps, transition: this.transition });this.animator.start();}elsethis.setDisplay(this.getContent(), "block");this.removeClassName(this.element, this.closedClass);this.addClassName(this.element, this.openClass);};Spry.Widget.CollapsiblePanel.prototype.close = function(){this.contentIsOpen = false;if (this.enableAnimation){if (this.animator)this.animator.stop();this.animator = new Spry.Widget.CollapsiblePanel.PanelAnimator(this, false, { duration: this.duration, fps: this.fps, transition: this.transition });this.animator.start();}elsethis.setDisplay(this.getContent(), "none");this.removeClassName(this.element, this.openClass);this.addClassName(this.element, this.closedClass);};Spry.Widget.CollapsiblePanel.prototype.onTabClick = function(e){if (this.isOpen())this.close();elsethis.open();this.focus();return this.stopPropagation(e);};Spry.Widget.CollapsiblePanel.prototype.onFocus = function(e){this.hasFocus = true;this.addClassName(this.element, this.focusedClass);return false;};Spry.Widget.CollapsiblePanel.prototype.onBlur = function(e){this.hasFocus = false;this.removeClassName(this.element, this.focusedClass);return false;};Spry.Widget.CollapsiblePanel.KEY_UP = 38;Spry.Widget.CollapsiblePanel.KEY_DOWN = 40;Spry.Widget.CollapsiblePanel.prototype.onKeyDown = function(e){var key = e.keyCode;if (!this.hasFocus || (key != this.openPanelKeyCode && key != this.closePanelKeyCode))return true;if (this.isOpen() && key == this.closePanelKeyCode)this.close();else if ( key == this.openPanelKeyCode)this.open();return this.stopPropagation(e);};Spry.Widget.CollapsiblePanel.prototype.stopPropagation = function(e){if (e.preventDefault) e.preventDefault();else e.returnValue = false;if (e.stopPropagation) e.stopPropagation();else e.cancelBubble = true;return false;};Spry.Widget.CollapsiblePanel.prototype.attachPanelHandlers = function(){var tab = this.getTab();if (!tab)return;var self = this;Spry.Widget.CollapsiblePanel.addEventListener(tab, "click", function(e) { return self.onTabClick(e); }, false);Spry.Widget.CollapsiblePanel.addEventListener(tab, "mouseover", function(e) { return self.onTabMouseOver(e); }, false);Spry.Widget.CollapsiblePanel.addEventListener(tab, "mouseout", function(e) { return self.onTabMouseOut(e); }, 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.CollapsiblePanel.addEventListener(this.focusElement, "focus", function(e) { return self.onFocus(e); }, false);Spry.Widget.CollapsiblePanel.addEventListener(this.focusElement, "blur", function(e) { return self.onBlur(e); }, false);Spry.Widget.CollapsiblePanel.addEventListener(this.focusElement, "keydown", function(e) { return self.onKeyDown(e); }, false);}}};Spry.Widget.CollapsiblePanel.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.CollapsiblePanel.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.CollapsiblePanel.prototype.attachBehaviors = function(){var panel = this.element;var tab = this.getTab();var content = this.getContent();if (this.contentIsOpen || this.hasClassName(panel, this.openClass)){this.addClassName(panel, this.openClass);this.removeClassName(panel, this.closedClass);this.setDisplay(content, "block");this.contentIsOpen = true;}else{this.removeClassName(panel, this.openClass);this.addClassName(panel, this.closedClass);this.setDisplay(content, "none");this.contentIsOpen = false;}this.attachPanelHandlers();};Spry.Widget.CollapsiblePanel.prototype.getTab = function(){return this.getElementChildren(this.element)[0];};Spry.Widget.CollapsiblePanel.prototype.getContent = function(){return this.getElementChildren(this.element)[1];};Spry.Widget.CollapsiblePanel.prototype.isOpen = function(){return this.contentIsOpen;};Spry.Widget.CollapsiblePanel.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.CollapsiblePanel.prototype.focus = function(){if (this.focusElement && this.focusElement.focus)this.focusElement.focus();};/////////////////////////////////////////////////////Spry.Widget.CollapsiblePanel.PanelAnimator = function(panel, doOpen, opts){this.timer = null;this.interval = 0;this.fps = 60;this.duration = 500;this.startTime = 0;this.transition = Spry.Widget.CollapsiblePanel.PanelAnimator.defaultTransition;this.onComplete = null;this.panel = panel;this.content = panel.getContent();this.doOpen = doOpen;Spry.Widget.CollapsiblePanel.setOptions(this, opts, true);this.interval = Math.floor(1000 / this.fps);var c = this.content;var curHeight = c.offsetHeight ? c.offsetHeight : 0;this.fromHeight = (doOpen && c.style.display == "none") ? 0 : curHeight;if (!doOpen)this.toHeight = 0;else{if (c.style.display == "none"){// The content area is not displayed so in order to calculate the extent// of the content inside it, we have to set its display to block.c.style.visibility = "hidden";c.style.display = "block";}// Clear the height property so we can calculate// the full height of the content we are going to show.c.style.height = "";this.toHeight = c.offsetHeight;}this.distance = this.toHeight - this.fromHeight;this.overflow = c.style.overflow;c.style.height = this.fromHeight + "px";c.style.visibility = "visible";c.style.overflow = "hidden";c.style.display = "block";};Spry.Widget.CollapsiblePanel.PanelAnimator.defaultTransition = function(time, begin, finish, duration) { time /= duration; return begin + ((2 - time) * time * finish); };Spry.Widget.CollapsiblePanel.PanelAnimator.prototype.start = function(){var self = this;this.startTime = (new Date).getTime();this.timer = setTimeout(function() { self.stepAnimation(); }, this.interval);};Spry.Widget.CollapsiblePanel.PanelAnimator.prototype.stop = function(){if (this.timer){clearTimeout(this.timer);// If we're killing the timer, restore the overflow property.this.content.style.overflow = this.overflow;}this.timer = null;};Spry.Widget.CollapsiblePanel.PanelAnimator.prototype.stepAnimation = function(){var curTime = (new Date).getTime();var elapsedTime = curTime - this.startTime;if (elapsedTime >= this.duration){if (!this.doOpen)this.content.style.display = "none";this.content.style.overflow = this.overflow;this.content.style.height = this.toHeight + "px";if (this.onComplete)this.onComplete();return;}var ht = this.transition(elapsedTime, this.fromHeight, this.distance, this.duration);this.content.style.height = ((ht < 0) ? 0 : ht) + "px";var self = this;this.timer = setTimeout(function() { self.stepAnimation(); }, this.interval);};Spry.Widget.CollapsiblePanelGroup = function(element, opts){this.element = this.getElement(element);this.opts = opts;this.attachBehaviors();};Spry.Widget.CollapsiblePanelGroup.prototype.setOptions = Spry.Widget.CollapsiblePanel.prototype.setOptions;Spry.Widget.CollapsiblePanelGroup.prototype.getElement = Spry.Widget.CollapsiblePanel.prototype.getElement;Spry.Widget.CollapsiblePanelGroup.prototype.getElementChildren = Spry.Widget.CollapsiblePanel.prototype.getElementChildren;Spry.Widget.CollapsiblePanelGroup.prototype.setElementWidget = function(element, widget){if (!element || !widget)return;if (!element.spry)element.spry = new Object;element.spry.collapsiblePanel = widget;};Spry.Widget.CollapsiblePanelGroup.prototype.getElementWidget = function(element){return (element && element.spry && element.spry.collapsiblePanel) ? element.spry.collapsiblePanel : null;};Spry.Widget.CollapsiblePanelGroup.prototype.getPanels = function(){if (!this.element)return [];return this.getElementChildren(this.element);};Spry.Widget.CollapsiblePanelGroup.prototype.getPanel = function(panelIndex){return this.getPanels()[panelIndex];};Spry.Widget.CollapsiblePanelGroup.prototype.attachBehaviors = function(){if (!this.element)return;var cpanels = this.getPanels();var numCPanels = cpanels.length;for (var i = 0; i < numCPanels; i++){var cpanel = cpanels[i];this.setElementWidget(cpanel, new Spry.Widget.CollapsiblePanel(cpanel, this.opts));}};Spry.Widget.CollapsiblePanelGroup.prototype.openPanel = function(panelIndex){var w = this.getElementWidget(this.getPanel(panelIndex));if (w && !w.isOpen())w.open();};Spry.Widget.CollapsiblePanelGroup.prototype.closePanel = function(panelIndex){var w = this.getElementWidget(this.getPanel(panelIndex));if (w && w.isOpen())w.close();};Spry.Widget.CollapsiblePanelGroup.prototype.openAllPanels = function(){var cpanels = this.getPanels();var numCPanels = cpanels.length;for (var i = 0; i < numCPanels; i++){var w = this.getElementWidget(cpanels[i]);if (w && !w.isOpen())w.open();}};Spry.Widget.CollapsiblePanelGroup.prototype.closeAllPanels = function(){var cpanels = this.getPanels();var numCPanels = cpanels.length;for (var i = 0; i < numCPanels; i++){var w = this.getElementWidget(cpanels[i]);if (w && w.isOpen())w.close();}};