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