Upgrade to ExtJS 4.0.1 - Released 05/18/2011
[extjs.git] / docs / source / Box.html
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="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../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-Box'>/**
19 </span> * @class Ext.layout.container.Box
20  * @extends Ext.layout.container.Container
21  * &lt;p&gt;Base Class for HBoxLayout and VBoxLayout Classes. Generally it should not need to be used directly.&lt;/p&gt;
22  */
23
24 Ext.define('Ext.layout.container.Box', {
25
26     /* Begin Definitions */
27
28     alias: ['layout.box'],
29     extend: 'Ext.layout.container.Container',
30     alternateClassName: 'Ext.layout.BoxLayout',
31     
32     requires: [
33         'Ext.layout.container.boxOverflow.None',
34         'Ext.layout.container.boxOverflow.Menu',
35         'Ext.layout.container.boxOverflow.Scroller',
36         'Ext.util.Format',
37         'Ext.dd.DragDropManager'
38     ],
39
40     /* End Definitions */
41
42 <span id='Ext-layout-container-Box-cfg-animate'>    /**
43 </span>     * @cfg {Mixed} animate
44      * &lt;p&gt;If truthy, child Component are &lt;i&gt;animated&lt;/i&gt; into position whenever the Container
45      * is layed out. If this option is numeric, it is used as the animation duration in milliseconds.&lt;/p&gt;
46      * &lt;p&gt;May be set as a property at any time.&lt;/p&gt;
47      */
48
49 <span id='Ext-layout-container-Box-cfg-defaultMargins'>    /**
50 </span>     * @cfg {Object} defaultMargins
51      * &lt;p&gt;If the individual contained items do not have a &lt;tt&gt;margins&lt;/tt&gt;
52      * property specified or margin specified via CSS, the default margins from this property will be
53      * applied to each item.&lt;/p&gt;
54      * &lt;br&gt;&lt;p&gt;This property may be specified as an object containing margins
55      * to apply in the format:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;
56 {
57     top: (top margin),
58     right: (right margin),
59     bottom: (bottom margin),
60     left: (left margin)
61 }&lt;/code&gt;&lt;/pre&gt;
62      * &lt;p&gt;This property may also be specified as a string containing
63      * space-separated, numeric margin values. The order of the sides associated
64      * with each value matches the way CSS processes margin values:&lt;/p&gt;
65      * &lt;div class=&quot;mdetail-params&quot;&gt;&lt;ul&gt;
66      * &lt;li&gt;If there is only one value, it applies to all sides.&lt;/li&gt;
67      * &lt;li&gt;If there are two values, the top and bottom borders are set to the
68      * first value and the right and left are set to the second.&lt;/li&gt;
69      * &lt;li&gt;If there are three values, the top is set to the first value, the left
70      * and right are set to the second, and the bottom is set to the third.&lt;/li&gt;
71      * &lt;li&gt;If there are four values, they apply to the top, right, bottom, and
72      * left, respectively.&lt;/li&gt;
73      * &lt;/ul&gt;&lt;/div&gt;
74      * &lt;p&gt;Defaults to:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;
75      * {top:0, right:0, bottom:0, left:0}
76      * &lt;/code&gt;&lt;/pre&gt;
77      */
78     defaultMargins: {
79         top: 0,
80         right: 0,
81         bottom: 0,
82         left: 0
83     },
84
85 <span id='Ext-layout-container-Box-cfg-padding'>    /**
86 </span>     * @cfg {String} padding
87      * &lt;p&gt;Sets the padding to be applied to all child items managed by this layout.&lt;/p&gt;
88      * &lt;p&gt;This property must be specified as a string containing
89      * space-separated, numeric padding values. The order of the sides associated
90      * with each value matches the way CSS processes padding values:&lt;/p&gt;
91      * &lt;div class=&quot;mdetail-params&quot;&gt;&lt;ul&gt;
92      * &lt;li&gt;If there is only one value, it applies to all sides.&lt;/li&gt;
93      * &lt;li&gt;If there are two values, the top and bottom borders are set to the
94      * first value and the right and left are set to the second.&lt;/li&gt;
95      * &lt;li&gt;If there are three values, the top is set to the first value, the left
96      * and right are set to the second, and the bottom is set to the third.&lt;/li&gt;
97      * &lt;li&gt;If there are four values, they apply to the top, right, bottom, and
98      * left, respectively.&lt;/li&gt;
99      * &lt;/ul&gt;&lt;/div&gt;
100      * &lt;p&gt;Defaults to: &lt;code&gt;&quot;0&quot;&lt;/code&gt;&lt;/p&gt;
101      */
102     padding: '0',
103     // documented in subclasses
104     pack: 'start',
105
106 <span id='Ext-layout-container-Box-cfg-pack'>    /**
107 </span>     * @cfg {String} pack
108      * Controls how the child items of the container are packed together. Acceptable configuration values
109      * for this property are:
110      * &lt;div class=&quot;mdetail-params&quot;&gt;&lt;ul&gt;
111      * &lt;li&gt;&lt;b&gt;&lt;tt&gt;start&lt;/tt&gt;&lt;/b&gt; : &lt;b&gt;Default&lt;/b&gt;&lt;div class=&quot;sub-desc&quot;&gt;child items are packed together at
112      * &lt;b&gt;left&lt;/b&gt; side of container&lt;/div&gt;&lt;/li&gt;
113      * &lt;li&gt;&lt;b&gt;&lt;tt&gt;center&lt;/tt&gt;&lt;/b&gt; : &lt;div class=&quot;sub-desc&quot;&gt;child items are packed together at
114      * &lt;b&gt;mid-width&lt;/b&gt; of container&lt;/div&gt;&lt;/li&gt;
115      * &lt;li&gt;&lt;b&gt;&lt;tt&gt;end&lt;/tt&gt;&lt;/b&gt; : &lt;div class=&quot;sub-desc&quot;&gt;child items are packed together at &lt;b&gt;right&lt;/b&gt;
116      * side of container&lt;/div&gt;&lt;/li&gt;
117      * &lt;/ul&gt;&lt;/div&gt;
118      */
119 <span id='Ext-layout-container-Box-cfg-flex'>    /**
120 </span>     * @cfg {Number} flex
121      * This configuration option is to be applied to &lt;b&gt;child &lt;tt&gt;items&lt;/tt&gt;&lt;/b&gt; of the container managed
122      * by this layout. Each child item with a &lt;tt&gt;flex&lt;/tt&gt; property will be flexed &lt;b&gt;horizontally&lt;/b&gt;
123      * according to each item's &lt;b&gt;relative&lt;/b&gt; &lt;tt&gt;flex&lt;/tt&gt; value compared to the sum of all items with
124      * a &lt;tt&gt;flex&lt;/tt&gt; value specified.  Any child items that have either a &lt;tt&gt;flex = 0&lt;/tt&gt; or
125      * &lt;tt&gt;flex = undefined&lt;/tt&gt; will not be 'flexed' (the initial size will not be changed).
126      */
127
128     type: 'box',
129     scrollOffset: 0,
130     itemCls: Ext.baseCSSPrefix + 'box-item',
131     targetCls: Ext.baseCSSPrefix + 'box-layout-ct',
132     innerCls: Ext.baseCSSPrefix + 'box-inner',
133
134     bindToOwnerCtContainer: true,
135
136     fixedLayout: false,
137     
138     // availableSpaceOffset is used to adjust the availableWidth, typically used
139     // to reserve space for a scrollbar
140     availableSpaceOffset: 0,
141     
142     // whether or not to reserve the availableSpaceOffset in layout calculations
143     reserveOffset: true,
144     
145 <span id='Ext-layout-container-Box-cfg-clearInnerCtOnLayout'>    /**
146 </span>     * @cfg {Boolean} clearInnerCtOnLayout
147      */
148     clearInnerCtOnLayout: false,
149
150     flexSortFn: function (a, b) {
151         var maxParallelPrefix = 'max' + this.parallelPrefixCap,
152             infiniteValue = Infinity;
153         a = a.component[maxParallelPrefix] || infiniteValue;
154         b = b.component[maxParallelPrefix] || infiniteValue;
155         // IE 6/7 Don't like Infinity - Infinity...
156         if (!isFinite(a) &amp;&amp; !isFinite(b)) {
157             return false;
158         }
159         return a - b;
160     },
161
162     // Sort into *descending* order.
163     minSizeSortFn: function(a, b) {
164         return b.available - a.available;
165     },
166
167     constructor: function(config) {
168         var me = this;
169
170         me.callParent(arguments);
171
172         // The sort function needs access to properties in this, so must be bound.
173         me.flexSortFn = Ext.Function.bind(me.flexSortFn, me);
174
175         me.initOverflowHandler();
176     },
177
178 <span id='Ext-layout-container-Box-method-getChildBox'>    /**
179 </span>     * @private
180      * Returns the current size and positioning of the passed child item.
181      * @param {Component} child The child Component to calculate the box for
182      * @return {Object} Object containing box measurements for the child. Properties are left,top,width,height.
183      */
184     getChildBox: function(child) {
185         child = child.el || this.owner.getComponent(child).el;
186         return {
187             left: child.getLeft(true),
188             top: child.getTop(true),
189             width: child.getWidth(),
190             height: child.getHeight()
191         };
192     },
193
194 <span id='Ext-layout-container-Box-method-calculateChildBox'>    /**
195 </span>     * @private
196      * Calculates the size and positioning of the passed child item.
197      * @param {Component} child The child Component to calculate the box for
198      * @return {Object} Object containing box measurements for the child. Properties are left,top,width,height.
199      */
200     calculateChildBox: function(child) {
201         var me = this,
202             boxes = me.calculateChildBoxes(me.getVisibleItems(), me.getLayoutTargetSize()).boxes,
203             ln = boxes.length,
204             i = 0;
205
206         child = me.owner.getComponent(child);
207         for (; i &lt; ln; i++) {
208             if (boxes[i].component === child) {
209                 return boxes[i];
210             }
211         }
212     },
213
214 <span id='Ext-layout-container-Box-method-calculateChildBoxes'>    /**
215 </span>     * @private
216      * Calculates the size and positioning of each item in the box. This iterates over all of the rendered,
217      * visible items and returns a height, width, top and left for each, as well as a reference to each. Also
218      * returns meta data such as maxSize which are useful when resizing layout wrappers such as this.innerCt.
219      * @param {Array} visibleItems The array of all rendered, visible items to be calculated for
220      * @param {Object} targetSize Object containing target size and height
221      * @return {Object} Object containing box measurements for each child, plus meta data
222      */
223     calculateChildBoxes: function(visibleItems, targetSize) {
224         var me = this,
225             math = Math,
226             mmax = math.max,
227             infiniteValue = Infinity,
228             undefinedValue,
229
230             parallelPrefix = me.parallelPrefix,
231             parallelPrefixCap = me.parallelPrefixCap,
232             perpendicularPrefix = me.perpendicularPrefix,
233             perpendicularPrefixCap = me.perpendicularPrefixCap,
234             parallelMinString = 'min' + parallelPrefixCap,
235             perpendicularMinString = 'min' + perpendicularPrefixCap,
236             perpendicularMaxString = 'max' + perpendicularPrefixCap,
237
238             parallelSize = targetSize[parallelPrefix] - me.scrollOffset,
239             perpendicularSize = targetSize[perpendicularPrefix],
240             padding = me.padding,
241             parallelOffset = padding[me.parallelBefore],
242             paddingParallel = parallelOffset + padding[me.parallelAfter],
243             perpendicularOffset = padding[me.perpendicularLeftTop],
244             paddingPerpendicular =  perpendicularOffset + padding[me.perpendicularRightBottom],
245             availPerpendicularSize = mmax(0, perpendicularSize - paddingPerpendicular),
246
247             isStart = me.pack == 'start',
248             isCenter = me.pack == 'center',
249             isEnd = me.pack == 'end',
250
251             constrain = Ext.Number.constrain,
252             visibleCount = visibleItems.length,
253             nonFlexSize = 0,
254             totalFlex = 0,
255             desiredSize = 0,
256             minimumSize = 0,
257             maxSize = 0,
258             boxes = [],
259             minSizes = [],
260             calculatedWidth,
261
262             i, child, childParallel, childPerpendicular, childMargins, childSize, minParallel, tmpObj, shortfall, 
263             tooNarrow, availableSpace, minSize, item, length, itemIndex, box, oldSize, newSize, reduction, diff, 
264             flexedBoxes, remainingSpace, remainingFlex, flexedSize, parallelMargins, calcs, offset, 
265             perpendicularMargins, stretchSize;
266
267         //gather the total flex of all flexed items and the width taken up by fixed width items
268         for (i = 0; i &lt; visibleCount; i++) {
269             child = visibleItems[i];
270             childPerpendicular = child[perpendicularPrefix];
271             me.layoutItem(child);
272             childMargins = child.margins;
273             parallelMargins = childMargins[me.parallelBefore] + childMargins[me.parallelAfter];
274
275             // Create the box description object for this child item.
276             tmpObj = {
277                 component: child,
278                 margins: childMargins
279             };
280
281             // flex and not 'auto' width
282             if (child.flex) {
283                 totalFlex += child.flex;
284                 childParallel = undefinedValue;
285             }
286             // Not flexed or 'auto' width or undefined width
287             else {
288                 if (!(child[parallelPrefix] &amp;&amp; childPerpendicular)) {
289                     childSize = child.getSize();
290                 }
291                 childParallel = child[parallelPrefix] || childSize[parallelPrefix];
292                 childPerpendicular = childPerpendicular || childSize[perpendicularPrefix];
293             }
294
295             nonFlexSize += parallelMargins + (childParallel || 0);
296             desiredSize += parallelMargins + (child.flex ? child[parallelMinString] || 0 : childParallel);
297             minimumSize += parallelMargins + (child[parallelMinString] || childParallel || 0);
298
299             // Max height for align - force layout of non-laid out subcontainers without a numeric height
300             if (typeof childPerpendicular != 'number') {
301                 // Clear any static sizing and revert to flow so we can get a proper measurement
302                 // child['set' + perpendicularPrefixCap](null);
303                 childPerpendicular = child['get' + perpendicularPrefixCap]();
304             }
305
306             // Track the maximum perpendicular size for use by the stretch and stretchmax align config values.
307             maxSize = mmax(maxSize, childPerpendicular + childMargins[me.perpendicularLeftTop] + childMargins[me.perpendicularRightBottom]);
308
309             tmpObj[parallelPrefix] = childParallel || undefinedValue;
310             tmpObj[perpendicularPrefix] = childPerpendicular || undefinedValue;
311             boxes.push(tmpObj);
312         }
313         shortfall = desiredSize - parallelSize;
314         tooNarrow = minimumSize &gt; parallelSize;
315
316         //the space available to the flexed items
317         availableSpace = mmax(0, parallelSize - nonFlexSize - paddingParallel - (me.reserveOffset ? me.availableSpaceOffset : 0));
318
319         if (tooNarrow) {
320             for (i = 0; i &lt; visibleCount; i++) {
321                 box = boxes[i];
322                 minSize = visibleItems[i][parallelMinString] || visibleItems[i][parallelPrefix] || box[parallelPrefix];
323                 box.dirtySize = box.dirtySize || box[parallelPrefix] != minSize;
324                 box[parallelPrefix] = minSize;
325             }
326         }
327         else {
328             //all flexed items should be sized to their minimum size, other items should be shrunk down until
329             //the shortfall has been accounted for
330             if (shortfall &gt; 0) {
331                 /*
332                  * When we have a shortfall but are not tooNarrow, we need to shrink the width of each non-flexed item.
333                  * Flexed items are immediately reduced to their minWidth and anything already at minWidth is ignored.
334                  * The remaining items are collected into the minWidths array, which is later used to distribute the shortfall.
335                  */
336                 for (i = 0; i &lt; visibleCount; i++) {
337                     item = visibleItems[i];
338                     minSize = item[parallelMinString] || 0;
339
340                     //shrink each non-flex tab by an equal amount to make them all fit. Flexed items are all
341                     //shrunk to their minSize because they're flexible and should be the first to lose size
342                     if (item.flex) {
343                         box = boxes[i];
344                         box.dirtySize = box.dirtySize || box[parallelPrefix] != minSize;
345                         box[parallelPrefix] = minSize;
346                     }
347                     else {
348                         minSizes.push({
349                             minSize: minSize,
350                             available: boxes[i][parallelPrefix] - minSize,
351                             index: i
352                         });
353                     }
354                 }
355
356                 //sort by descending amount of width remaining before minWidth is reached
357                 Ext.Array.sort(minSizes, me.minSizeSortFn);
358
359                 /*
360                  * Distribute the shortfall (difference between total desired size of all items and actual size available)
361                  * between the non-flexed items. We try to distribute the shortfall evenly, but apply it to items with the
362                  * smallest difference between their size and minSize first, so that if reducing the size by the average
363                  * amount would make that item less than its minSize, we carry the remainder over to the next item.
364                  */
365                 for (i = 0, length = minSizes.length; i &lt; length; i++) {
366                     itemIndex = minSizes[i].index;
367
368                     if (itemIndex == undefinedValue) {
369                         continue;
370                     }
371                     item = visibleItems[itemIndex];
372                     minSize = minSizes[i].minSize;
373
374                     box = boxes[itemIndex];
375                     oldSize = box[parallelPrefix];
376                     newSize = mmax(minSize, oldSize - math.ceil(shortfall / (length - i)));
377                     reduction = oldSize - newSize;
378
379                     box.dirtySize = box.dirtySize || box[parallelPrefix] != newSize;
380                     box[parallelPrefix] = newSize;
381                     shortfall -= reduction;
382                 }
383             }
384             else {
385                 remainingSpace = availableSpace;
386                 remainingFlex = totalFlex;
387                 flexedBoxes = [];
388
389                 // Create an array containing *just the flexed boxes* for allocation of remainingSpace
390                 for (i = 0; i &lt; visibleCount; i++) {
391                     child = visibleItems[i];
392                     if (isStart &amp;&amp; child.flex) {
393                         flexedBoxes.push(boxes[Ext.Array.indexOf(visibleItems, child)]);
394                     }
395                 }
396                 // The flexed boxes need to be sorted in ascending order of maxSize to work properly
397                 // so that unallocated space caused by maxWidth being less than flexed width
398                 // can be reallocated to subsequent flexed boxes.
399                 Ext.Array.sort(flexedBoxes, me.flexSortFn);
400
401                 // Calculate the size of each flexed item, and attempt to set it.
402                 for (i = 0; i &lt; flexedBoxes.length; i++) {
403                     calcs = flexedBoxes[i];
404                     child = calcs.component;
405                     childMargins = calcs.margins;
406
407                     flexedSize = math.ceil((child.flex / remainingFlex) * remainingSpace);
408
409                     // Implement maxSize and minSize check
410                     flexedSize = Math.max(child['min' + parallelPrefixCap] || 0, math.min(child['max' + parallelPrefixCap] || infiniteValue, flexedSize));
411
412                     // Remaining space has already had all parallel margins subtracted from it, so just subtract consumed size
413                     remainingSpace -= flexedSize;
414                     remainingFlex -= child.flex;
415
416                     calcs.dirtySize = calcs.dirtySize || calcs[parallelPrefix] != flexedSize;
417                     calcs[parallelPrefix] = flexedSize;
418                 }
419             }
420         }
421
422         if (isCenter) {
423             parallelOffset += availableSpace / 2;
424         }
425         else if (isEnd) {
426             parallelOffset += availableSpace;
427         }
428
429         // Fix for left and right docked Components in a dock component layout. This is for docked Headers and docked Toolbars.
430         // Older Microsoft browsers do not size a position:absolute element's width to match its content.
431         // So in this case, in the updateInnerCtSize method we may need to adjust the size of the owning Container's element explicitly based upon
432         // the discovered max width. So here we put a calculatedWidth property in the metadata to facilitate this.
433         if (me.owner.dock &amp;&amp; (Ext.isIE6 || Ext.isIE7 || Ext.isIEQuirks) &amp;&amp; !me.owner.width &amp;&amp; me.direction == 'vertical') {
434
435             calculatedWidth = maxSize + me.owner.el.getPadding('lr') + me.owner.el.getBorderWidth('lr');
436             if (me.owner.frameSize) {
437                 calculatedWidth += me.owner.frameSize.left + me.owner.frameSize.right;
438             }
439             // If the owning element is not sized, calculate the available width to center or stretch in based upon maxSize
440             availPerpendicularSize = Math.min(availPerpendicularSize, targetSize.width = maxSize + padding.left + padding.right);
441         }
442
443         //finally, calculate the left and top position of each item
444         for (i = 0; i &lt; visibleCount; i++) {
445             child = visibleItems[i];
446             calcs = boxes[i];
447
448             childMargins = calcs.margins;
449
450             perpendicularMargins = childMargins[me.perpendicularLeftTop] + childMargins[me.perpendicularRightBottom];
451
452             // Advance past the &quot;before&quot; margin
453             parallelOffset += childMargins[me.parallelBefore];
454
455             calcs[me.parallelBefore] = parallelOffset;
456             calcs[me.perpendicularLeftTop] = perpendicularOffset + childMargins[me.perpendicularLeftTop];
457
458             if (me.align == 'stretch') {
459                 stretchSize = constrain(availPerpendicularSize - perpendicularMargins, child[perpendicularMinString] || 0, child[perpendicularMaxString] || infiniteValue);
460                 calcs.dirtySize = calcs.dirtySize || calcs[perpendicularPrefix] != stretchSize;
461                 calcs[perpendicularPrefix] = stretchSize;
462             }
463             else if (me.align == 'stretchmax') {
464                 stretchSize = constrain(maxSize - perpendicularMargins, child[perpendicularMinString] || 0, child[perpendicularMaxString] || infiniteValue);
465                 calcs.dirtySize = calcs.dirtySize || calcs[perpendicularPrefix] != stretchSize;
466                 calcs[perpendicularPrefix] = stretchSize;
467             }
468             else if (me.align == me.alignCenteringString) {
469                 // When calculating a centered position within the content box of the innerCt, the width of the borders must be subtracted from
470                 // the size to yield the space available to center within.
471                 // The updateInnerCtSize method explicitly adds the border widths to the set size of the innerCt.
472                 diff = mmax(availPerpendicularSize, maxSize) - me.innerCt.getBorderWidth(me.perpendicularLT + me.perpendicularRB) - calcs[perpendicularPrefix];
473                 if (diff &gt; 0) {
474                     calcs[me.perpendicularLeftTop] = perpendicularOffset + Math.round(diff / 2);
475                 }
476             }
477
478             // Advance past the box size and the &quot;after&quot; margin
479             parallelOffset += (calcs[parallelPrefix] || 0) + childMargins[me.parallelAfter];
480         }
481
482         return {
483             boxes: boxes,
484             meta : {
485                 calculatedWidth: calculatedWidth,
486                 maxSize: maxSize,
487                 nonFlexSize: nonFlexSize,
488                 desiredSize: desiredSize,
489                 minimumSize: minimumSize,
490                 shortfall: shortfall,
491                 tooNarrow: tooNarrow
492             }
493         };
494     },
495     
496     onRemove: function(comp){
497         this.callParent(arguments);
498         if (this.overflowHandler) {
499             this.overflowHandler.onRemove(comp);
500         }
501     },
502
503 <span id='Ext-layout-container-Box-method-initOverflowHandler'>    /**
504 </span>     * @private
505      */
506     initOverflowHandler: function() {
507         var handler = this.overflowHandler;
508
509         if (typeof handler == 'string') {
510             handler = {
511                 type: handler
512             };
513         }
514
515         var handlerType = 'None';
516         if (handler &amp;&amp; handler.type !== undefined) {
517             handlerType = handler.type;
518         }
519
520         var constructor = Ext.layout.container.boxOverflow[handlerType];
521         if (constructor[this.type]) {
522             constructor = constructor[this.type];
523         }
524
525         this.overflowHandler = Ext.create('Ext.layout.container.boxOverflow.' + handlerType, this, handler);
526     },
527
528 <span id='Ext-layout-container-Box-method-onLayout'>    /**
529 </span>     * @private
530      * Runs the child box calculations and caches them in childBoxCache. Subclasses can used these cached values
531      * when laying out
532      */
533     onLayout: function() {
534         this.callParent();
535         // Clear the innerCt size so it doesn't influence the child items.
536         if (this.clearInnerCtOnLayout === true &amp;&amp; this.adjustmentPass !== true) {
537             this.innerCt.setSize(null, null);
538         }
539
540         var me = this,
541             targetSize = me.getLayoutTargetSize(),
542             items = me.getVisibleItems(),
543             calcs = me.calculateChildBoxes(items, targetSize),
544             boxes = calcs.boxes,
545             meta = calcs.meta,
546             handler, method, results;
547
548         if (me.autoSize &amp;&amp; calcs.meta.desiredSize) {
549             targetSize[me.parallelPrefix] = calcs.meta.desiredSize;
550         }
551
552         //invoke the overflow handler, if one is configured
553         if (meta.shortfall &gt; 0) {
554             handler = me.overflowHandler;
555             method = meta.tooNarrow ? 'handleOverflow': 'clearOverflow';
556
557             results = handler[method](calcs, targetSize);
558
559             if (results) {
560                 if (results.targetSize) {
561                     targetSize = results.targetSize;
562                 }
563
564                 if (results.recalculate) {
565                     items = me.getVisibleItems(owner);
566                     calcs = me.calculateChildBoxes(items, targetSize);
567                     boxes = calcs.boxes;
568                 }
569             }
570         } else {
571             me.overflowHandler.clearOverflow();
572         }
573
574 <span id='Ext-layout-container-Box-property-layoutTargetLastSize'>        /**
575 </span>         * @private
576          * @property layoutTargetLastSize
577          * @type Object
578          * Private cache of the last measured size of the layout target. This should never be used except by
579          * BoxLayout subclasses during their onLayout run.
580          */
581         me.layoutTargetLastSize = targetSize;
582
583 <span id='Ext-layout-container-Box-property-childBoxCache'>        /**
584 </span>         * @private
585          * @property childBoxCache
586          * @type Array
587          * Array of the last calculated height, width, top and left positions of each visible rendered component
588          * within the Box layout.
589          */
590         me.childBoxCache = calcs;
591
592         me.updateInnerCtSize(targetSize, calcs);
593         me.updateChildBoxes(boxes);
594         me.handleTargetOverflow(targetSize);
595     },
596
597 <span id='Ext-layout-container-Box-method-updateChildBoxes'>    /**
598 </span>     * Resizes and repositions each child component
599      * @param {Array} boxes The box measurements
600      */
601     updateChildBoxes: function(boxes) {
602         var me = this,
603             i = 0,
604             length = boxes.length,
605             animQueue = [],
606             dd = Ext.dd.DDM.getDDById(me.innerCt.id), // Any DD active on this layout's element (The BoxReorderer plugin does this.)
607             oldBox, newBox, changed, comp, boxAnim, animCallback;
608
609         for (; i &lt; length; i++) {
610             newBox = boxes[i];
611             comp = newBox.component;
612
613             // If a Component is being drag/dropped, skip positioning it.
614             // Accomodate the BoxReorderer plugin: Its current dragEl must not be positioned by the layout
615             if (dd &amp;&amp; (dd.getDragEl() === comp.el.dom)) {
616                 continue;
617             }
618
619             changed = false;
620
621             oldBox = me.getChildBox(comp);
622
623             // If we are animating, we build up an array of Anim config objects, one for each
624             // child Component which has any changed box properties. Those with unchanged
625             // properties are not animated.
626             if (me.animate) {
627                 // Animate may be a config object containing callback.
628                 animCallback = me.animate.callback || me.animate;
629                 boxAnim = {
630                     layoutAnimation: true,  // Component Target handler must use set*Calculated*Size
631                     target: comp,
632                     from: {},
633                     to: {},
634                     listeners: {}
635                 };
636                 // Only set from and to properties when there's a change.
637                 // Perform as few Component setter methods as possible.
638                 // Temporarily set the property values that we are not animating
639                 // so that doComponentLayout does not auto-size them.
640                 if (!isNaN(newBox.width) &amp;&amp; (newBox.width != oldBox.width)) {
641                     changed = true;
642                     // boxAnim.from.width = oldBox.width;
643                     boxAnim.to.width = newBox.width;
644                 }
645                 if (!isNaN(newBox.height) &amp;&amp; (newBox.height != oldBox.height)) {
646                     changed = true;
647                     // boxAnim.from.height = oldBox.height;
648                     boxAnim.to.height = newBox.height;
649                 }
650                 if (!isNaN(newBox.left) &amp;&amp; (newBox.left != oldBox.left)) {
651                     changed = true;
652                     // boxAnim.from.left = oldBox.left;
653                     boxAnim.to.left = newBox.left;
654                 }
655                 if (!isNaN(newBox.top) &amp;&amp; (newBox.top != oldBox.top)) {
656                     changed = true;
657                     // boxAnim.from.top = oldBox.top;
658                     boxAnim.to.top = newBox.top;
659                 }
660                 if (changed) {
661                     animQueue.push(boxAnim);
662                 }
663             } else {
664                 if (newBox.dirtySize) {
665                     if (newBox.width !== oldBox.width || newBox.height !== oldBox.height) {
666                         me.setItemSize(comp, newBox.width, newBox.height);
667                     }
668                 }
669                 // Don't set positions to NaN
670                 if (isNaN(newBox.left) || isNaN(newBox.top)) {
671                     continue;
672                 }
673                 comp.setPosition(newBox.left, newBox.top);
674             }
675         }
676
677         // Kick off any queued animations
678         length = animQueue.length;
679         if (length) {
680
681             // A function which cleans up when a Component's animation is done.
682             // The last one to finish calls the callback.
683             var afterAnimate = function(anim) {
684                 // When we've animated all changed boxes into position, clear our busy flag and call the callback.
685                 length -= 1;
686                 if (!length) {
687                     me.layoutBusy = false;
688                     if (Ext.isFunction(animCallback)) {
689                         animCallback();
690                     }
691                 }
692             };
693
694             var beforeAnimate = function() {
695                 me.layoutBusy = true;
696             };
697
698             // Start each box animation off
699             for (i = 0, length = animQueue.length; i &lt; length; i++) {
700                 boxAnim = animQueue[i];
701
702                 // Clean up the Component after. Clean up the *layout* after the last animation finishes
703                 boxAnim.listeners.afteranimate = afterAnimate;
704
705                 // The layout is busy during animation, and may not be called, so set the flag when the first animation begins
706                 if (!i) {
707                     boxAnim.listeners.beforeanimate = beforeAnimate;
708                 }
709                 if (me.animate.duration) {
710                     boxAnim.duration = me.animate.duration;
711                 }
712                 comp = boxAnim.target;
713                 delete boxAnim.target;
714                 // Stop any currently running animation
715                 comp.stopAnimation();
716                 comp.animate(boxAnim);
717             }
718         }
719     },
720
721 <span id='Ext-layout-container-Box-method-updateInnerCtSize'>    /**
722 </span>     * @private
723      * Called by onRender just before the child components are sized and positioned. This resizes the innerCt
724      * to make sure all child items fit within it. We call this before sizing the children because if our child
725      * items are larger than the previous innerCt size the browser will insert scrollbars and then remove them
726      * again immediately afterwards, giving a performance hit.
727      * Subclasses should provide an implementation.
728      * @param {Object} currentSize The current height and width of the innerCt
729      * @param {Array} calculations The new box calculations of all items to be laid out
730      */
731     updateInnerCtSize: function(tSize, calcs) {
732         var me = this,
733             mmax = Math.max,
734             align = me.align,
735             padding = me.padding,
736             width = tSize.width,
737             height = tSize.height,
738             meta = calcs.meta,
739             innerCtWidth,
740             innerCtHeight;
741
742         if (me.direction == 'horizontal') {
743             innerCtWidth = width;
744             innerCtHeight = meta.maxSize + padding.top + padding.bottom + me.innerCt.getBorderWidth('tb');
745
746             if (align == 'stretch') {
747                 innerCtHeight = height;
748             }
749             else if (align == 'middle') {
750                 innerCtHeight = mmax(height, innerCtHeight);
751             }
752         } else {
753             innerCtHeight = height;
754             innerCtWidth = meta.maxSize + padding.left + padding.right + me.innerCt.getBorderWidth('lr');
755
756             if (align == 'stretch') {
757                 innerCtWidth = width;
758             }
759             else if (align == 'center') {
760                 innerCtWidth = mmax(width, innerCtWidth);
761             }
762         }
763         me.getRenderTarget().setSize(innerCtWidth || undefined, innerCtHeight || undefined);
764
765         // If a calculated width has been found (and this only happens for auto-width vertical docked Components in old Microsoft browsers)
766         // then, if the Component has not assumed the size of its content, set it to do so.
767         if (meta.calculatedWidth &amp;&amp; me.owner.el.getWidth() &gt; meta.calculatedWidth) {
768             me.owner.el.setWidth(meta.calculatedWidth);
769         }
770
771         if (me.innerCt.dom.scrollTop) {
772             me.innerCt.dom.scrollTop = 0;
773         }
774     },
775
776 <span id='Ext-layout-container-Box-method-handleTargetOverflow'>    /**
777 </span>     * @private
778      * This should be called after onLayout of any BoxLayout subclass. If the target's overflow is not set to 'hidden',
779      * we need to lay out a second time because the scrollbars may have modified the height and width of the layout
780      * target. Having a Box layout inside such a target is therefore not recommended.
781      * @param {Object} previousTargetSize The size and height of the layout target before we just laid out
782      * @param {Ext.container.Container} container The container
783      * @param {Ext.core.Element} target The target element
784      * @return True if the layout overflowed, and was reflowed in a secondary onLayout call.
785      */
786     handleTargetOverflow: function(previousTargetSize) {
787         var target = this.getTarget(),
788             overflow = target.getStyle('overflow'),
789             newTargetSize;
790
791         if (overflow &amp;&amp; overflow != 'hidden' &amp;&amp; !this.adjustmentPass) {
792             newTargetSize = this.getLayoutTargetSize();
793             if (newTargetSize.width != previousTargetSize.width || newTargetSize.height != previousTargetSize.height) {
794                 this.adjustmentPass = true;
795                 this.onLayout();
796                 return true;
797             }
798         }
799
800         delete this.adjustmentPass;
801     },
802
803     // private
804     isValidParent : function(item, target, position) {
805         // Note: Box layouts do not care about order within the innerCt element because it's an absolutely positioning layout
806         // We only care whether the item is a direct child of the innerCt element.
807         var itemEl = item.el ? item.el.dom : Ext.getDom(item);
808         return (itemEl &amp;&amp; this.innerCt &amp;&amp; itemEl.parentNode === this.innerCt.dom) || false;
809     },
810
811     // Overridden method from AbstractContainer.
812     // Used in the base AbstractLayout.beforeLayout method to render all items into.
813     getRenderTarget: function() {
814         if (!this.innerCt) {
815             // the innerCt prevents wrapping and shuffling while the container is resizing
816             this.innerCt = this.getTarget().createChild({
817                 cls: this.innerCls,
818                 role: 'presentation'
819             });
820             this.padding = Ext.util.Format.parseBox(this.padding);
821         }
822         return this.innerCt;
823     },
824
825     // private
826     renderItem: function(item, target) {
827         this.callParent(arguments);
828         var me = this,
829             itemEl = item.getEl(),
830             style = itemEl.dom.style,
831             margins = item.margins || item.margin;
832
833         // Parse the item's margin/margins specification
834         if (margins) {
835             if (Ext.isString(margins) || Ext.isNumber(margins)) {
836                 margins = Ext.util.Format.parseBox(margins);
837             } else {
838                 Ext.applyIf(margins, {top: 0, right: 0, bottom: 0, left: 0});
839             }
840         } else {
841             margins = Ext.apply({}, me.defaultMargins);
842         }
843
844         // Add any before/after CSS margins to the configured margins, and zero the CSS margins
845         margins.top    += itemEl.getMargin('t');
846         margins.right  += itemEl.getMargin('r');
847         margins.bottom += itemEl.getMargin('b');
848         margins.left   += itemEl.getMargin('l');
849         style.marginTop = style.marginRight = style.marginBottom = style.marginLeft = '0';
850
851         // Item must reference calculated margins.
852         item.margins = margins;
853     },
854
855 <span id='Ext-layout-container-Box-method-destroy'>    /**
856 </span>     * @private
857      */
858     destroy: function() {
859         Ext.destroy(this.overflowHandler);
860         this.callParent(arguments);
861     }
862 });</pre>
863 </body>
864 </html>