/**
* @class Ext.layout.container.Box
* @extends Ext.layout.container.Container
* <p>Base Class for HBoxLayout and VBoxLayout Classes. Generally it should not need to be used directly.</p>
*/
Ext.define('Ext.layout.container.Box', {
/* Begin Definitions */
alias: ['layout.box'],
extend: 'Ext.layout.container.Container',
alternateClassName: 'Ext.layout.BoxLayout',
requires: [
'Ext.layout.container.boxOverflow.None',
'Ext.layout.container.boxOverflow.Menu',
'Ext.layout.container.boxOverflow.Scroller',
'Ext.util.Format',
'Ext.dd.DragDropManager'
],
/* End Definitions */
/**
* @cfg {Mixed} animate
* <p>If truthy, child Component are <i>animated</i> into position whenever the Container
* is layed out. If this option is numeric, it is used as the animation duration in milliseconds.</p>
* <p>May be set as a property at any time.</p>
*/
/**
* @cfg {Object} defaultMargins
* <p>If the individual contained items do not have a <tt>margins</tt>
* property specified or margin specified via CSS, the default margins from this property will be
* applied to each item.</p>
* <br><p>This property may be specified as an object containing margins
* to apply in the format:</p><pre><code>
{
top: (top margin),
right: (right margin),
bottom: (bottom margin),
left: (left margin)
}</code></pre>
* <p>This property may also be specified as a string containing
* space-separated, numeric margin values. The order of the sides associated
* with each value matches the way CSS processes margin values:</p>
* <div class="mdetail-params"><ul>
* <li>If there is only one value, it applies to all sides.</li>
* <li>If there are two values, the top and bottom borders are set to the
* first value and the right and left are set to the second.</li>
* <li>If there are three values, the top is set to the first value, the left
* and right are set to the second, and the bottom is set to the third.</li>
* <li>If there are four values, they apply to the top, right, bottom, and
* left, respectively.</li>
* </ul></div>
* <p>Defaults to:</p><pre><code>
* {top:0, right:0, bottom:0, left:0}
* </code></pre>
*/
defaultMargins: {
top: 0,
right: 0,
bottom: 0,
left: 0
},
/**
* @cfg {String} padding
* <p>Sets the padding to be applied to all child items managed by this layout.</p>
* <p>This property must be specified as a string containing
* space-separated, numeric padding values. The order of the sides associated
* with each value matches the way CSS processes padding values:</p>
* <div class="mdetail-params"><ul>
* <li>If there is only one value, it applies to all sides.</li>
* <li>If there are two values, the top and bottom borders are set to the
* first value and the right and left are set to the second.</li>
* <li>If there are three values, the top is set to the first value, the left
* and right are set to the second, and the bottom is set to the third.</li>
* <li>If there are four values, they apply to the top, right, bottom, and
* left, respectively.</li>
* </ul></div>
* <p>Defaults to: <code>"0"</code></p>
*/
padding: '0',
// documented in subclasses
pack: 'start',
/**
* @cfg {String} pack
* Controls how the child items of the container are packed together. Acceptable configuration values
* for this property are:
* <div class="mdetail-params"><ul>
* <li><b><tt>start</tt></b> : <b>Default</b><div class="sub-desc">child items are packed together at
* <b>left</b> side of container</div></li>
* <li><b><tt>center</tt></b> : <div class="sub-desc">child items are packed together at
* <b>mid-width</b> of container</div></li>
* <li><b><tt>end</tt></b> : <div class="sub-desc">child items are packed together at <b>right</b>
* side of container</div></li>
* </ul></div>
*/
/**
* @cfg {Number} flex
* This configuration option is to be applied to <b>child <tt>items</tt></b> of the container managed
* by this layout. Each child item with a <tt>flex</tt> property will be flexed <b>horizontally</b>
* according to each item's <b>relative</b> <tt>flex</tt> value compared to the sum of all items with
* a <tt>flex</tt> value specified. Any child items that have either a <tt>flex = 0</tt> or
* <tt>flex = undefined</tt> will not be 'flexed' (the initial size will not be changed).
*/
type: 'box',
scrollOffset: 0,
itemCls: Ext.baseCSSPrefix + 'box-item',
targetCls: Ext.baseCSSPrefix + 'box-layout-ct',
innerCls: Ext.baseCSSPrefix + 'box-inner',
bindToOwnerCtContainer: true,
fixedLayout: false,
// availableSpaceOffset is used to adjust the availableWidth, typically used
// to reserve space for a scrollbar
availableSpaceOffset: 0,
// whether or not to reserve the availableSpaceOffset in layout calculations
reserveOffset: true,
/**
* @cfg {Boolean} clearInnerCtOnLayout
*/
clearInnerCtOnLayout: false,
flexSortFn: function (a, b) {
var maxParallelPrefix = 'max' + this.parallelPrefixCap,
infiniteValue = Infinity;
a = a.component[maxParallelPrefix] || infiniteValue;
b = b.component[maxParallelPrefix] || infiniteValue;
// IE 6/7 Don't like Infinity - Infinity...
if (!isFinite(a) && !isFinite(b)) {
return false;
}
return a - b;
},
// Sort into *descending* order.
minSizeSortFn: function(a, b) {
return b.available - a.available;
},
constructor: function(config) {
var me = this;
me.callParent(arguments);
// The sort function needs access to properties in this, so must be bound.
me.flexSortFn = Ext.Function.bind(me.flexSortFn, me);
me.initOverflowHandler();
},
/**
* @private
* Returns the current size and positioning of the passed child item.
* @param {Component} child The child Component to calculate the box for
* @return {Object} Object containing box measurements for the child. Properties are left,top,width,height.
*/
getChildBox: function(child) {
child = child.el || this.owner.getComponent(child).el;
return {
left: child.getLeft(true),
top: child.getTop(true),
width: child.getWidth(),
height: child.getHeight()
};
},
/**
* @private
* Calculates the size and positioning of the passed child item.
* @param {Component} child The child Component to calculate the box for
* @return {Object} Object containing box measurements for the child. Properties are left,top,width,height.
*/
calculateChildBox: function(child) {
var me = this,
boxes = me.calculateChildBoxes(me.getVisibleItems(), me.getLayoutTargetSize()).boxes,
ln = boxes.length,
i = 0;
child = me.owner.getComponent(child);
for (; i < ln; i++) {
if (boxes[i].component === child) {
return boxes[i];
}
}
},
/**
* @private
* Calculates the size and positioning of each item in the box. This iterates over all of the rendered,
* visible items and returns a height, width, top and left for each, as well as a reference to each. Also
* returns meta data such as maxSize which are useful when resizing layout wrappers such as this.innerCt.
* @param {Array} visibleItems The array of all rendered, visible items to be calculated for
* @param {Object} targetSize Object containing target size and height
* @return {Object} Object containing box measurements for each child, plus meta data
*/
calculateChildBoxes: function(visibleItems, targetSize) {
var me = this,
math = Math,
mmax = math.max,
infiniteValue = Infinity,
undefinedValue,
parallelPrefix = me.parallelPrefix,
parallelPrefixCap = me.parallelPrefixCap,
perpendicularPrefix = me.perpendicularPrefix,
perpendicularPrefixCap = me.perpendicularPrefixCap,
parallelMinString = 'min' + parallelPrefixCap,
perpendicularMinString = 'min' + perpendicularPrefixCap,
perpendicularMaxString = 'max' + perpendicularPrefixCap,
parallelSize = targetSize[parallelPrefix] - me.scrollOffset,
perpendicularSize = targetSize[perpendicularPrefix],
padding = me.padding,
parallelOffset = padding[me.parallelBefore],
paddingParallel = parallelOffset + padding[me.parallelAfter],
perpendicularOffset = padding[me.perpendicularLeftTop],
paddingPerpendicular = perpendicularOffset + padding[me.perpendicularRightBottom],
availPerpendicularSize = mmax(0, perpendicularSize - paddingPerpendicular),
isStart = me.pack == 'start',
isCenter = me.pack == 'center',
isEnd = me.pack == 'end',
constrain = Ext.Number.constrain,
visibleCount = visibleItems.length,
nonFlexSize = 0,
totalFlex = 0,
desiredSize = 0,
minimumSize = 0,
maxSize = 0,
boxes = [],
minSizes = [],
calculatedWidth,
i, child, childParallel, childPerpendicular, childMargins, childSize, minParallel, tmpObj, shortfall,
tooNarrow, availableSpace, minSize, item, length, itemIndex, box, oldSize, newSize, reduction, diff,
flexedBoxes, remainingSpace, remainingFlex, flexedSize, parallelMargins, calcs, offset,
perpendicularMargins, stretchSize;
//gather the total flex of all flexed items and the width taken up by fixed width items
for (i = 0; i < visibleCount; i++) {
child = visibleItems[i];
childPerpendicular = child[perpendicularPrefix];
me.layoutItem(child);
childMargins = child.margins;
parallelMargins = childMargins[me.parallelBefore] + childMargins[me.parallelAfter];
// Create the box description object for this child item.
tmpObj = {
component: child,
margins: childMargins
};
// flex and not 'auto' width
if (child.flex) {
totalFlex += child.flex;
childParallel = undefinedValue;
}
// Not flexed or 'auto' width or undefined width
else {
if (!(child[parallelPrefix] && childPerpendicular)) {
childSize = child.getSize();
}
childParallel = child[parallelPrefix] || childSize[parallelPrefix];
childPerpendicular = childPerpendicular || childSize[perpendicularPrefix];
}
nonFlexSize += parallelMargins + (childParallel || 0);
desiredSize += parallelMargins + (child.flex ? child[parallelMinString] || 0 : childParallel);
minimumSize += parallelMargins + (child[parallelMinString] || childParallel || 0);
// Max height for align - force layout of non-laid out subcontainers without a numeric height
if (typeof childPerpendicular != 'number') {
// Clear any static sizing and revert to flow so we can get a proper measurement
// child['set' + perpendicularPrefixCap](null);
childPerpendicular = child['get' + perpendicularPrefixCap]();
}
// Track the maximum perpendicular size for use by the stretch and stretchmax align config values.
maxSize = mmax(maxSize, childPerpendicular + childMargins[me.perpendicularLeftTop] + childMargins[me.perpendicularRightBottom]);
tmpObj[parallelPrefix] = childParallel || undefinedValue;
tmpObj[perpendicularPrefix] = childPerpendicular || undefinedValue;
boxes.push(tmpObj);
}
shortfall = desiredSize - parallelSize;
tooNarrow = minimumSize > parallelSize;
//the space available to the flexed items
availableSpace = mmax(0, parallelSize - nonFlexSize - paddingParallel - (me.reserveOffset ? me.availableSpaceOffset : 0));
if (tooNarrow) {
for (i = 0; i < visibleCount; i++) {
box = boxes[i];
minSize = visibleItems[i][parallelMinString] || visibleItems[i][parallelPrefix] || box[parallelPrefix];
box.dirtySize = box.dirtySize || box[parallelPrefix] != minSize;
box[parallelPrefix] = minSize;
}
}
else {
//all flexed items should be sized to their minimum size, other items should be shrunk down until
//the shortfall has been accounted for
if (shortfall > 0) {
/*
* When we have a shortfall but are not tooNarrow, we need to shrink the width of each non-flexed item.
* Flexed items are immediately reduced to their minWidth and anything already at minWidth is ignored.
* The remaining items are collected into the minWidths array, which is later used to distribute the shortfall.
*/
for (i = 0; i < visibleCount; i++) {
item = visibleItems[i];
minSize = item[parallelMinString] || 0;
//shrink each non-flex tab by an equal amount to make them all fit. Flexed items are all
//shrunk to their minSize because they're flexible and should be the first to lose size
if (item.flex) {
box = boxes[i];
box.dirtySize = box.dirtySize || box[parallelPrefix] != minSize;
box[parallelPrefix] = minSize;
}
else {
minSizes.push({
minSize: minSize,
available: boxes[i][parallelPrefix] - minSize,
index: i
});
}
}
//sort by descending amount of width remaining before minWidth is reached
Ext.Array.sort(minSizes, me.minSizeSortFn);
/*
* Distribute the shortfall (difference between total desired size of all items and actual size available)
* between the non-flexed items. We try to distribute the shortfall evenly, but apply it to items with the
* smallest difference between their size and minSize first, so that if reducing the size by the average
* amount would make that item less than its minSize, we carry the remainder over to the next item.
*/
for (i = 0, length = minSizes.length; i < length; i++) {
itemIndex = minSizes[i].index;
if (itemIndex == undefinedValue) {
continue;
}
item = visibleItems[itemIndex];
minSize = minSizes[i].minSize;
box = boxes[itemIndex];
oldSize = box[parallelPrefix];
newSize = mmax(minSize, oldSize - math.ceil(shortfall / (length - i)));
reduction = oldSize - newSize;
box.dirtySize = box.dirtySize || box[parallelPrefix] != newSize;
box[parallelPrefix] = newSize;
shortfall -= reduction;
}
}
else {
remainingSpace = availableSpace;
remainingFlex = totalFlex;
flexedBoxes = [];
// Create an array containing *just the flexed boxes* for allocation of remainingSpace
for (i = 0; i < visibleCount; i++) {
child = visibleItems[i];
if (isStart && child.flex) {
flexedBoxes.push(boxes[Ext.Array.indexOf(visibleItems, child)]);
}
}
// The flexed boxes need to be sorted in ascending order of maxSize to work properly
// so that unallocated space caused by maxWidth being less than flexed width
// can be reallocated to subsequent flexed boxes.
Ext.Array.sort(flexedBoxes, me.flexSortFn);
// Calculate the size of each flexed item, and attempt to set it.
for (i = 0; i < flexedBoxes.length; i++) {
calcs = flexedBoxes[i];
child = calcs.component;
childMargins = calcs.margins;
flexedSize = math.ceil((child.flex / remainingFlex) * remainingSpace);
// Implement maxSize and minSize check
flexedSize = Math.max(child['min' + parallelPrefixCap] || 0, math.min(child['max' + parallelPrefixCap] || infiniteValue, flexedSize));
// Remaining space has already had all parallel margins subtracted from it, so just subtract consumed size
remainingSpace -= flexedSize;
remainingFlex -= child.flex;
calcs.dirtySize = calcs.dirtySize || calcs[parallelPrefix] != flexedSize;
calcs[parallelPrefix] = flexedSize;
}
}
}
if (isCenter) {
parallelOffset += availableSpace / 2;
}
else if (isEnd) {
parallelOffset += availableSpace;
}
// Fix for left and right docked Components in a dock component layout. This is for docked Headers and docked Toolbars.
// Older Microsoft browsers do not size a position:absolute element's width to match its content.
// So in this case, in the updateInnerCtSize method we may need to adjust the size of the owning Container's element explicitly based upon
// the discovered max width. So here we put a calculatedWidth property in the metadata to facilitate this.
if (me.owner.dock && (Ext.isIE6 || Ext.isIE7 || Ext.isIEQuirks) && !me.owner.width && me.direction == 'vertical') {
calculatedWidth = maxSize + me.owner.el.getPadding('lr') + me.owner.el.getBorderWidth('lr');
if (me.owner.frameSize) {
calculatedWidth += me.owner.frameSize.left + me.owner.frameSize.right;
}
// If the owning element is not sized, calculate the available width to center or stretch in based upon maxSize
availPerpendicularSize = Math.min(availPerpendicularSize, targetSize.width = maxSize + padding.left + padding.right);
}
//finally, calculate the left and top position of each item
for (i = 0; i < visibleCount; i++) {
child = visibleItems[i];
calcs = boxes[i];
childMargins = calcs.margins;
perpendicularMargins = childMargins[me.perpendicularLeftTop] + childMargins[me.perpendicularRightBottom];
// Advance past the "before" margin
parallelOffset += childMargins[me.parallelBefore];
calcs[me.parallelBefore] = parallelOffset;
calcs[me.perpendicularLeftTop] = perpendicularOffset + childMargins[me.perpendicularLeftTop];
if (me.align == 'stretch') {
stretchSize = constrain(availPerpendicularSize - perpendicularMargins, child[perpendicularMinString] || 0, child[perpendicularMaxString] || infiniteValue);
calcs.dirtySize = calcs.dirtySize || calcs[perpendicularPrefix] != stretchSize;
calcs[perpendicularPrefix] = stretchSize;
}
else if (me.align == 'stretchmax') {
stretchSize = constrain(maxSize - perpendicularMargins, child[perpendicularMinString] || 0, child[perpendicularMaxString] || infiniteValue);
calcs.dirtySize = calcs.dirtySize || calcs[perpendicularPrefix] != stretchSize;
calcs[perpendicularPrefix] = stretchSize;
}
else if (me.align == me.alignCenteringString) {
// When calculating a centered position within the content box of the innerCt, the width of the borders must be subtracted from
// the size to yield the space available to center within.
// The updateInnerCtSize method explicitly adds the border widths to the set size of the innerCt.
diff = mmax(availPerpendicularSize, maxSize) - me.innerCt.getBorderWidth(me.perpendicularLT + me.perpendicularRB) - calcs[perpendicularPrefix];
if (diff > 0) {
calcs[me.perpendicularLeftTop] = perpendicularOffset + Math.round(diff / 2);
}
}
// Advance past the box size and the "after" margin
parallelOffset += (calcs[parallelPrefix] || 0) + childMargins[me.parallelAfter];
}
return {
boxes: boxes,
meta : {
calculatedWidth: calculatedWidth,
maxSize: maxSize,
nonFlexSize: nonFlexSize,
desiredSize: desiredSize,
minimumSize: minimumSize,
shortfall: shortfall,
tooNarrow: tooNarrow
}
};
},
/**
* @private
*/
initOverflowHandler: function() {
var handler = this.overflowHandler;
if (typeof handler == 'string') {
handler = {
type: handler
};
}
var handlerType = 'None';
if (handler && handler.type != undefined) {
handlerType = handler.type;
}
var constructor = Ext.layout.container.boxOverflow[handlerType];
if (constructor[this.type]) {
constructor = constructor[this.type];
}
this.overflowHandler = Ext.create('Ext.layout.container.boxOverflow.' + handlerType, this, handler);
},
/**
* @private
* Runs the child box calculations and caches them in childBoxCache. Subclasses can used these cached values
* when laying out
*/
onLayout: function() {
this.callParent();
// Clear the innerCt size so it doesn't influence the child items.
if (this.clearInnerCtOnLayout === true && this.adjustmentPass !== true) {
this.innerCt.setSize(null, null);
}
var me = this,
targetSize = me.getLayoutTargetSize(),
items = me.getVisibleItems(),
calcs = me.calculateChildBoxes(items, targetSize),
boxes = calcs.boxes,
meta = calcs.meta,
handler, method, results;
if (me.autoSize && calcs.meta.desiredSize) {
targetSize[me.parallelPrefix] = calcs.meta.desiredSize;
}
//invoke the overflow handler, if one is configured
if (meta.shortfall > 0) {
handler = me.overflowHandler;
method = meta.tooNarrow ? 'handleOverflow': 'clearOverflow';
results = handler[method](calcs, targetSize);
if (results) {
if (results.targetSize) {
targetSize = results.targetSize;
}
if (results.recalculate) {
items = me.getVisibleItems(owner);
calcs = me.calculateChildBoxes(items, targetSize);
boxes = calcs.boxes;
}
}
} else {
me.overflowHandler.clearOverflow();
}
/**
* @private
* @property layoutTargetLastSize
* @type Object
* Private cache of the last measured size of the layout target. This should never be used except by
* BoxLayout subclasses during their onLayout run.
*/
me.layoutTargetLastSize = targetSize;
/**
* @private
* @property childBoxCache
* @type Array
* Array of the last calculated height, width, top and left positions of each visible rendered component
* within the Box layout.
*/
me.childBoxCache = calcs;
me.updateInnerCtSize(targetSize, calcs);
me.updateChildBoxes(boxes);
me.handleTargetOverflow(targetSize);
},
/**
* Resizes and repositions each child component
* @param {Array} boxes The box measurements
*/
updateChildBoxes: function(boxes) {
var me = this,
i = 0,
length = boxes.length,
animQueue = [],
dd = Ext.dd.DDM.getDDById(me.innerCt.id), // Any DD active on this layout's element (The BoxReorderer plugin does this.)
oldBox, newBox, changed, comp, boxAnim, animCallback;
for (; i < length; i++) {
newBox = boxes[i];
comp = newBox.component;
// If a Component is being drag/dropped, skip positioning it.
// Accomodate the BoxReorderer plugin: Its current dragEl must not be positioned by the layout
if (dd && (dd.getDragEl() === comp.el.dom)) {
continue;
}
changed = false;
oldBox = me.getChildBox(comp);
// If we are animating, we build up an array of Anim config objects, one for each
// child Component which has any changed box properties. Those with unchanged
// properties are not animated.
if (me.animate) {
// Animate may be a config object containing callback.
animCallback = me.animate.callback || me.animate;
boxAnim = {
layoutAnimation: true, // Component Target handler must use set*Calculated*Size
target: comp,
from: {},
to: {},
listeners: {}
};
// Only set from and to properties when there's a change.
// Perform as few Component setter methods as possible.
// Temporarily set the property values that we are not animating
// so that doComponentLayout does not auto-size them.
if (!isNaN(newBox.width) && (newBox.width != oldBox.width)) {
changed = true;
// boxAnim.from.width = oldBox.width;
boxAnim.to.width = newBox.width;
}
if (!isNaN(newBox.height) && (newBox.height != oldBox.height)) {
changed = true;
// boxAnim.from.height = oldBox.height;
boxAnim.to.height = newBox.height;
}
if (!isNaN(newBox.left) && (newBox.left != oldBox.left)) {
changed = true;
// boxAnim.from.left = oldBox.left;
boxAnim.to.left = newBox.left;
}
if (!isNaN(newBox.top) && (newBox.top != oldBox.top)) {
changed = true;
// boxAnim.from.top = oldBox.top;
boxAnim.to.top = newBox.top;
}
if (changed) {
animQueue.push(boxAnim);
}
} else {
if (newBox.dirtySize) {
if (newBox.width !== oldBox.width || newBox.height !== oldBox.height) {
me.setItemSize(comp, newBox.width, newBox.height);
}
}
// Don't set positions to NaN
if (isNaN(newBox.left) || isNaN(newBox.top)) {
continue;
}
comp.setPosition(newBox.left, newBox.top);
}
}
// Kick off any queued animations
length = animQueue.length;
if (length) {
// A function which cleans up when a Component's animation is done.
// The last one to finish calls the callback.
var afterAnimate = function(anim) {
// When we've animated all changed boxes into position, clear our busy flag and call the callback.
length -= 1;
if (!length) {
me.layoutBusy = false;
if (Ext.isFunction(animCallback)) {
animCallback();
}
}
};
var beforeAnimate = function() {
me.layoutBusy = true;
};
// Start each box animation off
for (i = 0, length = animQueue.length; i < length; i++) {
boxAnim = animQueue[i];
// Clean up the Component after. Clean up the *layout* after the last animation finishes
boxAnim.listeners.afteranimate = afterAnimate;
// The layout is busy during animation, and may not be called, so set the flag when the first animation begins
if (!i) {
boxAnim.listeners.beforeanimate = beforeAnimate;
}
if (me.animate.duration) {
boxAnim.duration = me.animate.duration;
}
comp = boxAnim.target;
delete boxAnim.target;
// Stop any currently running animation
comp.stopAnimation();
comp.animate(boxAnim);
}
}
},
/**
* @private
* Called by onRender just before the child components are sized and positioned. This resizes the innerCt
* to make sure all child items fit within it. We call this before sizing the children because if our child
* items are larger than the previous innerCt size the browser will insert scrollbars and then remove them
* again immediately afterwards, giving a performance hit.
* Subclasses should provide an implementation.
* @param {Object} currentSize The current height and width of the innerCt
* @param {Array} calculations The new box calculations of all items to be laid out
*/
updateInnerCtSize: function(tSize, calcs) {
var me = this,
mmax = Math.max,
align = me.align,
padding = me.padding,
width = tSize.width,
height = tSize.height,
meta = calcs.meta,
innerCtWidth,
innerCtHeight;
if (me.direction == 'horizontal') {
innerCtWidth = width;
innerCtHeight = meta.maxSize + padding.top + padding.bottom + me.innerCt.getBorderWidth('tb');
if (align == 'stretch') {
innerCtHeight = height;
}
else if (align == 'middle') {
innerCtHeight = mmax(height, innerCtHeight);
}
} else {
innerCtHeight = height;
innerCtWidth = meta.maxSize + padding.left + padding.right + me.innerCt.getBorderWidth('lr');
if (align == 'stretch') {
innerCtWidth = width;
}
else if (align == 'center') {
innerCtWidth = mmax(width, innerCtWidth);
}
}
me.getRenderTarget().setSize(innerCtWidth || undefined, innerCtHeight || undefined);
// If a calculated width has been found (and this only happens for auto-width vertical docked Components in old Microsoft browsers)
// then, if the Component has not assumed the size of its content, set it to do so.
if (meta.calculatedWidth && me.owner.el.getWidth() > meta.calculatedWidth) {
me.owner.el.setWidth(meta.calculatedWidth);
}
if (me.innerCt.dom.scrollTop) {
me.innerCt.dom.scrollTop = 0;
}
},
/**
* @private
* This should be called after onLayout of any BoxLayout subclass. If the target's overflow is not set to 'hidden',
* we need to lay out a second time because the scrollbars may have modified the height and width of the layout
* target. Having a Box layout inside such a target is therefore not recommended.
* @param {Object} previousTargetSize The size and height of the layout target before we just laid out
* @param {Ext.container.Container} container The container
* @param {Ext.core.Element} target The target element
* @return True if the layout overflowed, and was reflowed in a secondary onLayout call.
*/
handleTargetOverflow: function(previousTargetSize) {
var target = this.getTarget(),
overflow = target.getStyle('overflow'),
newTargetSize;
if (overflow && overflow != 'hidden' && !this.adjustmentPass) {
newTargetSize = this.getLayoutTargetSize();
if (newTargetSize.width != previousTargetSize.width || newTargetSize.height != previousTargetSize.height) {
this.adjustmentPass = true;
this.onLayout();
return true;
}
}
delete this.adjustmentPass;
},
// private
isValidParent : function(item, target, position) {
// Note: Box layouts do not care about order within the innerCt element because it's an absolutely positioning layout
// We only care whether the item is a direct child of the innerCt element.
var itemEl = item.el ? item.el.dom : Ext.getDom(item);
return (itemEl && this.innerCt && itemEl.parentNode === this.innerCt.dom) || false;
},
// Overridden method from AbstractContainer.
// Used in the base AbstractLayout.beforeLayout method to render all items into.
getRenderTarget: function() {
if (!this.innerCt) {
// the innerCt prevents wrapping and shuffling while the container is resizing
this.innerCt = this.getTarget().createChild({
cls: this.innerCls,
role: 'presentation'
});
this.padding = Ext.util.Format.parseBox(this.padding);
}
return this.innerCt;
},
// private
renderItem: function(item, target) {
this.callParent(arguments);
var me = this,
itemEl = item.getEl(),
style = itemEl.dom.style,
margins = item.margins || item.margin;
// Parse the item's margin/margins specification
if (margins) {
if (Ext.isString(margins) || Ext.isNumber(margins)) {
margins = Ext.util.Format.parseBox(margins);
} else {
Ext.applyIf(margins, {top: 0, right: 0, bottom: 0, left: 0});
}
} else {
margins = Ext.apply({}, me.defaultMargins);
}
// Add any before/after CSS margins to the configured margins, and zero the CSS margins
margins.top += itemEl.getMargin('t');
margins.right += itemEl.getMargin('r');
margins.bottom += itemEl.getMargin('b');
margins.left += itemEl.getMargin('l');
style.marginTop = style.marginRight = style.marginBottom = style.marginLeft = '0';
// Item must reference calculated margins.
item.margins = margins;
},
/**
* @private
*/
destroy: function() {
Ext.destroy(this.overflowHandler);
this.callParent(arguments);
}
});