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