TitlePane.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*
  2. Copyright (c) 2004-2012, 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.TitlePane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dijit.TitlePane"] = true;
  8. dojo.provide("dijit.TitlePane");
  9. dojo.require("dojo.fx");
  10. dojo.require("dijit._Templated");
  11. dojo.require("dijit.layout.ContentPane");
  12. dojo.require("dijit._CssStateMixin");
  13. dojo.declare(
  14. "dijit.TitlePane",
  15. [dijit.layout.ContentPane, dijit._Templated, dijit._CssStateMixin],
  16. {
  17. // summary:
  18. // A pane with a title on top, that can be expanded or collapsed.
  19. //
  20. // description:
  21. // An accessible container with a title Heading, and a content
  22. // section that slides open and closed. TitlePane is an extension to
  23. // `dijit.layout.ContentPane`, providing all the useful content-control aspects from it.
  24. //
  25. // example:
  26. // | // load a TitlePane from remote file:
  27. // | var foo = new dijit.TitlePane({ href: "foobar.html", title:"Title" });
  28. // | foo.startup();
  29. //
  30. // example:
  31. // | <!-- markup href example: -->
  32. // | <div dojoType="dijit.TitlePane" href="foobar.html" title="Title"></div>
  33. //
  34. // example:
  35. // | <!-- markup with inline data -->
  36. // | <div dojoType="dijit.TitlePane" title="Title">
  37. // | <p>I am content</p>
  38. // | </div>
  39. // title: String
  40. // Title of the pane
  41. title: "",
  42. // open: Boolean
  43. // Whether pane is opened or closed.
  44. open: true,
  45. // toggleable: Boolean
  46. // Whether pane can be opened or closed by clicking the title bar.
  47. toggleable: true,
  48. // tabIndex: String
  49. // Tabindex setting for the title (so users can tab to the title then
  50. // use space/enter to open/close the title pane)
  51. tabIndex: "0",
  52. // duration: Integer
  53. // Time in milliseconds to fade in/fade out
  54. duration: dijit.defaultDuration,
  55. // baseClass: [protected] String
  56. // The root className to be placed on this widget's domNode.
  57. baseClass: "dijitTitlePane",
  58. templateString: dojo.cache("dijit", "templates/TitlePane.html", "<div>\n\t<div dojoAttachEvent=\"onclick:_onTitleClick, onkeypress:_onTitleKey\"\n\t\t\tclass=\"dijitTitlePaneTitle\" dojoAttachPoint=\"titleBarNode\">\n\t\t<div class=\"dijitTitlePaneTitleFocus\" dojoAttachPoint=\"focusNode\">\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" dojoAttachPoint=\"arrowNode\" class=\"dijitArrowNode\" role=\"presentation\"\n\t\t\t/><span dojoAttachPoint=\"arrowNodeInner\" class=\"dijitArrowNodeInner\"></span\n\t\t\t><span dojoAttachPoint=\"titleNode\" class=\"dijitTitlePaneTextNode\"></span>\n\t\t</div>\n\t</div>\n\t<div class=\"dijitTitlePaneContentOuter\" dojoAttachPoint=\"hideNode\" role=\"presentation\">\n\t\t<div class=\"dijitReset\" dojoAttachPoint=\"wipeNode\" role=\"presentation\">\n\t\t\t<div class=\"dijitTitlePaneContentInner\" dojoAttachPoint=\"containerNode\" role=\"region\" id=\"${id}_pane\">\n\t\t\t\t<!-- nested divs because wipeIn()/wipeOut() doesn't work right on node w/padding etc. Put padding on inner div. -->\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n"),
  59. attributeMap: dojo.delegate(dijit.layout.ContentPane.prototype.attributeMap, {
  60. title: { node: "titleNode", type: "innerHTML" },
  61. tooltip: {node: "focusNode", type: "attribute", attribute: "title"}, // focusNode spans the entire width, titleNode doesn't
  62. id:""
  63. }),
  64. buildRendering: function(){
  65. this.inherited(arguments);
  66. dojo.setSelectable(this.titleNode, false);
  67. },
  68. postCreate: function(){
  69. this.inherited(arguments);
  70. // Hover and focus effect on title bar, except for non-toggleable TitlePanes
  71. // This should really be controlled from _setToggleableAttr() but _CssStateMixin
  72. // doesn't provide a way to disconnect a previous _trackMouseState() call
  73. if(this.toggleable){
  74. this._trackMouseState(this.titleBarNode, "dijitTitlePaneTitle");
  75. }
  76. // setup open/close animations
  77. var hideNode = this.hideNode, wipeNode = this.wipeNode;
  78. this._wipeIn = dojo.fx.wipeIn({
  79. node: this.wipeNode,
  80. duration: this.duration,
  81. beforeBegin: function(){
  82. hideNode.style.display="";
  83. }
  84. });
  85. this._wipeOut = dojo.fx.wipeOut({
  86. node: this.wipeNode,
  87. duration: this.duration,
  88. onEnd: function(){
  89. hideNode.style.display="none";
  90. }
  91. });
  92. },
  93. _setOpenAttr: function(/*Boolean*/ open, /*Boolean*/ animate){
  94. // summary:
  95. // Hook to make set("open", boolean) control the open/closed state of the pane.
  96. // open: Boolean
  97. // True if you want to open the pane, false if you want to close it.
  98. dojo.forEach([this._wipeIn, this._wipeOut], function(animation){
  99. if(animation && animation.status() == "playing"){
  100. animation.stop();
  101. }
  102. });
  103. if(animate){
  104. var anim = this[open ? "_wipeIn" : "_wipeOut"];
  105. anim.play();
  106. }else{
  107. this.hideNode.style.display = this.wipeNode.style.display = open ? "" : "none";
  108. }
  109. // load content (if this is the first time we are opening the TitlePane
  110. // and content is specified as an href, or href was set when hidden)
  111. if(this._started){
  112. if(open){
  113. this._onShow();
  114. }else{
  115. this.onHide();
  116. }
  117. }
  118. this.arrowNodeInner.innerHTML = open ? "-" : "+";
  119. dijit.setWaiState(this.containerNode,"hidden", open ? "false" : "true");
  120. dijit.setWaiState(this.focusNode, "pressed", open ? "true" : "false");
  121. this._set("open", open);
  122. this._setCss();
  123. },
  124. _setToggleableAttr: function(/*Boolean*/ canToggle){
  125. // summary:
  126. // Hook to make set("toggleable", boolean) work.
  127. // canToggle: Boolean
  128. // True to allow user to open/close pane by clicking title bar.
  129. dijit.setWaiRole(this.focusNode, canToggle ? "button" : "heading");
  130. if(canToggle){
  131. // TODO: if canToggle is switched from true to false shouldn't we remove this setting?
  132. dijit.setWaiState(this.focusNode, "controls", this.id+"_pane");
  133. dojo.attr(this.focusNode, "tabIndex", this.tabIndex);
  134. }else{
  135. dojo.removeAttr(this.focusNode, "tabIndex");
  136. }
  137. this._set("toggleable", canToggle);
  138. this._setCss();
  139. },
  140. _setContentAttr: function(/*String|DomNode|Nodelist*/ content){
  141. // summary:
  142. // Hook to make set("content", ...) work.
  143. // Typically called when an href is loaded. Our job is to make the animation smooth.
  144. if(!this.open || !this._wipeOut || this._wipeOut.status() == "playing"){
  145. // we are currently *closing* the pane (or the pane is closed), so just let that continue
  146. this.inherited(arguments);
  147. }else{
  148. if(this._wipeIn && this._wipeIn.status() == "playing"){
  149. this._wipeIn.stop();
  150. }
  151. // freeze container at current height so that adding new content doesn't make it jump
  152. dojo.marginBox(this.wipeNode, { h: dojo.marginBox(this.wipeNode).h });
  153. // add the new content (erasing the old content, if any)
  154. this.inherited(arguments);
  155. // call _wipeIn.play() to animate from current height to new height
  156. if(this._wipeIn){
  157. this._wipeIn.play();
  158. }else{
  159. this.hideNode.style.display = "";
  160. }
  161. }
  162. },
  163. toggle: function(){
  164. // summary:
  165. // Switches between opened and closed state
  166. // tags:
  167. // private
  168. this._setOpenAttr(!this.open, true);
  169. },
  170. _setCss: function(){
  171. // summary:
  172. // Set the open/close css state for the TitlePane
  173. // tags:
  174. // private
  175. var node = this.titleBarNode || this.focusNode;
  176. var oldCls = this._titleBarClass;
  177. this._titleBarClass = "dijit" + (this.toggleable ? "" : "Fixed") + (this.open ? "Open" : "Closed");
  178. dojo.replaceClass(node, this._titleBarClass, oldCls || "");
  179. this.arrowNodeInner.innerHTML = this.open ? "-" : "+";
  180. },
  181. _onTitleKey: function(/*Event*/ e){
  182. // summary:
  183. // Handler for when user hits a key
  184. // tags:
  185. // private
  186. if(e.charOrCode == dojo.keys.ENTER || e.charOrCode == ' '){
  187. if(this.toggleable){
  188. this.toggle();
  189. }
  190. dojo.stopEvent(e);
  191. }else if(e.charOrCode == dojo.keys.DOWN_ARROW && this.open){
  192. this.containerNode.focus();
  193. e.preventDefault();
  194. }
  195. },
  196. _onTitleClick: function(){
  197. // summary:
  198. // Handler when user clicks the title bar
  199. // tags:
  200. // private
  201. if(this.toggleable){
  202. this.toggle();
  203. }
  204. },
  205. setTitle: function(/*String*/ title){
  206. // summary:
  207. // Deprecated. Use set('title', ...) instead.
  208. // tags:
  209. // deprecated
  210. dojo.deprecated("dijit.TitlePane.setTitle() is deprecated. Use set('title', ...) instead.", "", "2.0");
  211. this.set("title", title);
  212. }
  213. });
  214. }