--- /dev/null
+<!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-layout.container.Box'>/**
+</span> * @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 */
+
+<span id='Ext-layout.container.Box-cfg-animate'> /**
+</span> * @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>
+ */
+
+<span id='Ext-layout.container.Box-cfg-defaultMargins'> /**
+</span> * @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
+ },
+
+<span id='Ext-layout.container.Box-cfg-padding'> /**
+</span> * @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',
+
+<span id='Ext-layout.container.Box-cfg-pack'> /**
+</span> * @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>
+ */
+<span id='Ext-layout.container.Box-cfg-flex'> /**
+</span> * @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,
+
+<span id='Ext-layout.container.Box-cfg-clearInnerCtOnLayout'> /**
+</span> * @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();
+ },
+
+<span id='Ext-layout.container.Box-method-getChildBox'> /**
+</span> * @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()
+ };
+ },
+
+<span id='Ext-layout.container.Box-method-calculateChildBox'> /**
+</span> * @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];
+ }
+ }
+ },
+
+<span id='Ext-layout.container.Box-method-calculateChildBoxes'> /**
+</span> * @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
+ }
+ };
+ },
+
+<span id='Ext-layout.container.Box-method-initOverflowHandler'> /**
+</span> * @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);
+ },
+
+<span id='Ext-layout.container.Box-method-onLayout'> /**
+</span> * @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();
+ }
+
+<span id='Ext-layout.container.Box-property-layoutTargetLastSize'> /**
+</span> * @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;
+
+<span id='Ext-layout.container.Box-property-childBoxCache'> /**
+</span> * @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);
+ },
+
+<span id='Ext-layout.container.Box-method-updateChildBoxes'> /**
+</span> * 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);
+ }
+ }
+ },
+
+<span id='Ext-layout.container.Box-method-updateInnerCtSize'> /**
+</span> * @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;
+ }
+ },
+
+<span id='Ext-layout.container.Box-method-handleTargetOverflow'> /**
+</span> * @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;
+ },
+
+<span id='Ext-layout.container.Box-method-destroy'> /**
+</span> * @private
+ */
+ destroy: function() {
+ Ext.destroy(this.overflowHandler);
+ this.callParent(arguments);
+ }
+});</pre></pre></body></html>
\ No newline at end of file