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