home *** CD-ROM | disk | FTP | other *** search
/ mcgregor.k12.mn.us / www.mcgregor.k12.mn.us.tar / www.mcgregor.k12.mn.us / SpryAssets / SpryCollapsiblePanel.js < prev    next >
Text File  |  2010-09-08  |  16KB  |  535 lines

  1. // SpryCollapsiblePanel.js - version 0.7 - Spry Pre-Release 1.6.1
  2. //
  3. // Copyright (c) 2006. Adobe Systems Incorporated.
  4. // All rights reserved.
  5. //
  6. // Redistribution and use in source and binary forms, with or without
  7. // modification, are permitted provided that the following conditions are met:
  8. //
  9. //   * Redistributions of source code must retain the above copyright notice,
  10. //     this list of conditions and the following disclaimer.
  11. //   * Redistributions in binary form must reproduce the above copyright notice,
  12. //     this list of conditions and the following disclaimer in the documentation
  13. //     and/or other materials provided with the distribution.
  14. //   * Neither the name of Adobe Systems Incorporated nor the names of its
  15. //     contributors may be used to endorse or promote products derived from this
  16. //     software without specific prior written permission.
  17. //
  18. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  19. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21. // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  22. // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  23. // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  24. // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  25. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  26. // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  27. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. // POSSIBILITY OF SUCH DAMAGE.
  29.  
  30. var Spry;
  31. if (!Spry) Spry = {};
  32. if (!Spry.Widget) Spry.Widget = {};
  33.  
  34. Spry.Widget.CollapsiblePanel = function(element, opts)
  35. {
  36.     this.element = this.getElement(element);
  37.     this.focusElement = null;
  38.     this.hoverClass = "CollapsiblePanelTabHover";
  39.     this.openClass = "CollapsiblePanelOpen";
  40.     this.closedClass = "CollapsiblePanelClosed";
  41.     this.focusedClass = "CollapsiblePanelFocused";
  42.     this.enableAnimation = true;
  43.     this.enableKeyboardNavigation = true;
  44.     this.animator = null;
  45.     this.hasFocus = false;
  46.     this.contentIsOpen = true;
  47.  
  48.     this.openPanelKeyCode = Spry.Widget.CollapsiblePanel.KEY_DOWN;
  49.     this.closePanelKeyCode = Spry.Widget.CollapsiblePanel.KEY_UP;
  50.  
  51.     Spry.Widget.CollapsiblePanel.setOptions(this, opts);
  52.  
  53.     this.attachBehaviors();
  54. };
  55.  
  56. Spry.Widget.CollapsiblePanel.prototype.getElement = function(ele)
  57. {
  58.     if (ele && typeof ele == "string")
  59.         return document.getElementById(ele);
  60.     return ele;
  61. };
  62.  
  63. Spry.Widget.CollapsiblePanel.prototype.addClassName = function(ele, className)
  64. {
  65.     if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) != -1))
  66.         return;
  67.     ele.className += (ele.className ? " " : "") + className;
  68. };
  69.  
  70. Spry.Widget.CollapsiblePanel.prototype.removeClassName = function(ele, className)
  71. {
  72.     if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) == -1))
  73.         return;
  74.     ele.className = ele.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), "");
  75. };
  76.  
  77. Spry.Widget.CollapsiblePanel.prototype.hasClassName = function(ele, className)
  78. {
  79.     if (!ele || !className || !ele.className || ele.className.search(new RegExp("\\b" + className + "\\b")) == -1)
  80.         return false;
  81.     return true;
  82. };
  83.  
  84. Spry.Widget.CollapsiblePanel.prototype.setDisplay = function(ele, display)
  85. {
  86.     if( ele )
  87.         ele.style.display = display;
  88. };
  89.  
  90. Spry.Widget.CollapsiblePanel.setOptions = function(obj, optionsObj, ignoreUndefinedProps)
  91. {
  92.     if (!optionsObj)
  93.         return;
  94.     for (var optionName in optionsObj)
  95.     {
  96.         if (ignoreUndefinedProps && optionsObj[optionName] == undefined)
  97.             continue;
  98.         obj[optionName] = optionsObj[optionName];
  99.     }
  100. };
  101.  
  102. Spry.Widget.CollapsiblePanel.prototype.onTabMouseOver = function(e)
  103. {
  104.     this.addClassName(this.getTab(), this.hoverClass);
  105.     return false;
  106. };
  107.  
  108. Spry.Widget.CollapsiblePanel.prototype.onTabMouseOut = function(e)
  109. {
  110.     this.removeClassName(this.getTab(), this.hoverClass);
  111.     return false;
  112. };
  113.  
  114. Spry.Widget.CollapsiblePanel.prototype.open = function()
  115. {
  116.     this.contentIsOpen = true;
  117.     if (this.enableAnimation)
  118.     {
  119.         if (this.animator)
  120.             this.animator.stop();
  121.         this.animator = new Spry.Widget.CollapsiblePanel.PanelAnimator(this, true, { duration: this.duration, fps: this.fps, transition: this.transition });
  122.         this.animator.start();
  123.     }
  124.     else
  125.         this.setDisplay(this.getContent(), "block");
  126.  
  127.     this.removeClassName(this.element, this.closedClass);
  128.     this.addClassName(this.element, this.openClass);
  129. };
  130.  
  131. Spry.Widget.CollapsiblePanel.prototype.close = function()
  132. {
  133.     this.contentIsOpen = false;
  134.     if (this.enableAnimation)
  135.     {
  136.         if (this.animator)
  137.             this.animator.stop();
  138.         this.animator = new Spry.Widget.CollapsiblePanel.PanelAnimator(this, false, { duration: this.duration, fps: this.fps, transition: this.transition });
  139.         this.animator.start();
  140.     }
  141.     else
  142.         this.setDisplay(this.getContent(), "none");
  143.  
  144.     this.removeClassName(this.element, this.openClass);
  145.     this.addClassName(this.element, this.closedClass);
  146. };
  147.  
  148. Spry.Widget.CollapsiblePanel.prototype.onTabClick = function(e)
  149. {
  150.     if (this.isOpen())
  151.         this.close();
  152.     else
  153.         this.open();
  154.  
  155.     this.focus();
  156.  
  157.     return this.stopPropagation(e);
  158. };
  159.  
  160. Spry.Widget.CollapsiblePanel.prototype.onFocus = function(e)
  161. {
  162.     this.hasFocus = true;
  163.     this.addClassName(this.element, this.focusedClass);
  164.     return false;
  165. };
  166.  
  167. Spry.Widget.CollapsiblePanel.prototype.onBlur = function(e)
  168. {
  169.     this.hasFocus = false;
  170.     this.removeClassName(this.element, this.focusedClass);
  171.     return false;
  172. };
  173.  
  174. Spry.Widget.CollapsiblePanel.KEY_UP = 38;
  175. Spry.Widget.CollapsiblePanel.KEY_DOWN = 40;
  176.  
  177. Spry.Widget.CollapsiblePanel.prototype.onKeyDown = function(e)
  178. {
  179.     var key = e.keyCode;
  180.     if (!this.hasFocus || (key != this.openPanelKeyCode && key != this.closePanelKeyCode))
  181.         return true;
  182.  
  183.     if (this.isOpen() && key == this.closePanelKeyCode)
  184.         this.close();
  185.     else if ( key == this.openPanelKeyCode)
  186.         this.open();
  187.     
  188.     return this.stopPropagation(e);
  189. };
  190.  
  191. Spry.Widget.CollapsiblePanel.prototype.stopPropagation = function(e)
  192. {
  193.     if (e.preventDefault) e.preventDefault();
  194.     else e.returnValue = false;
  195.     if (e.stopPropagation) e.stopPropagation();
  196.     else e.cancelBubble = true;
  197.     return false;
  198. };
  199.  
  200. Spry.Widget.CollapsiblePanel.prototype.attachPanelHandlers = function()
  201. {
  202.     var tab = this.getTab();
  203.     if (!tab)
  204.         return;
  205.  
  206.     var self = this;
  207.     Spry.Widget.CollapsiblePanel.addEventListener(tab, "click", function(e) { return self.onTabClick(e); }, false);
  208.     Spry.Widget.CollapsiblePanel.addEventListener(tab, "mouseover", function(e) { return self.onTabMouseOver(e); }, false);
  209.     Spry.Widget.CollapsiblePanel.addEventListener(tab, "mouseout", function(e) { return self.onTabMouseOut(e); }, false);
  210.  
  211.     if (this.enableKeyboardNavigation)
  212.     {
  213.         // XXX: IE doesn't allow the setting of tabindex dynamically. This means we can't
  214.         // rely on adding the tabindex attribute if it is missing to enable keyboard navigation
  215.         // by default.
  216.  
  217.         // Find the first element within the tab container that has a tabindex or the first
  218.         // anchor tag.
  219.         
  220.         var tabIndexEle = null;
  221.         var tabAnchorEle = null;
  222.  
  223.         this.preorderTraversal(tab, function(node) {
  224.             if (node.nodeType == 1 /* NODE.ELEMENT_NODE */)
  225.             {
  226.                 var tabIndexAttr = tab.attributes.getNamedItem("tabindex");
  227.                 if (tabIndexAttr)
  228.                 {
  229.                     tabIndexEle = node;
  230.                     return true;
  231.                 }
  232.                 if (!tabAnchorEle && node.nodeName.toLowerCase() == "a")
  233.                     tabAnchorEle = node;
  234.             }
  235.             return false;
  236.         });
  237.  
  238.         if (tabIndexEle)
  239.             this.focusElement = tabIndexEle;
  240.         else if (tabAnchorEle)
  241.             this.focusElement = tabAnchorEle;
  242.  
  243.         if (this.focusElement)
  244.         {
  245.             Spry.Widget.CollapsiblePanel.addEventListener(this.focusElement, "focus", function(e) { return self.onFocus(e); }, false);
  246.             Spry.Widget.CollapsiblePanel.addEventListener(this.focusElement, "blur", function(e) { return self.onBlur(e); }, false);
  247.             Spry.Widget.CollapsiblePanel.addEventListener(this.focusElement, "keydown", function(e) { return self.onKeyDown(e); }, false);
  248.         }
  249.     }
  250. };
  251.  
  252. Spry.Widget.CollapsiblePanel.addEventListener = function(element, eventType, handler, capture)
  253. {
  254.     try
  255.     {
  256.         if (element.addEventListener)
  257.             element.addEventListener(eventType, handler, capture);
  258.         else if (element.attachEvent)
  259.             element.attachEvent("on" + eventType, handler);
  260.     }
  261.     catch (e) {}
  262. };
  263.  
  264. Spry.Widget.CollapsiblePanel.prototype.preorderTraversal = function(root, func)
  265. {
  266.     var stopTraversal = false;
  267.     if (root)
  268.     {
  269.         stopTraversal = func(root);
  270.         if (root.hasChildNodes())
  271.         {
  272.             var child = root.firstChild;
  273.             while (!stopTraversal && child)
  274.             {
  275.                 stopTraversal = this.preorderTraversal(child, func);
  276.                 try { child = child.nextSibling; } catch (e) { child = null; }
  277.             }
  278.         }
  279.     }
  280.     return stopTraversal;
  281. };
  282.  
  283. Spry.Widget.CollapsiblePanel.prototype.attachBehaviors = function()
  284. {
  285.     var panel = this.element;
  286.     var tab = this.getTab();
  287.     var content = this.getContent();
  288.  
  289.     if (this.contentIsOpen || this.hasClassName(panel, this.openClass))
  290.     {
  291.         this.addClassName(panel, this.openClass);
  292.         this.removeClassName(panel, this.closedClass);
  293.         this.setDisplay(content, "block");
  294.         this.contentIsOpen = true;
  295.     }
  296.     else
  297.     {
  298.         this.removeClassName(panel, this.openClass);
  299.         this.addClassName(panel, this.closedClass);
  300.         this.setDisplay(content, "none");
  301.         this.contentIsOpen = false;
  302.     }
  303.  
  304.     this.attachPanelHandlers();
  305. };
  306.  
  307. Spry.Widget.CollapsiblePanel.prototype.getTab = function()
  308. {
  309.     return this.getElementChildren(this.element)[0];
  310. };
  311.  
  312. Spry.Widget.CollapsiblePanel.prototype.getContent = function()
  313. {
  314.     return this.getElementChildren(this.element)[1];
  315. };
  316.  
  317. Spry.Widget.CollapsiblePanel.prototype.isOpen = function()
  318. {
  319.     return this.contentIsOpen;
  320. };
  321.  
  322. Spry.Widget.CollapsiblePanel.prototype.getElementChildren = function(element)
  323. {
  324.     var children = [];
  325.     var child = element.firstChild;
  326.     while (child)
  327.     {
  328.         if (child.nodeType == 1 /* Node.ELEMENT_NODE */)
  329.             children.push(child);
  330.         child = child.nextSibling;
  331.     }
  332.     return children;
  333. };
  334.  
  335. Spry.Widget.CollapsiblePanel.prototype.focus = function()
  336. {
  337.     if (this.focusElement && this.focusElement.focus)
  338.         this.focusElement.focus();
  339. };
  340.  
  341. /////////////////////////////////////////////////////
  342.  
  343. Spry.Widget.CollapsiblePanel.PanelAnimator = function(panel, doOpen, opts)
  344. {
  345.     this.timer = null;
  346.     this.interval = 0;
  347.  
  348.     this.fps = 60;
  349.     this.duration = 500;
  350.     this.startTime = 0;
  351.  
  352.     this.transition = Spry.Widget.CollapsiblePanel.PanelAnimator.defaultTransition;
  353.  
  354.     this.onComplete = null;
  355.  
  356.     this.panel = panel;
  357.     this.content = panel.getContent();
  358.     this.doOpen = doOpen;
  359.  
  360.     Spry.Widget.CollapsiblePanel.setOptions(this, opts, true);
  361.  
  362.     this.interval = Math.floor(1000 / this.fps);
  363.  
  364.     var c = this.content;
  365.  
  366.     var curHeight = c.offsetHeight ? c.offsetHeight : 0;
  367.     this.fromHeight = (doOpen && c.style.display == "none") ? 0 : curHeight;
  368.  
  369.     if (!doOpen)
  370.         this.toHeight = 0;
  371.     else
  372.     {
  373.         if (c.style.display == "none")
  374.         {
  375.             // The content area is not displayed so in order to calculate the extent
  376.             // of the content inside it, we have to set its display to block.
  377.  
  378.             c.style.visibility = "hidden";
  379.             c.style.display = "block";
  380.         }
  381.  
  382.         // Clear the height property so we can calculate
  383.         // the full height of the content we are going to show.
  384.  
  385.         c.style.height = "";
  386.         this.toHeight = c.offsetHeight;
  387.     }
  388.  
  389.     this.distance = this.toHeight - this.fromHeight;
  390.     this.overflow = c.style.overflow;
  391.  
  392.     c.style.height = this.fromHeight + "px";
  393.     c.style.visibility = "visible";
  394.     c.style.overflow = "hidden";
  395.     c.style.display = "block";
  396. };
  397.  
  398. Spry.Widget.CollapsiblePanel.PanelAnimator.defaultTransition = function(time, begin, finish, duration) { time /= duration; return begin + ((2 - time) * time * finish); };
  399.  
  400. Spry.Widget.CollapsiblePanel.PanelAnimator.prototype.start = function()
  401. {
  402.     var self = this;
  403.     this.startTime = (new Date).getTime();
  404.     this.timer = setTimeout(function() { self.stepAnimation(); }, this.interval);
  405. };
  406.  
  407. Spry.Widget.CollapsiblePanel.PanelAnimator.prototype.stop = function()
  408. {
  409.     if (this.timer)
  410.     {
  411.         clearTimeout(this.timer);
  412.  
  413.         // If we're killing the timer, restore the overflow property.
  414.  
  415.         this.content.style.overflow = this.overflow;
  416.     }
  417.  
  418.     this.timer = null;
  419. };
  420.  
  421. Spry.Widget.CollapsiblePanel.PanelAnimator.prototype.stepAnimation = function()
  422. {
  423.     var curTime = (new Date).getTime();
  424.     var elapsedTime = curTime - this.startTime;
  425.  
  426.     if (elapsedTime >= this.duration)
  427.     {
  428.         if (!this.doOpen)
  429.             this.content.style.display = "none";
  430.         this.content.style.overflow = this.overflow;
  431.         this.content.style.height = this.toHeight + "px";
  432.         if (this.onComplete)
  433.             this.onComplete();
  434.         return;
  435.     }
  436.  
  437.     var ht = this.transition(elapsedTime, this.fromHeight, this.distance, this.duration);
  438.  
  439.     this.content.style.height = ((ht < 0) ? 0 : ht) + "px";
  440.  
  441.     var self = this;
  442.     this.timer = setTimeout(function() { self.stepAnimation(); }, this.interval);
  443. };
  444.  
  445. Spry.Widget.CollapsiblePanelGroup = function(element, opts)
  446. {
  447.     this.element = this.getElement(element);
  448.     this.opts = opts;
  449.  
  450.     this.attachBehaviors();
  451. };
  452.  
  453. Spry.Widget.CollapsiblePanelGroup.prototype.setOptions = Spry.Widget.CollapsiblePanel.prototype.setOptions;
  454. Spry.Widget.CollapsiblePanelGroup.prototype.getElement = Spry.Widget.CollapsiblePanel.prototype.getElement;
  455. Spry.Widget.CollapsiblePanelGroup.prototype.getElementChildren = Spry.Widget.CollapsiblePanel.prototype.getElementChildren;
  456.  
  457. Spry.Widget.CollapsiblePanelGroup.prototype.setElementWidget = function(element, widget)
  458. {
  459.     if (!element || !widget)
  460.         return;
  461.     if (!element.spry)
  462.         element.spry = new Object;
  463.     element.spry.collapsiblePanel = widget;
  464. };
  465.  
  466. Spry.Widget.CollapsiblePanelGroup.prototype.getElementWidget = function(element)
  467. {
  468.     return (element && element.spry && element.spry.collapsiblePanel) ? element.spry.collapsiblePanel : null;
  469. };
  470.  
  471. Spry.Widget.CollapsiblePanelGroup.prototype.getPanels = function()
  472. {
  473.     if (!this.element)
  474.         return [];
  475.     return this.getElementChildren(this.element);
  476. };
  477.  
  478. Spry.Widget.CollapsiblePanelGroup.prototype.getPanel = function(panelIndex)
  479. {
  480.     return this.getPanels()[panelIndex];
  481. };
  482.  
  483. Spry.Widget.CollapsiblePanelGroup.prototype.attachBehaviors = function()
  484. {
  485.     if (!this.element)
  486.         return;
  487.  
  488.     var cpanels = this.getPanels();
  489.     var numCPanels = cpanels.length;
  490.     for (var i = 0; i < numCPanels; i++)
  491.     {
  492.         var cpanel = cpanels[i];
  493.         this.setElementWidget(cpanel, new Spry.Widget.CollapsiblePanel(cpanel, this.opts));
  494.     }
  495. };
  496.  
  497. Spry.Widget.CollapsiblePanelGroup.prototype.openPanel = function(panelIndex)
  498. {
  499.     var w = this.getElementWidget(this.getPanel(panelIndex));
  500.     if (w && !w.isOpen())
  501.         w.open();
  502. };
  503.  
  504. Spry.Widget.CollapsiblePanelGroup.prototype.closePanel = function(panelIndex)
  505. {
  506.     var w = this.getElementWidget(this.getPanel(panelIndex));
  507.     if (w && w.isOpen())
  508.         w.close();
  509. };
  510.  
  511. Spry.Widget.CollapsiblePanelGroup.prototype.openAllPanels = function()
  512. {
  513.     var cpanels = this.getPanels();
  514.     var numCPanels = cpanels.length;
  515.     for (var i = 0; i < numCPanels; i++)
  516.     {
  517.         var w = this.getElementWidget(cpanels[i]);
  518.         if (w && !w.isOpen())
  519.             w.open();
  520.     }
  521. };
  522.  
  523. Spry.Widget.CollapsiblePanelGroup.prototype.closeAllPanels = function()
  524. {
  525.     var cpanels = this.getPanels();
  526.     var numCPanels = cpanels.length;
  527.     for (var i = 0; i < numCPanels; i++)
  528.     {
  529.         var w = this.getElementWidget(cpanels[i]);
  530.         if (w && w.isOpen())
  531.             w.close();
  532.     }
  533. };
  534.  
  535.