/public/javascripts/dojo/release/dojo/dijit/layout/AccordionContainer.js

http://enginey.googlecode.com/ · JavaScript · 265 lines · 184 code · 32 blank · 49 comment · 19 complexity · 9aa52551eff13a9fb9a86c15be5d2f81 MD5 · raw file

  1. /*
  2. Copyright (c) 2004-2008, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dijit.layout.AccordionContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dijit.layout.AccordionContainer"] = true;
  8. dojo.provide("dijit.layout.AccordionContainer");
  9. dojo.require("dojo.fx");
  10. dojo.require("dijit._Container");
  11. dojo.require("dijit._Templated");
  12. dojo.require("dijit.layout.StackContainer");
  13. dojo.require("dijit.layout.ContentPane");
  14. dojo.declare(
  15. "dijit.layout.AccordionContainer",
  16. dijit.layout.StackContainer,
  17. {
  18. // summary:
  19. // Holds a set of panes where every pane's title is visible, but only one pane's content is visible at a time,
  20. // and switching between panes is visualized by sliding the other panes up/down.
  21. // example:
  22. // | <div dojoType="dijit.layout.AccordionContainer">
  23. // | <div dojoType="dijit.layout.AccordionPane" title="pane 1">
  24. // | <div dojoType="dijit.layout.ContentPane">...</div>
  25. // | </div>
  26. // | <div dojoType="dijit.layout.AccordionPane" title="pane 2">
  27. // | <p>This is some text</p>
  28. // || ...
  29. // | </div>
  30. //
  31. // duration: Integer
  32. // Amount of time (in ms) it takes to slide panes
  33. duration: dijit.defaultDuration,
  34. _verticalSpace: 0,
  35. baseClass: "dijitAccordionContainer",
  36. postCreate: function(){
  37. this.domNode.style.overflow = "hidden";
  38. this.inherited(arguments);
  39. dijit.setWaiRole(this.domNode, "tablist");
  40. },
  41. startup: function(){
  42. if(this._started){ return; }
  43. this.inherited(arguments);
  44. if(this.selectedChildWidget){
  45. var style = this.selectedChildWidget.containerNode.style;
  46. style.display = "";
  47. style.overflow = "auto";
  48. this.selectedChildWidget._setSelectedState(true);
  49. }
  50. },
  51. _getTargetHeight: function(/* Node */ node){
  52. // summary:
  53. // For the given node, returns the height that should be
  54. // set to achieve our vertical space (subtract any padding
  55. // we may have)
  56. var cs = dojo.getComputedStyle(node);
  57. return Math.max(this._verticalSpace - dojo._getPadBorderExtents(node, cs).h, 0);
  58. },
  59. layout: function(){
  60. // summary:
  61. // Set the height of the open pane based on what room remains
  62. // get cumulative height of all the title bars, and figure out which pane is open
  63. var totalCollapsedHeight = 0;
  64. var openPane = this.selectedChildWidget;
  65. dojo.forEach(this.getChildren(), function(child){
  66. totalCollapsedHeight += child.getTitleHeight();
  67. });
  68. var mySize = this._contentBox;
  69. this._verticalSpace = mySize.h - totalCollapsedHeight;
  70. if(openPane){
  71. openPane.containerNode.style.height = this._getTargetHeight(openPane.containerNode) + "px";
  72. /***
  73. TODO: this is wrong. probably you wanted to call resize on the SplitContainer
  74. inside the AccordionPane??
  75. if(openPane.resize){
  76. openPane.resize({h: this._verticalSpace});
  77. }
  78. ***/
  79. }
  80. },
  81. _setupChild: function(/*Widget*/ page){
  82. // Summary: prepare the given child
  83. return page;
  84. },
  85. _transition: function(/*Widget?*/newWidget, /*Widget?*/oldWidget){
  86. //TODO: should be able to replace this with calls to slideIn/slideOut
  87. if(this._inTransition){ return; }
  88. this._inTransition = true;
  89. var animations = [];
  90. var paneHeight = this._verticalSpace;
  91. if(newWidget){
  92. newWidget.setSelected(true);
  93. var newContents = newWidget.containerNode;
  94. newContents.style.display = "";
  95. paneHeight = this._getTargetHeight(newWidget.containerNode)
  96. animations.push(dojo.animateProperty({
  97. node: newContents,
  98. duration: this.duration,
  99. properties: {
  100. height: { start: 1, end: paneHeight }
  101. },
  102. onEnd: function(){
  103. newContents.style.overflow = "auto";
  104. }
  105. }));
  106. }
  107. if(oldWidget){
  108. oldWidget.setSelected(false);
  109. var oldContents = oldWidget.containerNode;
  110. oldContents.style.overflow = "hidden";
  111. paneHeight = this._getTargetHeight(oldWidget.containerNode);
  112. animations.push(dojo.animateProperty({
  113. node: oldContents,
  114. duration: this.duration,
  115. properties: {
  116. height: { start: paneHeight, end: "1" }
  117. },
  118. onEnd: function(){
  119. oldContents.style.display = "none";
  120. }
  121. }));
  122. }
  123. this._inTransition = false;
  124. dojo.fx.combine(animations).play();
  125. },
  126. // note: we are treating the container as controller here
  127. _onKeyPress: function(/*Event*/ e){
  128. if(this.disabled || e.altKey || !(e._dijitWidget || e.ctrlKey)){ return; }
  129. var k = dojo.keys;
  130. var fromTitle = e._dijitWidget;
  131. switch(e.charOrCode){
  132. case k.LEFT_ARROW:
  133. case k.UP_ARROW:
  134. if (fromTitle){
  135. this._adjacent(false)._onTitleClick();
  136. dojo.stopEvent(e);
  137. }
  138. break;
  139. case k.PAGE_UP:
  140. if (e.ctrlKey){
  141. this._adjacent(false)._onTitleClick();
  142. dojo.stopEvent(e);
  143. }
  144. break;
  145. case k.RIGHT_ARROW:
  146. case k.DOWN_ARROW:
  147. if (fromTitle){
  148. this._adjacent(true)._onTitleClick();
  149. dojo.stopEvent(e);
  150. }
  151. break;
  152. case k.PAGE_DOWN:
  153. if (e.ctrlKey){
  154. this._adjacent(true)._onTitleClick();
  155. dojo.stopEvent(e);
  156. }
  157. break;
  158. default:
  159. if(e.ctrlKey && e.charOrCode === k.TAB){
  160. this._adjacent(e._dijitWidget, !e.shiftKey)._onTitleClick();
  161. dojo.stopEvent(e);
  162. }
  163. }
  164. }
  165. }
  166. );
  167. dojo.declare("dijit.layout.AccordionPane",
  168. [dijit.layout.ContentPane, dijit._Templated, dijit._Contained],
  169. {
  170. // summary:
  171. // AccordionPane is a ContentPane with a title that may contain another widget.
  172. // Nested layout widgets, such as SplitContainer, are not supported at this time.
  173. // example:
  174. // | see dijit.layout.AccordionContainer
  175. templateString:"<div waiRole=\"presentation\"\r\n\t><div dojoAttachPoint='titleNode,focusNode' dojoAttachEvent='ondijitclick:_onTitleClick,onkeypress:_onTitleKeyPress,onfocus:_handleFocus,onblur:_handleFocus,onmouseenter:_onTitleEnter,onmouseleave:_onTitleLeave'\r\n\t\tclass='dijitAccordionTitle' wairole=\"tab\" waiState=\"expanded-false\"\r\n\t\t><span class='dijitInline dijitAccordionArrow' waiRole=\"presentation\"></span\r\n\t\t><span class='arrowTextUp' waiRole=\"presentation\">+</span\r\n\t\t><span class='arrowTextDown' waiRole=\"presentation\">-</span\r\n\t\t><span waiRole=\"presentation\" dojoAttachPoint='titleTextNode' class='dijitAccordionText'></span></div\r\n\t><div waiRole=\"presentation\"><div dojoAttachPoint='containerNode' style='overflow: hidden; height: 1px; display: none'\r\n\t\tclass='dijitAccordionBody' wairole=\"tabpanel\"\r\n\t></div></div>\r\n</div>\r\n",
  176. attributeMap: dojo.mixin(dojo.clone(dijit.layout.ContentPane.prototype.attributeMap), {
  177. title: {node: "titleTextNode", type: "innerHTML" }
  178. }),
  179. baseClass: "dijitAccordionPane",
  180. postCreate: function(){
  181. this.inherited(arguments)
  182. dojo.setSelectable(this.titleNode, false);
  183. this.setSelected(this.selected);
  184. dojo.attr(this.titleTextNode, "id", this.domNode.id+"_title");
  185. dijit.setWaiState(this.focusNode, "labelledby", dojo.attr(this.titleTextNode, "id"));
  186. },
  187. getTitleHeight: function(){
  188. // summary: returns the height of the title dom node
  189. return dojo.marginBox(this.titleNode).h; // Integer
  190. },
  191. _onTitleClick: function(){
  192. // summary: callback when someone clicks my title
  193. var parent = this.getParent();
  194. if(!parent._inTransition){
  195. parent.selectChild(this);
  196. dijit.focus(this.focusNode);
  197. }
  198. },
  199. _onTitleEnter: function(){
  200. // summary: callback when someone hovers over my title
  201. dojo.addClass(this.focusNode, "dijitAccordionTitle-hover");
  202. },
  203. _onTitleLeave: function(){
  204. // summary: callback when someone stops hovering over my title
  205. dojo.removeClass(this.focusNode, "dijitAccordionTitle-hover");
  206. },
  207. _onTitleKeyPress: function(/*Event*/ evt){
  208. evt._dijitWidget = this;
  209. return this.getParent()._onKeyPress(evt);
  210. },
  211. _setSelectedState: function(/*Boolean*/ isSelected){
  212. this.selected = isSelected;
  213. dojo[(isSelected ? "addClass" : "removeClass")](this.titleNode,"dijitAccordionTitle-selected");
  214. dijit.setWaiState(this.focusNode, "expanded", isSelected);
  215. this.focusNode.setAttribute("tabIndex", isSelected ? "0" : "-1");
  216. },
  217. _handleFocus: function(/*Event*/e){
  218. // summary: handle the blur and focus state of this widget
  219. dojo[(e.type=="focus" ? "addClass" : "removeClass")](this.focusNode,"dijitAccordionFocused");
  220. },
  221. setSelected: function(/*Boolean*/ isSelected){
  222. // summary: change the selected state on this pane
  223. this._setSelectedState(isSelected);
  224. if(isSelected){
  225. this.onSelected();
  226. this._loadCheck(); // if href specified, trigger load
  227. }
  228. },
  229. onSelected: function(){
  230. // summary: called when this pane is selected
  231. }
  232. });
  233. }