Accordion.html 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>The source code</title>
  6. <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  7. <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  8. <style type="text/css">
  9. .highlight { display: block; background-color: #ddd; }
  10. </style>
  11. <script type="text/javascript">
  12. function highlight() {
  13. document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
  14. }
  15. </script>
  16. </head>
  17. <body onload="prettyPrint(); highlight();">
  18. <pre class="prettyprint lang-js"><span id='Ext-layout-container-Accordion'>/**
  19. </span> * This is a layout that manages multiple Panels in an expandable accordion style such that by default only
  20. * one Panel can be expanded at any given time (set {@link #multi} config to have more open). Each Panel has
  21. * built-in support for expanding and collapsing.
  22. *
  23. * Note: Only Ext Panels and all subclasses of Ext.panel.Panel may be used in an accordion layout Container.
  24. *
  25. * @example
  26. * Ext.create('Ext.panel.Panel', {
  27. * title: 'Accordion Layout',
  28. * width: 300,
  29. * height: 300,
  30. * defaults: {
  31. * // applied to each contained panel
  32. * bodyStyle: 'padding:15px'
  33. * },
  34. * layout: {
  35. * // layout-specific configs go here
  36. * type: 'accordion',
  37. * titleCollapse: false,
  38. * animate: true,
  39. * activeOnTop: true
  40. * },
  41. * items: [{
  42. * title: 'Panel 1',
  43. * html: 'Panel content!'
  44. * },{
  45. * title: 'Panel 2',
  46. * html: 'Panel content!'
  47. * },{
  48. * title: 'Panel 3',
  49. * html: 'Panel content!'
  50. * }],
  51. * renderTo: Ext.getBody()
  52. * });
  53. */
  54. Ext.define('Ext.layout.container.Accordion', {
  55. extend: 'Ext.layout.container.VBox',
  56. alias: ['layout.accordion'],
  57. alternateClassName: 'Ext.layout.AccordionLayout',
  58. itemCls: [Ext.baseCSSPrefix + 'box-item', Ext.baseCSSPrefix + 'accordion-item'],
  59. align: 'stretch',
  60. <span id='Ext-layout-container-Accordion-cfg-fill'> /**
  61. </span> * @cfg {Boolean} fill
  62. * True to adjust the active item's height to fill the available space in the container, false to use the
  63. * item's current height, or auto height if not explicitly set.
  64. */
  65. fill : true,
  66. <span id='Ext-layout-container-Accordion-cfg-autoWidth'> /**
  67. </span> * @cfg {Boolean} autoWidth
  68. * Child Panels have their width actively managed to fit within the accordion's width.
  69. * @removed This config is ignored in ExtJS 4
  70. */
  71. <span id='Ext-layout-container-Accordion-cfg-titleCollapse'> /**
  72. </span> * @cfg {Boolean} titleCollapse
  73. * True to allow expand/collapse of each contained panel by clicking anywhere on the title bar, false to allow
  74. * expand/collapse only when the toggle tool button is clicked. When set to false,
  75. * {@link #hideCollapseTool} should be false also.
  76. */
  77. titleCollapse : true,
  78. <span id='Ext-layout-container-Accordion-cfg-hideCollapseTool'> /**
  79. </span> * @cfg {Boolean} hideCollapseTool
  80. * True to hide the contained Panels' collapse/expand toggle buttons, false to display them.
  81. * When set to true, {@link #titleCollapse} is automatically set to true.
  82. */
  83. hideCollapseTool : false,
  84. <span id='Ext-layout-container-Accordion-cfg-collapseFirst'> /**
  85. </span> * @cfg {Boolean} collapseFirst
  86. * True to make sure the collapse/expand toggle button always renders first (to the left of) any other tools
  87. * in the contained Panels' title bars, false to render it last.
  88. */
  89. collapseFirst : false,
  90. <span id='Ext-layout-container-Accordion-cfg-animate'> /**
  91. </span> * @cfg {Boolean} animate
  92. * True to slide the contained panels open and closed during expand/collapse using animation, false to open and
  93. * close directly with no animation. Note: The layout performs animated collapsing
  94. * and expanding, *not* the child Panels.
  95. */
  96. animate : true,
  97. <span id='Ext-layout-container-Accordion-cfg-activeOnTop'> /**
  98. </span> * @cfg {Boolean} activeOnTop
  99. * Only valid when {@link #multi} is `false` and {@link #animate} is `false`.
  100. *
  101. * True to swap the position of each panel as it is expanded so that it becomes the first item in the container,
  102. * false to keep the panels in the rendered order.
  103. */
  104. activeOnTop : false,
  105. <span id='Ext-layout-container-Accordion-cfg-multi'> /**
  106. </span> * @cfg {Boolean} multi
  107. * Set to true to enable multiple accordion items to be open at once.
  108. */
  109. multi: false,
  110. defaultAnimatePolicy: {
  111. y: true,
  112. height: true
  113. },
  114. constructor: function() {
  115. var me = this;
  116. me.callParent(arguments);
  117. if (me.animate) {
  118. me.animatePolicy = Ext.apply({}, me.defaultAnimatePolicy);
  119. } else {
  120. me.animatePolicy = null;
  121. }
  122. },
  123. beforeRenderItems: function (items) {
  124. var me = this,
  125. ln = items.length,
  126. i = 0,
  127. comp;
  128. for (; i &lt; ln; i++) {
  129. comp = items[i];
  130. if (!comp.rendered) {
  131. // Set up initial properties for Panels in an accordion.
  132. if (me.collapseFirst) {
  133. comp.collapseFirst = me.collapseFirst;
  134. }
  135. if (me.hideCollapseTool) {
  136. comp.hideCollapseTool = me.hideCollapseTool;
  137. comp.titleCollapse = true;
  138. }
  139. else if (me.titleCollapse) {
  140. comp.titleCollapse = me.titleCollapse;
  141. }
  142. delete comp.hideHeader;
  143. delete comp.width;
  144. comp.collapsible = true;
  145. comp.title = comp.title || '&amp;#160;';
  146. comp.addBodyCls(Ext.baseCSSPrefix + 'accordion-body');
  147. // If only one child Panel is allowed to be expanded
  148. // then collapse all except the first one found with collapsed:false
  149. if (!me.multi) {
  150. // If there is an expanded item, all others must be rendered collapsed.
  151. if (me.expandedItem !== undefined) {
  152. comp.collapsed = true;
  153. }
  154. // Otherwise expand the first item with collapsed explicitly configured as false
  155. else if (comp.hasOwnProperty('collapsed') &amp;&amp; comp.collapsed === false) {
  156. me.expandedItem = i;
  157. } else {
  158. comp.collapsed = true;
  159. }
  160. // If only one child Panel may be expanded, then intercept expand/show requests.
  161. me.owner.mon(comp, {
  162. show: me.onComponentShow,
  163. beforeexpand: me.onComponentExpand,
  164. scope: me
  165. });
  166. }
  167. // If we must fill available space, a collapse must be listened for and a sibling must
  168. // be expanded.
  169. if (me.fill) {
  170. me.owner.mon(comp, {
  171. beforecollapse: me.onComponentCollapse,
  172. scope: me
  173. });
  174. }
  175. }
  176. }
  177. // If no collapsed:false Panels found, make the first one expanded.
  178. if (ln &amp;&amp; me.expandedItem === undefined) {
  179. me.expandedItem = 0;
  180. items[0].collapsed = false;
  181. }
  182. },
  183. getItemsRenderTree: function(items) {
  184. this.beforeRenderItems(items);
  185. return this.callParent(arguments);
  186. },
  187. renderItems : function(items, target) {
  188. this.beforeRenderItems(items);
  189. this.callParent(arguments);
  190. },
  191. configureItem: function(item) {
  192. this.callParent(arguments);
  193. // We handle animations for the expand/collapse of items.
  194. // Items do not have individual borders
  195. item.animCollapse = item.border = false;
  196. // If filling available space, all Panels flex.
  197. if (this.fill) {
  198. item.flex = 1;
  199. }
  200. },
  201. onChildPanelRender: function(panel) {
  202. panel.header.addCls(Ext.baseCSSPrefix + 'accordion-hd');
  203. },
  204. beginLayout: function (ownerContext) {
  205. this.callParent(arguments);
  206. this.updatePanelClasses(ownerContext);
  207. },
  208. updatePanelClasses: function(ownerContext) {
  209. var children = ownerContext.visibleItems,
  210. ln = children.length,
  211. siblingCollapsed = true,
  212. i, child, header;
  213. for (i = 0; i &lt; ln; i++) {
  214. child = children[i];
  215. header = child.header;
  216. header.addCls(Ext.baseCSSPrefix + 'accordion-hd');
  217. if (siblingCollapsed) {
  218. header.removeCls(Ext.baseCSSPrefix + 'accordion-hd-sibling-expanded');
  219. } else {
  220. header.addCls(Ext.baseCSSPrefix + 'accordion-hd-sibling-expanded');
  221. }
  222. if (i + 1 == ln &amp;&amp; child.collapsed) {
  223. header.addCls(Ext.baseCSSPrefix + 'accordion-hd-last-collapsed');
  224. } else {
  225. header.removeCls(Ext.baseCSSPrefix + 'accordion-hd-last-collapsed');
  226. }
  227. siblingCollapsed = child.collapsed;
  228. }
  229. },
  230. // When a Component expands, adjust the heights of the other Components to be just enough to accommodate
  231. // their headers.
  232. // The expanded Component receives the only flex value, and so gets all remaining space.
  233. onComponentExpand: function(toExpand) {
  234. var me = this,
  235. owner = me.owner,
  236. expanded,
  237. expandedCount, i,
  238. previousValue;
  239. if (!me.processing) {
  240. me.processing = true;
  241. previousValue = owner.deferLayouts;
  242. owner.deferLayouts = true;
  243. expanded = me.multi ? [] : owner.query('&gt;panel:not([collapsed])');
  244. expandedCount = expanded.length;
  245. // Collapse all other expanded child items (Won't loop if multi is true)
  246. for (i = 0; i &lt; expandedCount; i++) {
  247. expanded[i].collapse();
  248. }
  249. owner.deferLayouts = previousValue;
  250. me.processing = false;
  251. }
  252. },
  253. onComponentCollapse: function(comp) {
  254. var me = this,
  255. owner = me.owner,
  256. toExpand,
  257. expanded,
  258. previousValue;
  259. if (me.owner.items.getCount() === 1) {
  260. // do not allow collapse if there is only one item
  261. return false;
  262. }
  263. if (!me.processing) {
  264. me.processing = true;
  265. previousValue = owner.deferLayouts;
  266. owner.deferLayouts = true;
  267. toExpand = comp.next() || comp.prev();
  268. // If we are allowing multi, and the &quot;toCollapse&quot; component is NOT the only expanded Component,
  269. // then ask the box layout to collapse it to its header.
  270. if (me.multi) {
  271. expanded = me.owner.query('&gt;panel:not([collapsed])');
  272. // If the collapsing Panel is the only expanded one, expand the following Component.
  273. // All this is handling fill: true, so there must be at least one expanded,
  274. if (expanded.length === 1) {
  275. toExpand.expand();
  276. }
  277. } else if (toExpand) {
  278. toExpand.expand();
  279. }
  280. owner.deferLayouts = previousValue;
  281. me.processing = false;
  282. }
  283. },
  284. onComponentShow: function(comp) {
  285. // Showing a Component means that you want to see it, so expand it.
  286. this.onComponentExpand(comp);
  287. }
  288. });</pre>
  289. </body>
  290. </html>