3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @class Ext.layout.container.Box
17 * @extends Ext.layout.container.Container
18 * <p>Base Class for HBoxLayout and VBoxLayout Classes. Generally it should not need to be used directly.</p>
21 Ext.define('Ext.layout.container.Box', {
23 /* Begin Definitions */
25 alias: ['layout.box'],
26 extend: 'Ext.layout.container.Container',
27 alternateClassName: 'Ext.layout.BoxLayout',
30 'Ext.layout.container.boxOverflow.None',
31 'Ext.layout.container.boxOverflow.Menu',
32 'Ext.layout.container.boxOverflow.Scroller',
34 'Ext.dd.DragDropManager'
40 * @cfg {Mixed} animate
41 * <p>If truthy, child Component are <i>animated</i> into position whenever the Container
42 * is layed out. If this option is numeric, it is used as the animation duration in milliseconds.</p>
43 * <p>May be set as a property at any time.</p>
47 * @cfg {Object} defaultMargins
48 * <p>If the individual contained items do not have a <tt>margins</tt>
49 * property specified or margin specified via CSS, the default margins from this property will be
50 * applied to each item.</p>
51 * <br><p>This property may be specified as an object containing margins
52 * to apply in the format:</p><pre><code>
55 right: (right margin),
56 bottom: (bottom margin),
59 * <p>This property may also be specified as a string containing
60 * space-separated, numeric margin values. The order of the sides associated
61 * with each value matches the way CSS processes margin values:</p>
62 * <div class="mdetail-params"><ul>
63 * <li>If there is only one value, it applies to all sides.</li>
64 * <li>If there are two values, the top and bottom borders are set to the
65 * first value and the right and left are set to the second.</li>
66 * <li>If there are three values, the top is set to the first value, the left
67 * and right are set to the second, and the bottom is set to the third.</li>
68 * <li>If there are four values, they apply to the top, right, bottom, and
69 * left, respectively.</li>
71 * <p>Defaults to:</p><pre><code>
72 * {top:0, right:0, bottom:0, left:0}
83 * @cfg {String} padding
84 * <p>Sets the padding to be applied to all child items managed by this layout.</p>
85 * <p>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:</p>
88 * <div class="mdetail-params"><ul>
89 * <li>If there is only one value, it applies to all sides.</li>
90 * <li>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.</li>
92 * <li>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.</li>
94 * <li>If there are four values, they apply to the top, right, bottom, and
95 * left, respectively.</li>
97 * <p>Defaults to: <code>"0"</code></p>
100 // documented in subclasses
105 * Controls how the child items of the container are packed together. Acceptable configuration values
106 * for this property are:
107 * <div class="mdetail-params"><ul>
108 * <li><b><tt>start</tt></b> : <b>Default</b><div class="sub-desc">child items are packed together at
109 * <b>left</b> side of container</div></li>
110 * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are packed together at
111 * <b>mid-width</b> of container</div></li>
112 * <li><b><tt>end</tt></b> : <div class="sub-desc">child items are packed together at <b>right</b>
113 * side of container</div></li>
118 * This configuration option is to be applied to <b>child <tt>items</tt></b> of the container managed
119 * by this layout. Each child item with a <tt>flex</tt> property will be flexed <b>horizontally</b>
120 * according to each item's <b>relative</b> <tt>flex</tt> value compared to the sum of all items with
121 * a <tt>flex</tt> value specified. Any child items that have either a <tt>flex = 0</tt> or
122 * <tt>flex = undefined</tt> will not be 'flexed' (the initial size will not be changed).
127 itemCls: Ext.baseCSSPrefix + 'box-item',
128 targetCls: Ext.baseCSSPrefix + 'box-layout-ct',
129 innerCls: Ext.baseCSSPrefix + 'box-inner',
131 bindToOwnerCtContainer: true,
133 // availableSpaceOffset is used to adjust the availableWidth, typically used
134 // to reserve space for a scrollbar
135 availableSpaceOffset: 0,
137 // whether or not to reserve the availableSpaceOffset in layout calculations
141 * @cfg {Boolean} clearInnerCtOnLayout
143 clearInnerCtOnLayout: false,
145 flexSortFn: function (a, b) {
146 var maxParallelPrefix = 'max' + this.parallelPrefixCap,
147 infiniteValue = Infinity;
148 a = a.component[maxParallelPrefix] || infiniteValue;
149 b = b.component[maxParallelPrefix] || infiniteValue;
150 // IE 6/7 Don't like Infinity - Infinity...
151 if (!isFinite(a) && !isFinite(b)) {
157 // Sort into *descending* order.
158 minSizeSortFn: function(a, b) {
159 return b.available - a.available;
162 constructor: function(config) {
165 me.callParent(arguments);
167 // The sort function needs access to properties in this, so must be bound.
168 me.flexSortFn = Ext.Function.bind(me.flexSortFn, me);
170 me.initOverflowHandler();
175 * Returns the current size and positioning of the passed child item.
176 * @param {Component} child The child Component to calculate the box for
177 * @return {Object} Object containing box measurements for the child. Properties are left,top,width,height.
179 getChildBox: function(child) {
180 child = child.el || this.owner.getComponent(child).el;
181 var size = child.getBox(false, true);
192 * Calculates the size and positioning of the passed child item.
193 * @param {Component} child The child Component to calculate the box for
194 * @return {Object} Object containing box measurements for the child. Properties are left,top,width,height.
196 calculateChildBox: function(child) {
198 boxes = me.calculateChildBoxes(me.getVisibleItems(), me.getLayoutTargetSize()).boxes,
202 child = me.owner.getComponent(child);
203 for (; i < ln; i++) {
204 if (boxes[i].component === child) {
212 * Calculates the size and positioning of each item in the box. This iterates over all of the rendered,
213 * visible items and returns a height, width, top and left for each, as well as a reference to each. Also
214 * returns meta data such as maxSize which are useful when resizing layout wrappers such as this.innerCt.
215 * @param {Array} visibleItems The array of all rendered, visible items to be calculated for
216 * @param {Object} targetSize Object containing target size and height
217 * @return {Object} Object containing box measurements for each child, plus meta data
219 calculateChildBoxes: function(visibleItems, targetSize) {
223 infiniteValue = Infinity,
226 parallelPrefix = me.parallelPrefix,
227 parallelPrefixCap = me.parallelPrefixCap,
228 perpendicularPrefix = me.perpendicularPrefix,
229 perpendicularPrefixCap = me.perpendicularPrefixCap,
230 parallelMinString = 'min' + parallelPrefixCap,
231 perpendicularMinString = 'min' + perpendicularPrefixCap,
232 perpendicularMaxString = 'max' + perpendicularPrefixCap,
234 parallelSize = targetSize[parallelPrefix] - me.scrollOffset,
235 perpendicularSize = targetSize[perpendicularPrefix],
236 padding = me.padding,
237 parallelOffset = padding[me.parallelBefore],
238 paddingParallel = parallelOffset + padding[me.parallelAfter],
239 perpendicularOffset = padding[me.perpendicularLeftTop],
240 paddingPerpendicular = perpendicularOffset + padding[me.perpendicularRightBottom],
241 availPerpendicularSize = mmax(0, perpendicularSize - paddingPerpendicular),
243 innerCtBorderWidth = me.innerCt.getBorderWidth(me.perpendicularLT + me.perpendicularRB),
245 isStart = me.pack == 'start',
246 isCenter = me.pack == 'center',
247 isEnd = me.pack == 'end',
249 constrain = Ext.Number.constrain,
250 visibleCount = visibleItems.length,
260 i, child, childParallel, childPerpendicular, childMargins, childSize, minParallel, tmpObj, shortfall,
261 tooNarrow, availableSpace, minSize, item, length, itemIndex, box, oldSize, newSize, reduction, diff,
262 flexedBoxes, remainingSpace, remainingFlex, flexedSize, parallelMargins, calcs, offset,
263 perpendicularMargins, stretchSize;
265 //gather the total flex of all flexed items and the width taken up by fixed width items
266 for (i = 0; i < visibleCount; i++) {
267 child = visibleItems[i];
268 childPerpendicular = child[perpendicularPrefix];
269 me.layoutItem(child);
270 childMargins = child.margins;
271 parallelMargins = childMargins[me.parallelBefore] + childMargins[me.parallelAfter];
273 // Create the box description object for this child item.
276 margins: childMargins
279 // flex and not 'auto' width
281 totalFlex += child.flex;
282 childParallel = undefinedValue;
284 // Not flexed or 'auto' width or undefined width
286 if (!(child[parallelPrefix] && childPerpendicular)) {
287 childSize = child.getSize();
289 childParallel = child[parallelPrefix] || childSize[parallelPrefix];
290 childPerpendicular = childPerpendicular || childSize[perpendicularPrefix];
293 nonFlexSize += parallelMargins + (childParallel || 0);
294 desiredSize += parallelMargins + (child.flex ? child[parallelMinString] || 0 : childParallel);
295 minimumSize += parallelMargins + (child[parallelMinString] || childParallel || 0);
297 // Max height for align - force layout of non-laid out subcontainers without a numeric height
298 if (typeof childPerpendicular != 'number') {
299 // Clear any static sizing and revert to flow so we can get a proper measurement
300 // child['set' + perpendicularPrefixCap](null);
301 childPerpendicular = child['get' + perpendicularPrefixCap]();
304 // Track the maximum perpendicular size for use by the stretch and stretchmax align config values.
305 maxSize = mmax(maxSize, childPerpendicular + childMargins[me.perpendicularLeftTop] + childMargins[me.perpendicularRightBottom]);
307 tmpObj[parallelPrefix] = childParallel || undefinedValue;
308 tmpObj[perpendicularPrefix] = childPerpendicular || undefinedValue;
311 shortfall = desiredSize - parallelSize;
312 tooNarrow = minimumSize > parallelSize;
314 //the space available to the flexed items
315 availableSpace = mmax(0, parallelSize - nonFlexSize - paddingParallel - (me.reserveOffset ? me.availableSpaceOffset : 0));
318 for (i = 0; i < visibleCount; i++) {
320 minSize = visibleItems[i][parallelMinString] || visibleItems[i][parallelPrefix] || box[parallelPrefix];
321 box.dirtySize = box.dirtySize || box[parallelPrefix] != minSize;
322 box[parallelPrefix] = minSize;
326 //all flexed items should be sized to their minimum size, other items should be shrunk down until
327 //the shortfall has been accounted for
330 * When we have a shortfall but are not tooNarrow, we need to shrink the width of each non-flexed item.
331 * Flexed items are immediately reduced to their minWidth and anything already at minWidth is ignored.
332 * The remaining items are collected into the minWidths array, which is later used to distribute the shortfall.
334 for (i = 0; i < visibleCount; i++) {
335 item = visibleItems[i];
336 minSize = item[parallelMinString] || 0;
338 //shrink each non-flex tab by an equal amount to make them all fit. Flexed items are all
339 //shrunk to their minSize because they're flexible and should be the first to lose size
342 box.dirtySize = box.dirtySize || box[parallelPrefix] != minSize;
343 box[parallelPrefix] = minSize;
348 available: boxes[i][parallelPrefix] - minSize,
354 //sort by descending amount of width remaining before minWidth is reached
355 Ext.Array.sort(minSizes, me.minSizeSortFn);
358 * Distribute the shortfall (difference between total desired size of all items and actual size available)
359 * between the non-flexed items. We try to distribute the shortfall evenly, but apply it to items with the
360 * smallest difference between their size and minSize first, so that if reducing the size by the average
361 * amount would make that item less than its minSize, we carry the remainder over to the next item.
363 for (i = 0, length = minSizes.length; i < length; i++) {
364 itemIndex = minSizes[i].index;
366 if (itemIndex == undefinedValue) {
369 item = visibleItems[itemIndex];
370 minSize = minSizes[i].minSize;
372 box = boxes[itemIndex];
373 oldSize = box[parallelPrefix];
374 newSize = mmax(minSize, oldSize - math.ceil(shortfall / (length - i)));
375 reduction = oldSize - newSize;
377 box.dirtySize = box.dirtySize || box[parallelPrefix] != newSize;
378 box[parallelPrefix] = newSize;
379 shortfall -= reduction;
383 remainingSpace = availableSpace;
384 remainingFlex = totalFlex;
387 // Create an array containing *just the flexed boxes* for allocation of remainingSpace
388 for (i = 0; i < visibleCount; i++) {
389 child = visibleItems[i];
390 if (isStart && child.flex) {
391 flexedBoxes.push(boxes[Ext.Array.indexOf(visibleItems, child)]);
394 // The flexed boxes need to be sorted in ascending order of maxSize to work properly
395 // so that unallocated space caused by maxWidth being less than flexed width
396 // can be reallocated to subsequent flexed boxes.
397 Ext.Array.sort(flexedBoxes, me.flexSortFn);
399 // Calculate the size of each flexed item, and attempt to set it.
400 for (i = 0; i < flexedBoxes.length; i++) {
401 calcs = flexedBoxes[i];
402 child = calcs.component;
403 childMargins = calcs.margins;
405 flexedSize = math.ceil((child.flex / remainingFlex) * remainingSpace);
407 // Implement maxSize and minSize check
408 flexedSize = Math.max(child['min' + parallelPrefixCap] || 0, math.min(child['max' + parallelPrefixCap] || infiniteValue, flexedSize));
410 // Remaining space has already had all parallel margins subtracted from it, so just subtract consumed size
411 remainingSpace -= flexedSize;
412 remainingFlex -= child.flex;
414 calcs.dirtySize = calcs.dirtySize || calcs[parallelPrefix] != flexedSize;
415 calcs[parallelPrefix] = flexedSize;
421 parallelOffset += availableSpace / 2;
424 parallelOffset += availableSpace;
427 // Fix for left and right docked Components in a dock component layout. This is for docked Headers and docked Toolbars.
428 // Older Microsoft browsers do not size a position:absolute element's width to match its content.
429 // So in this case, in the updateInnerCtSize method we may need to adjust the size of the owning Container's element explicitly based upon
430 // the discovered max width. So here we put a calculatedWidth property in the metadata to facilitate this.
431 if (me.owner.dock && (Ext.isIE6 || Ext.isIE7 || Ext.isIEQuirks) && !me.owner.width && me.direction == 'vertical') {
433 calculatedWidth = maxSize + me.owner.el.getPadding('lr') + me.owner.el.getBorderWidth('lr');
434 if (me.owner.frameSize) {
435 calculatedWidth += me.owner.frameSize.left + me.owner.frameSize.right;
437 // If the owning element is not sized, calculate the available width to center or stretch in based upon maxSize
438 availPerpendicularSize = Math.min(availPerpendicularSize, targetSize.width = maxSize + padding.left + padding.right);
441 //finally, calculate the left and top position of each item
442 for (i = 0; i < visibleCount; i++) {
443 child = visibleItems[i];
446 childMargins = calcs.margins;
448 perpendicularMargins = childMargins[me.perpendicularLeftTop] + childMargins[me.perpendicularRightBottom];
450 // Advance past the "before" margin
451 parallelOffset += childMargins[me.parallelBefore];
453 calcs[me.parallelBefore] = parallelOffset;
454 calcs[me.perpendicularLeftTop] = perpendicularOffset + childMargins[me.perpendicularLeftTop];
456 if (me.align == 'stretch') {
457 stretchSize = constrain(availPerpendicularSize - perpendicularMargins, child[perpendicularMinString] || 0, child[perpendicularMaxString] || infiniteValue);
458 calcs.dirtySize = calcs.dirtySize || calcs[perpendicularPrefix] != stretchSize;
459 calcs[perpendicularPrefix] = stretchSize;
461 else if (me.align == 'stretchmax') {
462 stretchSize = constrain(maxSize - perpendicularMargins, child[perpendicularMinString] || 0, child[perpendicularMaxString] || infiniteValue);
463 calcs.dirtySize = calcs.dirtySize || calcs[perpendicularPrefix] != stretchSize;
464 calcs[perpendicularPrefix] = stretchSize;
466 else if (me.align == me.alignCenteringString) {
467 // When calculating a centered position within the content box of the innerCt, the width of the borders must be subtracted from
468 // the size to yield the space available to center within.
469 // The updateInnerCtSize method explicitly adds the border widths to the set size of the innerCt.
470 diff = mmax(availPerpendicularSize, maxSize) - innerCtBorderWidth - calcs[perpendicularPrefix];
472 calcs[me.perpendicularLeftTop] = perpendicularOffset + Math.round(diff / 2);
476 // Advance past the box size and the "after" margin
477 parallelOffset += (calcs[parallelPrefix] || 0) + childMargins[me.parallelAfter];
483 calculatedWidth: calculatedWidth,
485 nonFlexSize: nonFlexSize,
486 desiredSize: desiredSize,
487 minimumSize: minimumSize,
488 shortfall: shortfall,
494 onRemove: function(comp){
495 this.callParent(arguments);
496 if (this.overflowHandler) {
497 this.overflowHandler.onRemove(comp);
504 initOverflowHandler: function() {
505 var handler = this.overflowHandler;
507 if (typeof handler == 'string') {
513 var handlerType = 'None';
514 if (handler && handler.type !== undefined) {
515 handlerType = handler.type;
518 var constructor = Ext.layout.container.boxOverflow[handlerType];
519 if (constructor[this.type]) {
520 constructor = constructor[this.type];
523 this.overflowHandler = Ext.create('Ext.layout.container.boxOverflow.' + handlerType, this, handler);
528 * Runs the child box calculations and caches them in childBoxCache. Subclasses can used these cached values
531 onLayout: function() {
533 // Clear the innerCt size so it doesn't influence the child items.
534 if (this.clearInnerCtOnLayout === true && this.adjustmentPass !== true) {
535 this.innerCt.setSize(null, null);
539 targetSize = me.getLayoutTargetSize(),
540 items = me.getVisibleItems(),
541 calcs = me.calculateChildBoxes(items, targetSize),
544 handler, method, results;
546 if (me.autoSize && calcs.meta.desiredSize) {
547 targetSize[me.parallelPrefix] = calcs.meta.desiredSize;
550 //invoke the overflow handler, if one is configured
551 if (meta.shortfall > 0) {
552 handler = me.overflowHandler;
553 method = meta.tooNarrow ? 'handleOverflow': 'clearOverflow';
555 results = handler[method](calcs, targetSize);
558 if (results.targetSize) {
559 targetSize = results.targetSize;
562 if (results.recalculate) {
563 items = me.getVisibleItems();
564 calcs = me.calculateChildBoxes(items, targetSize);
569 me.overflowHandler.clearOverflow();
574 * @property layoutTargetLastSize
576 * Private cache of the last measured size of the layout target. This should never be used except by
577 * BoxLayout subclasses during their onLayout run.
579 me.layoutTargetLastSize = targetSize;
583 * @property childBoxCache
585 * Array of the last calculated height, width, top and left positions of each visible rendered component
586 * within the Box layout.
588 me.childBoxCache = calcs;
590 me.updateInnerCtSize(targetSize, calcs);
591 me.updateChildBoxes(boxes);
592 me.handleTargetOverflow(targetSize);
596 * Resizes and repositions each child component
597 * @param {Array} boxes The box measurements
599 updateChildBoxes: function(boxes) {
602 length = boxes.length,
604 dd = Ext.dd.DDM.getDDById(me.innerCt.id), // Any DD active on this layout's element (The BoxReorderer plugin does this.)
605 oldBox, newBox, changed, comp, boxAnim, animCallback;
607 for (; i < length; i++) {
609 comp = newBox.component;
611 // If a Component is being drag/dropped, skip positioning it.
612 // Accomodate the BoxReorderer plugin: Its current dragEl must not be positioned by the layout
613 if (dd && (dd.getDragEl() === comp.el.dom)) {
619 oldBox = me.getChildBox(comp);
621 // If we are animating, we build up an array of Anim config objects, one for each
622 // child Component which has any changed box properties. Those with unchanged
623 // properties are not animated.
625 // Animate may be a config object containing callback.
626 animCallback = me.animate.callback || me.animate;
628 layoutAnimation: true, // Component Target handler must use set*Calculated*Size
634 // Only set from and to properties when there's a change.
635 // Perform as few Component setter methods as possible.
636 // Temporarily set the property values that we are not animating
637 // so that doComponentLayout does not auto-size them.
638 if (!isNaN(newBox.width) && (newBox.width != oldBox.width)) {
640 // boxAnim.from.width = oldBox.width;
641 boxAnim.to.width = newBox.width;
643 if (!isNaN(newBox.height) && (newBox.height != oldBox.height)) {
645 // boxAnim.from.height = oldBox.height;
646 boxAnim.to.height = newBox.height;
648 if (!isNaN(newBox.left) && (newBox.left != oldBox.left)) {
650 // boxAnim.from.left = oldBox.left;
651 boxAnim.to.left = newBox.left;
653 if (!isNaN(newBox.top) && (newBox.top != oldBox.top)) {
655 // boxAnim.from.top = oldBox.top;
656 boxAnim.to.top = newBox.top;
659 animQueue.push(boxAnim);
662 if (newBox.dirtySize) {
663 if (newBox.width !== oldBox.width || newBox.height !== oldBox.height) {
664 me.setItemSize(comp, newBox.width, newBox.height);
667 // Don't set positions to NaN
668 if (isNaN(newBox.left) || isNaN(newBox.top)) {
671 comp.setPosition(newBox.left, newBox.top);
675 // Kick off any queued animations
676 length = animQueue.length;
679 // A function which cleans up when a Component's animation is done.
680 // The last one to finish calls the callback.
681 var afterAnimate = function(anim) {
682 // When we've animated all changed boxes into position, clear our busy flag and call the callback.
685 me.layoutBusy = false;
686 if (Ext.isFunction(animCallback)) {
692 var beforeAnimate = function() {
693 me.layoutBusy = true;
696 // Start each box animation off
697 for (i = 0, length = animQueue.length; i < length; i++) {
698 boxAnim = animQueue[i];
700 // Clean up the Component after. Clean up the *layout* after the last animation finishes
701 boxAnim.listeners.afteranimate = afterAnimate;
703 // The layout is busy during animation, and may not be called, so set the flag when the first animation begins
705 boxAnim.listeners.beforeanimate = beforeAnimate;
707 if (me.animate.duration) {
708 boxAnim.duration = me.animate.duration;
710 comp = boxAnim.target;
711 delete boxAnim.target;
712 // Stop any currently running animation
713 comp.stopAnimation();
714 comp.animate(boxAnim);
721 * Called by onRender just before the child components are sized and positioned. This resizes the innerCt
722 * to make sure all child items fit within it. We call this before sizing the children because if our child
723 * items are larger than the previous innerCt size the browser will insert scrollbars and then remove them
724 * again immediately afterwards, giving a performance hit.
725 * Subclasses should provide an implementation.
726 * @param {Object} currentSize The current height and width of the innerCt
727 * @param {Array} calculations The new box calculations of all items to be laid out
729 updateInnerCtSize: function(tSize, calcs) {
733 padding = me.padding,
735 height = tSize.height,
740 if (me.direction == 'horizontal') {
741 innerCtWidth = width;
742 innerCtHeight = meta.maxSize + padding.top + padding.bottom + me.innerCt.getBorderWidth('tb');
744 if (align == 'stretch') {
745 innerCtHeight = height;
747 else if (align == 'middle') {
748 innerCtHeight = mmax(height, innerCtHeight);
751 innerCtHeight = height;
752 innerCtWidth = meta.maxSize + padding.left + padding.right + me.innerCt.getBorderWidth('lr');
754 if (align == 'stretch') {
755 innerCtWidth = width;
757 else if (align == 'center') {
758 innerCtWidth = mmax(width, innerCtWidth);
761 me.getRenderTarget().setSize(innerCtWidth || undefined, innerCtHeight || undefined);
763 // If a calculated width has been found (and this only happens for auto-width vertical docked Components in old Microsoft browsers)
764 // then, if the Component has not assumed the size of its content, set it to do so.
765 if (meta.calculatedWidth && me.owner.el.getWidth() > meta.calculatedWidth) {
766 me.owner.el.setWidth(meta.calculatedWidth);
769 if (me.innerCt.dom.scrollTop) {
770 me.innerCt.dom.scrollTop = 0;
776 * This should be called after onLayout of any BoxLayout subclass. If the target's overflow is not set to 'hidden',
777 * we need to lay out a second time because the scrollbars may have modified the height and width of the layout
778 * target. Having a Box layout inside such a target is therefore not recommended.
779 * @param {Object} previousTargetSize The size and height of the layout target before we just laid out
780 * @param {Ext.container.Container} container The container
781 * @param {Ext.core.Element} target The target element
782 * @return True if the layout overflowed, and was reflowed in a secondary onLayout call.
784 handleTargetOverflow: function(previousTargetSize) {
785 var target = this.getTarget(),
786 overflow = target.getStyle('overflow'),
789 if (overflow && overflow != 'hidden' && !this.adjustmentPass) {
790 newTargetSize = this.getLayoutTargetSize();
791 if (newTargetSize.width != previousTargetSize.width || newTargetSize.height != previousTargetSize.height) {
792 this.adjustmentPass = true;
798 delete this.adjustmentPass;
802 isValidParent : function(item, target, position) {
803 // Note: Box layouts do not care about order within the innerCt element because it's an absolutely positioning layout
804 // We only care whether the item is a direct child of the innerCt element.
805 var itemEl = item.el ? item.el.dom : Ext.getDom(item);
806 return (itemEl && this.innerCt && itemEl.parentNode === this.innerCt.dom) || false;
809 // Overridden method from AbstractContainer.
810 // Used in the base AbstractLayout.beforeLayout method to render all items into.
811 getRenderTarget: function() {
813 // the innerCt prevents wrapping and shuffling while the container is resizing
814 this.innerCt = this.getTarget().createChild({
818 this.padding = Ext.util.Format.parseBox(this.padding);
824 renderItem: function(item, target) {
825 this.callParent(arguments);
827 itemEl = item.getEl(),
828 style = itemEl.dom.style,
829 margins = item.margins || item.margin;
831 // Parse the item's margin/margins specification
833 if (Ext.isString(margins) || Ext.isNumber(margins)) {
834 margins = Ext.util.Format.parseBox(margins);
836 Ext.applyIf(margins, {top: 0, right: 0, bottom: 0, left: 0});
839 margins = Ext.apply({}, me.defaultMargins);
842 // Add any before/after CSS margins to the configured margins, and zero the CSS margins
843 margins.top += itemEl.getMargin('t');
844 margins.right += itemEl.getMargin('r');
845 margins.bottom += itemEl.getMargin('b');
846 margins.left += itemEl.getMargin('l');
847 style.marginTop = style.marginRight = style.marginBottom = style.marginLeft = '0';
849 // Item must reference calculated margins.
850 item.margins = margins;
856 destroy: function() {
857 Ext.destroy(this.overflowHandler);
858 this.callParent(arguments);