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; }
11 <script type="text/javascript">
12 function highlight() {
13 document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
17 <body onload="prettyPrint(); highlight();">
18 <pre class="prettyprint lang-js"><span id='Ext-layout-container-Accordion'>/**
19 </span> * @class Ext.layout.container.Accordion
20 * @extends Ext.layout.container.VBox
22 * This is a layout that manages multiple Panels in an expandable accordion style such that only
23 * **one Panel can be expanded at any given time**. Each Panel has built-in support for expanding and collapsing.
25 * Note: Only Ext Panels and all subclasses of Ext.panel.Panel may be used in an accordion layout Container.
28 * Ext.create('Ext.panel.Panel', {
29 * title: 'Accordion Layout',
34 * // applied to each contained panel
35 * bodyStyle: 'padding:15px'
38 * // layout-specific configs go here
39 * titleCollapse: false,
45 * html: 'Panel content!'
48 * html: 'Panel content!'
51 * html: 'Panel content!'
53 * renderTo: Ext.getBody()
56 Ext.define('Ext.layout.container.Accordion', {
57 extend: 'Ext.layout.container.VBox',
58 alias: ['layout.accordion'],
59 alternateClassName: 'Ext.layout.AccordionLayout',
61 itemCls: Ext.baseCSSPrefix + 'box-item ' + Ext.baseCSSPrefix + 'accordion-item',
65 <span id='Ext-layout-container-Accordion-cfg-fill'> /**
66 </span> * @cfg {Boolean} fill
67 * True to adjust the active item's height to fill the available space in the container, false to use the
68 * item's current height, or auto height if not explicitly set.
72 <span id='Ext-layout-container-Accordion-cfg-autoWidth'> /**
73 </span> * @cfg {Boolean} autoWidth
74 * Child Panels have their width actively managed to fit within the accordion's width.
75 * @deprecated This config is ignored in ExtJS 4
79 <span id='Ext-layout-container-Accordion-cfg-titleCollapse'> /**
80 </span> * @cfg {Boolean} titleCollapse
81 * True to allow expand/collapse of each contained panel by clicking anywhere on the title bar, false to allow
82 * expand/collapse only when the toggle tool button is clicked. When set to false,
83 * {@link #hideCollapseTool} should be false also.
87 <span id='Ext-layout-container-Accordion-cfg-hideCollapseTool'> /**
88 </span> * @cfg {Boolean} hideCollapseTool
89 * True to hide the contained Panels' collapse/expand toggle buttons, false to display them.
90 * When set to true, {@link #titleCollapse} is automatically set to <code>true</code>.
92 hideCollapseTool : false,
94 <span id='Ext-layout-container-Accordion-cfg-collapseFirst'> /**
95 </span> * @cfg {Boolean} collapseFirst
96 * True to make sure the collapse/expand toggle button always renders first (to the left of) any other tools
97 * in the contained Panels' title bars, false to render it last.
99 collapseFirst : false,
101 <span id='Ext-layout-container-Accordion-cfg-animate'> /**
102 </span> * @cfg {Boolean} animate
103 * True to slide the contained panels open and closed during expand/collapse using animation, false to open and
104 * close directly with no animation. Note: The layout performs animated collapsing
105 * and expanding, <i>not</i> the child Panels.
108 <span id='Ext-layout-container-Accordion-cfg-activeOnTop'> /**
109 </span> * @cfg {Boolean} activeOnTop
110 * Only valid when {@link #multi} is `false` and {@link #animate} is `false`.
112 * True to swap the position of each panel as it is expanded so that it becomes the first item in the container,
113 * false to keep the panels in the rendered order.
116 <span id='Ext-layout-container-Accordion-cfg-multi'> /**
117 </span> * @cfg {Boolean} multi
118 * Set to <code>true</code> to enable multiple accordion items to be open at once.
122 constructor: function() {
125 me.callParent(arguments);
127 // animate flag must be false during initial render phase so we don't get animations.
128 me.initialAnimate = me.animate;
131 // Child Panels are not absolutely positioned if we are not filling, so use a different itemCls.
132 if (me.fill === false) {
133 me.itemCls = Ext.baseCSSPrefix + 'accordion-item';
137 // Cannot lay out a fitting accordion before we have been allocated a height.
138 // So during render phase, layout will not be performed.
139 beforeLayout: function() {
142 me.callParent(arguments);
144 if (!(me.owner.el.dom.style.height || me.getLayoutTargetSize().height)) {
148 me.owner.componentLayout.monitorChildren = false;
150 me.owner.setAutoScroll(true);
154 renderItems : function(items, target) {
159 targetSize = me.getLayoutTargetSize(),
162 for (; i < ln; i++) {
164 if (!comp.rendered) {
165 renderedPanels.push(comp);
167 // Set up initial properties for Panels in an accordion.
168 if (me.collapseFirst) {
169 comp.collapseFirst = me.collapseFirst;
171 if (me.hideCollapseTool) {
172 comp.hideCollapseTool = me.hideCollapseTool;
173 comp.titleCollapse = true;
175 else if (me.titleCollapse) {
176 comp.titleCollapse = me.titleCollapse;
179 delete comp.hideHeader;
180 comp.collapsible = true;
181 comp.title = comp.title || '&#160;';
184 comp.width = targetSize.width;
189 // If there is an expanded item, all others must be rendered collapsed.
190 if (me.expandedItem !== undefined) {
191 comp.collapsed = true;
193 // Otherwise expand the first item with collapsed explicitly configured as false
194 else if (comp.hasOwnProperty('collapsed') && comp.collapsed === false) {
198 comp.collapsed = true;
200 // If we are fitting, then intercept expand/collapse requests.
202 show: me.onComponentShow,
203 beforeexpand: me.onComponentExpand,
204 beforecollapse: me.onComponentCollapse,
209 comp.animCollapse = me.initialAnimate;
210 comp.autoHeight = true;
211 comp.autoScroll = false;
213 comp.border = comp.collapsed;
217 // If no collapsed:false Panels found, make the first one expanded.
218 if (ln && me.expandedItem === undefined) {
221 comp.collapsed = comp.border = false;
227 // Render all Panels.
228 me.callParent(arguments);
230 // Postprocess rendered Panels.
231 ln = renderedPanels.length;
232 for (i = 0; i < ln; i++) {
233 comp = renderedPanels[i];
235 // Delete the dimension property so that our align: 'stretch' processing manages the width from here
238 comp.header.addCls(Ext.baseCSSPrefix + 'accordion-hd');
239 comp.body.addCls(Ext.baseCSSPrefix + 'accordion-body');
243 onLayout: function() {
248 me.callParent(arguments);
250 var targetSize = me.getLayoutTargetSize(),
251 items = me.getVisibleItems(),
255 for (; i < len; i++) {
257 if (comp.collapsed) {
258 items[i].setWidth(targetSize.width);
260 items[i].setSize(null, null);
264 me.updatePanelClasses();
269 updatePanelClasses: function() {
270 var children = this.getLayoutItems(),
271 ln = children.length,
272 siblingCollapsed = true,
275 for (i = 0; i < ln; i++) {
278 // Fix for EXTJSIV-3724. Windows only.
279 // Collapsing the Psnel's el to a size which only allows a single hesder to be visible, scrolls the header out of view.
281 child.el.dom.scrollTop = 0;
284 if (siblingCollapsed) {
285 child.header.removeCls(Ext.baseCSSPrefix + 'accordion-hd-sibling-expanded');
288 child.header.addCls(Ext.baseCSSPrefix + 'accordion-hd-sibling-expanded');
291 if (i + 1 == ln && child.collapsed) {
292 child.header.addCls(Ext.baseCSSPrefix + 'accordion-hd-last-collapsed');
295 child.header.removeCls(Ext.baseCSSPrefix + 'accordion-hd-last-collapsed');
297 siblingCollapsed = child.collapsed;
301 animCallback: function(){
302 Ext.Array.forEach(this.toCollapse, function(comp){
303 comp.fireEvent('collapse', comp);
306 Ext.Array.forEach(this.toExpand, function(comp){
307 comp.fireEvent('expand', comp);
311 setupEvents: function(){
312 this.toCollapse = [];
316 // When a Component expands, adjust the heights of the other Components to be just enough to accommodate
318 // The expanded Component receives the only flex value, and so gets all remaining space.
319 onComponentExpand: function(toExpand) {
321 it = me.owner.items.items,
327 for (; i < len; i++) {
329 if (comp === toExpand && comp.collapsed) {
330 me.setExpanded(comp);
331 } else if (!me.multi && (comp.rendered && comp.header.rendered && comp !== toExpand && !comp.collapsed)) {
332 me.setCollapsed(comp);
336 me.animate = me.initialAnimate;
337 if (me.activeOnTop) {
338 // insert will trigger a layout
339 me.owner.insert(0, toExpand);
347 onComponentCollapse: function(comp) {
349 toExpand = comp.next() || comp.prev(),
350 expanded = me.multi ? me.owner.query('>panel:not([collapsed])') : [];
353 // If we are allowing multi, and the "toCollapse" component is NOT the only expanded Component,
354 // then ask the box layout to collapse it to its header.
356 me.setCollapsed(comp);
358 // If the collapsing Panel is the only expanded one, expand the following Component.
359 // All this is handling fill: true, so there must be at least one expanded,
360 if (expanded.length === 1 && expanded[0] === comp) {
361 me.setExpanded(toExpand);
364 me.animate = me.initialAnimate;
368 // Not allowing multi: expand the next sibling if possible, prev sibling if we collapsed the last
370 me.onComponentExpand(toExpand);
375 onComponentShow: function(comp) {
376 // Showing a Component means that you want to see it, so expand it.
377 this.onComponentExpand(comp);
380 setCollapsed: function(comp) {
381 var otherDocks = comp.getDockedItems(),
383 len = otherDocks.length,
386 // Hide all docked items except the header
387 comp.hiddenDocked = [];
388 for (; i < len; i++) {
389 dockItem = otherDocks[i];
390 if ((dockItem !== comp.header) && !dockItem.hidden) {
391 dockItem.hidden = true;
392 comp.hiddenDocked.push(dockItem);
395 comp.addCls(comp.collapsedCls);
396 comp.header.addCls(comp.collapsedHeaderCls);
397 comp.height = comp.header.getHeight();
398 comp.el.setHeight(comp.height);
399 comp.collapsed = true;
401 if (this.initialAnimate) {
402 this.toCollapse.push(comp);
404 comp.fireEvent('collapse', comp);
406 if (comp.collapseTool) {
407 comp.collapseTool.setType('expand-' + comp.getOppositeDirection(comp.collapseDirection));
411 setExpanded: function(comp) {
412 var otherDocks = comp.hiddenDocked,
413 len = otherDocks ? otherDocks.length : 0,
416 // Show temporarily hidden docked items
417 for (; i < len; i++) {
418 otherDocks[i].show();
421 // If it was an initial native collapse which hides the body
422 if (!comp.body.isVisible()) {
425 delete comp.collapsed;
427 delete comp.componentLayout.lastComponentSize;
428 comp.suspendLayout = false;
430 comp.removeCls(comp.collapsedCls);
431 comp.header.removeCls(comp.collapsedHeaderCls);
432 if (this.initialAnimate) {
433 this.toExpand.push(comp);
435 comp.fireEvent('expand', comp);
437 if (comp.collapseTool) {
438 comp.collapseTool.setType('collapse-' + comp.collapseDirection);
440 comp.setAutoScroll(comp.initialConfig.autoScroll);