12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106 |
- <!DOCTYPE html>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title>The source code</title>
- <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
- <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
- <style type="text/css">
- .highlight { display: block; background-color: #ddd; }
- </style>
- <script type="text/javascript">
- function highlight() {
- document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
- }
- </script>
- </head>
- <body onload="prettyPrint(); highlight();">
- <pre class="prettyprint lang-js"><span id='Ext-layout-container-Box'>/**
- </span> * Base Class for HBoxLayout and VBoxLayout Classes. Generally it should not need to be used directly.
- */
- 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-defaultMargins'> /**
- </span> * @cfg {Object} defaultMargins
- * If the individual contained items do not have a margins property specified or margin specified via CSS, the
- * default margins from this property will be applied to each item.
- *
- * This property may be specified as an object containing margins to apply in the format:
- *
- * {
- * top: (top margin),
- * right: (right margin),
- * bottom: (bottom margin),
- * left: (left margin)
- * }
- *
- * 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:
- *
- * - If there is only one value, it applies to all sides.
- * - 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.
- * - 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.
- * - If there are four values, they apply to the top, right, bottom, and left, respectively.
- */
- defaultMargins: {
- top: 0,
- right: 0,
- bottom: 0,
- left: 0
- },
- <span id='Ext-layout-container-Box-cfg-padding'> /**
- </span> * @cfg {String} padding
- * Sets the padding to be applied to all child items managed by this layout.
- *
- * 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:
- *
- * - If there is only one value, it applies to all sides.
- * - 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.
- * - 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.
- * - If there are four values, they apply to the top, right, bottom, and left, respectively.
- */
- padding: 0,
- <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:
- *
- * - **start** - child items are packed together at **left** (HBox) or **top** (VBox) side of container (*default**)
- * - **center** - child items are packed together at **mid-width** (HBox) or **mid-height** (VBox) of container
- * - **end** - child items are packed together at **right** (HBox) or **bottom** (VBox) side of container
- */
- pack: 'start',
- <span id='Ext-layout-container-Box-cfg-flex'> /**
- </span> * @cfg {Number} flex
- * This configuration option is to be applied to **child items** of the container managed by this layout. Each child
- * item with a flex property will be flexed (horizontally in `hbox`, vertically in `vbox`) according to each item's
- * **relative** flex value compared to the sum of all items with a flex value specified. Any child items that have
- * either a `flex = 0` or `flex = undefined` will not be 'flexed' (the initial size will not be changed).
- */
- flex: undefined,
- <span id='Ext-layout-container-Box-cfg-stretchMaxPartner'> /**
- </span> * @cfg {String/Ext.Component} stretchMaxPartner
- * Allows stretchMax calculation to take into account the max perpendicular size (height for HBox layout and width
- * for VBox layout) of another Box layout when calculating its maximum perpendicular child size.
- *
- * If specified as a string, this may be either a known Container ID, or a ComponentQuery selector which is rooted
- * at this layout's Container (ie, to find a sibling, use `"^>#siblingItemId`).
- */
- stretchMaxPartner: undefined,
- type: 'box',
- scrollOffset: 0,
- itemCls: Ext.baseCSSPrefix + 'box-item',
- targetCls: Ext.baseCSSPrefix + 'box-layout-ct',
- innerCls: Ext.baseCSSPrefix + 'box-inner',
- // 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,
- manageMargins: true,
- childEls: [
- 'innerCt',
- 'targetEl'
- ],
- renderTpl: [
- '{%var oc,l=values.$comp.layout,oh=l.overflowHandler;',
- 'if (oh.getPrefixConfig!==Ext.emptyFn) {',
- 'if(oc=oh.getPrefixConfig())dh.generateMarkup(oc, out)',
- '}%}',
- '<div id="{ownerId}-innerCt" class="{[l.innerCls]} {[oh.getOverflowCls()]}" role="presentation">',
- '<div id="{ownerId}-targetEl" style="position:absolute;',
- // This width for the "CSS container box" of the box child items gives
- // them the room they need to avoid being "crushed" (aka, "wrapped").
- // On Opera, elements cannot be wider than 32767px or else they break
- // the scrollWidth (it becomes == offsetWidth) and you cannot scroll
- // the content.
- 'width:20000px;',
- // On IE quirks and IE6/7 strict, a text-align:center style trickles
- // down to this el at times and will cause it to move off the left edge.
- // The easy fix is to just always set left:0px here. The top:0px part
- // is just being paranoid. The requirement for targetEl is that its
- // origin align with innerCt... this ensures that it does!
- 'left:0px;top:0px;',
- // If we don't give the element a height, it does not always participate
- // in the scrollWidth.
- 'height:1px">',
- '{%this.renderBody(out, values)%}',
- '</div>',
- '</div>',
- '{%if (oh.getSuffixConfig!==Ext.emptyFn) {',
- 'if(oc=oh.getSuffixConfig())dh.generateMarkup(oc, out)',
- '}%}',
- {
- disableFormats: true,
- definitions: 'var dh=Ext.DomHelper;'
- }
- ],
- constructor: function(config) {
- var me = this,
- type;
- me.callParent(arguments);
- // The sort function needs access to properties in this, so must be bound.
- me.flexSortFn = Ext.Function.bind(me.flexSort, me);
- me.initOverflowHandler();
- type = typeof me.padding;
- if (type == 'string' || type == 'number') {
- me.padding = Ext.util.Format.parseBox(me.padding);
- me.padding.height = me.padding.top + me.padding.bottom;
- me.padding.width = me.padding.left + me.padding.right;
- }
- },
- getNames: function () {
- return this.names;
- },
- // Matches: <spaces>digits[.digits]<spaces>%<spaces>
- // Captures: digits[.digits]
- _percentageRe: /^\s*(\d+(?:\.\d*)?)\s*[%]\s*$/,
- getItemSizePolicy: function (item, ownerSizeModel) {
- var me = this,
- policy = me.sizePolicy,
- align = me.align,
- flex = item.flex,
- key = align,
- names = me.names,
- width = item[names.width],
- height = item[names.height],
- percentageRe = me._percentageRe,
- percentageWidth = percentageRe.test(width),
- isStretch = (align == 'stretch');
-
- if ((isStretch || flex || percentageWidth) && !ownerSizeModel) {
- ownerSizeModel = me.owner.getSizeModel();
- }
- if (isStretch) {
- // If we are height.shrinkWrap, we behave as if we were stretchmax (for more
- // details, see beginLayoutCycle)...
- if (!percentageRe.test(height) && ownerSizeModel[names.height].shrinkWrap) {
- key = 'stretchmax';
- // We leave %age height as stretch since it will not participate in the
- // stretchmax size calculation. This avoid running such a child in its
- // shrinkWrap mode prior to supplying the calculated size.
- }
- } else if (align != 'stretchmax') {
- if (percentageRe.test(height)) {
- // Height %ages are calculated based on container size, so they are the
- // same as align=stretch for this purpose...
- key = 'stretch';
- } else {
- key = '';
- }
- }
- if (flex || percentageWidth) {
- // If we are width.shrinkWrap, we won't be flexing since that requires a
- // container width...
- if (!ownerSizeModel[names.width].shrinkWrap) {
- policy = policy.flex; // both flex and %age width are calculated
- }
- }
- return policy[key];
- },
- flexSort: function (a, b) {
- var maxWidthName = this.getNames().maxWidth,
- infiniteValue = Infinity;
- a = a.target[maxWidthName] || infiniteValue;
- b = b.target[maxWidthName] || infiniteValue;
- // IE 6/7 Don't like Infinity - Infinity...
- if (!isFinite(a) && !isFinite(b)) {
- return 0;
- }
- return a - b;
- },
- isItemBoxParent: function (itemContext) {
- return true;
- },
- isItemShrinkWrap: function (item) {
- return true;
- },
- // Sort into *descending* order.
- minSizeSortFn: function(a, b) {
- return b.available - a.available;
- },
- roundFlex: function(width) {
- return Math.ceil(width);
- },
- <span id='Ext-layout-container-Box-method-beginCollapse'> /**
- </span> * @private
- * Called by an owning Panel before the Panel begins its collapse process.
- * Most layouts will not need to override the default Ext.emptyFn implementation.
- */
- beginCollapse: function(child) {
- var me = this;
- if (me.direction === 'vertical' && child.collapsedVertical()) {
- child.collapseMemento.capture(['flex']);
- delete child.flex;
- } else if (me.direction === 'horizontal' && child.collapsedHorizontal()) {
- child.collapseMemento.capture(['flex']);
- delete child.flex;
- }
- },
- <span id='Ext-layout-container-Box-method-beginExpand'> /**
- </span> * @private
- * Called by an owning Panel before the Panel begins its expand process.
- * Most layouts will not need to override the default Ext.emptyFn implementation.
- */
- beginExpand: function(child) {
- // Restores the flex if we used to be flexed before
- child.collapseMemento.restore(['flex']);
- },
- beginLayout: function (ownerContext) {
- var me = this,
- smp = me.owner.stretchMaxPartner,
- style = me.innerCt.dom.style,
- names = me.getNames();
- ownerContext.boxNames = names;
- // this must happen before callParent to allow the overflow handler to do its work
- // that can effect the childItems collection...
- me.overflowHandler.beginLayout(ownerContext);
- // get the contextItem for our stretchMax buddy:
- if (typeof smp === 'string') {
- smp = Ext.getCmp(smp) || me.owner.query(smp)[0];
- }
- ownerContext.stretchMaxPartner = smp && ownerContext.context.getCmp(smp);
- me.callParent(arguments);
- ownerContext.innerCtContext = ownerContext.getEl('innerCt', me);
- // Capture whether the owning Container is scrolling in the parallel direction
- me.scrollParallel = !!(me.owner.autoScroll || me.owner[names.overflowX]);
- // Capture whether the owning Container is scrolling in the perpendicular direction
- me.scrollPerpendicular = !!(me.owner.autoScroll || me.owner[names.overflowY]);
- // If we *are* scrolling parallel, capture the scroll position of the encapsulating element
- if (me.scrollParallel) {
- me.scrollPos = me.owner.getTargetEl().dom[names.scrollLeft];
- }
- // Don't allow sizes burned on to the innerCt to influence measurements.
- style.width = '';
- style.height = '';
- },
- beginLayoutCycle: function (ownerContext, firstCycle) {
- var me = this,
- align = me.align,
- names = ownerContext.boxNames,
- pack = me.pack,
- heightModelName = names.heightModel;
- // this must happen before callParent to allow the overflow handler to do its work
- // that can effect the childItems collection...
- me.overflowHandler.beginLayoutCycle(ownerContext, firstCycle);
- me.callParent(arguments);
- // Cache several of our string concat/compare results (since width/heightModel can
- // change if we are invalidated, we cannot do this in beginLayout)
- ownerContext.parallelSizeModel = ownerContext[names.widthModel];
- ownerContext.perpendicularSizeModel = ownerContext[heightModelName];
- ownerContext.boxOptions = {
- align: align = {
- stretch: align == 'stretch',
- stretchmax: align == 'stretchmax',
- center: align == names.center
- },
- pack: pack = {
- center: pack == 'center',
- end: pack == 'end'
- }
- };
- // Consider an hbox w/stretch which means "assign all items the container's height".
- // The spirit of this request is make all items the same height, but when shrinkWrap
- // height is also requested, the height of the tallest item determines the height.
- // This is exactly what the stretchmax option does, so we jiggle the flags here to
- // act as if stretchmax were requested.
- if (align.stretch && ownerContext.perpendicularSizeModel.shrinkWrap) {
- align.stretchmax = true;
- align.stretch = false;
- }
- // This is handy for knowing that we might need to apply height %ages
- align.nostretch = !(align.stretch || align.stretchmax);
- // In our example hbox, packing items to the right (end) or center can only work if
- // there is a container width. So, if we are shrinkWrap, we just turn off the pack
- // options for the run.
- if (ownerContext.parallelSizeModel.shrinkWrap) {
- pack.center = pack.end = false;
- }
- me.cacheFlexes(ownerContext);
- // In webkit we set the width of the target el equal to the width of the innerCt
- // when the layout cycle is finished, so we need to set it back to 20000px here
- // to prevent the children from being crushed.
- if (Ext.isWebKit) {
- me.targetEl.setWidth(20000);
- }
- },
- <span id='Ext-layout-container-Box-method-cacheFlexes'> /**
- </span> * This method is called to (re)cache our understanding of flexes. This happens during beginLayout and may need to
- * be called again if the flexes are changed during the layout (e.g., like ColumnLayout).
- * @param {Object} ownerContext
- * @protected
- */
- cacheFlexes: function (ownerContext) {
- var me = this,
- names = ownerContext.boxNames,
- widthModelName = names.widthModel,
- heightModelName = names.heightModel,
- nostretch = ownerContext.boxOptions.align.nostretch,
- totalFlex = 0,
- childItems = ownerContext.childItems,
- i = childItems.length,
- flexedItems = [],
- minWidth = 0,
- minWidthName = names.minWidth,
- percentageRe = me._percentageRe,
- percentageWidths = 0,
- percentageHeights = 0,
- child, childContext, flex, match;
- while (i--) {
- childContext = childItems[i];
- child = childContext.target;
- // check widthModel to see if we are the sizing layout. If so, copy the flex
- // from the item to the contextItem and add it to totalFlex
- //
- if (childContext[widthModelName].calculated) {
- childContext.flex = flex = child.flex;
- if (flex) {
- totalFlex += flex;
- flexedItems.push(childContext);
- minWidth += child[minWidthName] || 0;
- } else { // a %age width...
- match = percentageRe.exec(child[names.width]);
- childContext.percentageParallel = parseFloat(match[1]) / 100;
- ++percentageWidths;
- }
- }
- // the above means that "childContext.flex" is properly truthy/falsy, which is
- // often times quite convenient...
- if (nostretch && childContext[heightModelName].calculated) {
- // the only reason we would be calculated height in this case is due to a
- // height %age...
- match = percentageRe.exec(child[names.height]);
- childContext.percentagePerpendicular = parseFloat(match[1]) / 100;
- ++percentageHeights;
- }
- }
- ownerContext.flexedItems = flexedItems;
- ownerContext.flexedMinSize = minWidth;
- ownerContext.totalFlex = totalFlex;
- ownerContext.percentageWidths = percentageWidths;
- ownerContext.percentageHeights = percentageHeights;
- // 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(flexedItems, me.flexSortFn);
- },
- calculate: function(ownerContext) {
- var me = this,
- targetSize = me.getContainerSize(ownerContext),
- names = ownerContext.boxNames,
- state = ownerContext.state,
- plan = state.boxPlan || (state.boxPlan = {});
- plan.targetSize = targetSize;
- // If we are not widthModel.shrinkWrap, we need the width before we can lay out boxes:
- if (!ownerContext.parallelSizeModel.shrinkWrap && !targetSize[names.gotWidth]) {
- me.done = false;
- return;
- }
- if (!state.parallelDone) {
- state.parallelDone = me.calculateParallel(ownerContext, names, plan);
- }
- if (!state.perpendicularDone) {
- state.perpendicularDone = me.calculatePerpendicular(ownerContext, names, plan);
- }
- if (state.parallelDone && state.perpendicularDone) {
- // 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 publishInnerCtSize 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.horizontal) {
- plan.isIEVerticalDock = true;
- plan.calculatedWidth = plan.maxSize + ownerContext.getPaddingInfo().width + ownerContext.getFrameInfo().width;
- }
- me.publishInnerCtSize(ownerContext, me.reserveOffset ? me.availableSpaceOffset : 0);
- // Calculate stretchmax only if there is >1 child item
- if (me.done && ownerContext.childItems.length > 1 && ownerContext.boxOptions.align.stretchmax && !state.stretchMaxDone) {
- me.calculateStretchMax(ownerContext, names, plan);
- state.stretchMaxDone = true;
- }
- } else {
- me.done = false;
- }
- },
- calculateParallel: function(ownerContext, names, plan) {
- var me = this,
- widthName = names.width,
- childItems = ownerContext.childItems,
- leftName = names.left,
- rightName = names.right,
- setWidthName = names.setWidth,
- childItemsLength = childItems.length,
- flexedItems = ownerContext.flexedItems,
- flexedItemsLength = flexedItems.length,
- pack = ownerContext.boxOptions.pack,
- padding = me.padding,
- containerWidth = plan.targetSize[widthName],
- totalMargin = 0,
- left = padding[leftName],
- nonFlexWidth = left + padding[rightName] + me.scrollOffset +
- (me.reserveOffset ? me.availableSpaceOffset : 0),
- scrollbarWidth = Ext.getScrollbarSize()[names.width],
- i, childMargins, remainingWidth, remainingFlex, childContext, flex, flexedWidth,
- contentWidth, mayNeedScrollbarAdjust, childWidth, percentageSpace;
- // We may need to add scrollbar size to parallel size if
- // Scrollbars take up space
- // and we are scrolling in the perpendicular direction
- // and shrinkWrapping in the parallel direction,
- // and NOT stretching perpendicular dimensions to fit
- // and NOT shrinkWrapping in the perpendicular direction
- if (scrollbarWidth &&
- me.scrollPerpendicular &&
- ownerContext.parallelSizeModel.shrinkWrap &&
- !ownerContext.boxOptions.align.stretch &&
- !ownerContext.perpendicularSizeModel.shrinkWrap) {
- // If its possible that we may need to add scrollbar size to the parallel size
- // then we need to wait until the perpendicular size has been determined,
- // so that we know if there is a scrollbar.
- if (!ownerContext.state.perpendicularDone) {
- return false;
- }
- mayNeedScrollbarAdjust = true;
- }
- // Gather the total size taken up by non-flexed items:
- for (i = 0; i < childItemsLength; ++i) {
- childContext = childItems[i];
- childMargins = childContext.marginInfo || childContext.getMarginInfo();
- totalMargin += childMargins[widthName];
- if (!childContext[names.widthModel].calculated) {
- childWidth = childContext.getProp(widthName);
- nonFlexWidth += childWidth; // min/maxWidth safe
- if (isNaN(nonFlexWidth)) {
- return false;
- }
- }
- }
- nonFlexWidth += totalMargin;
- if (ownerContext.percentageWidths) {
- percentageSpace = containerWidth - totalMargin;
- if (isNaN(percentageSpace)) {
- return false;
- }
- for (i = 0; i < childItemsLength; ++i) {
- childContext = childItems[i];
- if (childContext.percentageParallel) {
- childWidth = Math.ceil(percentageSpace * childContext.percentageParallel);
- childWidth = childContext.setWidth(childWidth);
- nonFlexWidth += childWidth;
- }
- }
- }
- // if we get here, we have all the childWidths for non-flexed items...
- if (ownerContext.parallelSizeModel.shrinkWrap) {
- plan.availableSpace = 0;
- plan.tooNarrow = false;
- } else {
- plan.availableSpace = containerWidth - nonFlexWidth;
- // If we're going to need space for a parallel scrollbar, then we need to redo the perpendicular measurements
- plan.tooNarrow = plan.availableSpace < ownerContext.flexedMinSize;
- if (plan.tooNarrow && Ext.getScrollbarSize()[names.height] && me.scrollParallel && ownerContext.state.perpendicularDone) {
- ownerContext.state.perpendicularDone = false;
- for (i = 0; i < childItemsLength; ++i) {
- childItems[i].invalidate();
- }
- }
- }
- contentWidth = nonFlexWidth;
- remainingWidth = plan.availableSpace;
- remainingFlex = ownerContext.totalFlex;
- // Calculate flexed item sizes:
- for (i = 0; i < flexedItemsLength; i++) {
- childContext = flexedItems[i];
- flex = childContext.flex;
- flexedWidth = me.roundFlex((flex / remainingFlex) * remainingWidth);
- flexedWidth = childContext[setWidthName](flexedWidth); // constrained
- // due to minWidth constraints, it may be that flexedWidth > remainingWidth
- contentWidth += flexedWidth;
- // Remaining space has already had margins subtracted, so just subtract size
- remainingWidth = Math.max(0, remainingWidth - flexedWidth); // no negatives!
- remainingFlex -= flex;
- }
- if (pack.center) {
- left += remainingWidth / 2;
- // If content is too wide to pack to center, do not allow the centering calculation to place it off the left edge.
- if (left < 0) {
- left = 0;
- }
- } else if (pack.end) {
- left += remainingWidth;
- }
- // Assign parallel position for the boxes:
- for (i = 0; i < childItemsLength; ++i) {
- childContext = childItems[i];
- childMargins = childContext.marginInfo; // already cached by first loop
- left += childMargins[leftName];
- childContext.setProp(names.x, left);
- // We can read directly from "props.width" because we have already properly
- // requested it in the calculation of nonFlexedWidths or we calculated it.
- // We cannot call getProp because that would be inappropriate for flexed items
- // and we don't need any extra function call overhead:
- left += childMargins[rightName] + childContext.props[widthName];
- }
- contentWidth += ownerContext.targetContext.getPaddingInfo()[widthName];
- // Stash the contentWidth on the state so that it can always be accessed later in the calculation
- ownerContext.state.contentWidth = contentWidth;
- // if there is perpendicular overflow, the published parallel content size includes
- // the size of the perpendicular scrollbar.
- if (mayNeedScrollbarAdjust &&
- (ownerContext.peek(names.contentHeight) > plan.targetSize[names.height])) {
- contentWidth += scrollbarWidth;
- ownerContext[names.hasOverflowY] = true;
- // tell the component layout to set the parallel size in the dom
- ownerContext.target.componentLayout[names.setWidthInDom] = true;
- // IE8 in what passes for "strict" mode will not create a scrollbar if
- // there is just the *exactly correct* spare space created for it. We
- // have to force that to happen once all the styles have been flushed
- // to the DOM (see completeLayout):
- ownerContext[names.invalidateScrollY] = (Ext.isStrict && Ext.isIE8);
- }
- ownerContext[names.setContentWidth](contentWidth);
- return true;
- },
- calculatePerpendicular: function(ownerContext, names, plan) {
- var me = this,
- heightShrinkWrap = ownerContext.perpendicularSizeModel.shrinkWrap,
- targetSize = plan.targetSize,
- childItems = ownerContext.childItems,
- childItemsLength = childItems.length,
- mmax = Math.max,
- heightName = names.height,
- setHeightName = names.setHeight,
- topName = names.top,
- topPositionName = names.y,
- padding = me.padding,
- top = padding[topName],
- availHeight = targetSize[heightName] - top - padding[names.bottom],
- align = ownerContext.boxOptions.align,
- isStretch = align.stretch, // never true if heightShrinkWrap (see beginLayoutCycle)
- isStretchMax = align.stretchmax,
- isCenter = align.center,
- maxHeight = 0,
- hasPercentageSizes = 0,
- scrollbarHeight = Ext.getScrollbarSize().height,
- childTop, i, childHeight, childMargins, diff, height, childContext,
- stretchMaxPartner, stretchMaxChildren, shrinkWrapParallelOverflow,
- percentagePerpendicular;
- if (isStretch || (isCenter && !heightShrinkWrap)) {
- if (isNaN(availHeight)) {
- return false;
- }
- }
- // If the intention is to horizontally scroll child components, but the container is too narrow,
- // then:
- // if we are shrinkwrapping height:
- // Set a flag because we are going to expand the height taken by the perpendicular dimension to accommodate the scrollbar
- // else
- // We must allow for the parallel scrollbar to intrude into the height
- if (me.scrollParallel && plan.tooNarrow) {
- if (heightShrinkWrap) {
- shrinkWrapParallelOverflow = true;
- } else {
- availHeight -= scrollbarHeight;
- plan.targetSize[heightName] -= scrollbarHeight;
- }
- }
- if (isStretch) {
- height = availHeight; // never heightShrinkWrap...
- } else {
- for (i = 0; i < childItemsLength; i++) {
- childContext = childItems[i];
- childMargins = (childContext.marginInfo || childContext.getMarginInfo())[heightName];
- if (!(percentagePerpendicular = childContext.percentagePerpendicular)) {
- childHeight = childContext.getProp(heightName);
- } else {
- ++hasPercentageSizes;
- if (heightShrinkWrap) {
- // height %age items cannot contribute to maxHeight... they are going
- // to be a %age of that maxHeight!
- continue;
- } else {
- childHeight = percentagePerpendicular * availHeight - childMargins;
- childHeight = childContext[names.setHeight](childHeight);
- }
- }
- // Max perpendicular measurement (used for stretchmax) must take the min perpendicular size of each child into account in case any fall short.
- if (isNaN(maxHeight = mmax(maxHeight, childHeight + childMargins,
- childContext.target[names.minHeight] || 0))) {
- return false; // heightShrinkWrap || isCenter || isStretchMax ??
- }
- }
- // If there is going to be a parallel scrollbar maxHeight must include it to the outside world.
- // ie: a stretchmaxPartner, and the setContentHeight
- if (shrinkWrapParallelOverflow) {
- maxHeight += scrollbarHeight;
- ownerContext[names.hasOverflowX] = true;
- // tell the component layout to set the perpendicular size in the dom
- ownerContext.target.componentLayout[names.setHeightInDom] = true;
- // IE8 in what passes for "strict" mode will not create a scrollbar if
- // there is just the *exactly correct* spare space created for it. We
- // have to force that to happen once all the styles have been flushed
- // to the DOM (see completeLayout):
- ownerContext[names.invalidateScrollX] = (Ext.isStrict && Ext.isIE8);
- }
- // If we are associated with another box layout, grab its maxChildHeight
- // This must happen before we calculate and publish our contentHeight
- stretchMaxPartner = ownerContext.stretchMaxPartner;
- if (stretchMaxPartner) {
- // Publish maxChildHeight as soon as it has been calculated for our partner:
- ownerContext.setProp('maxChildHeight', maxHeight);
- stretchMaxChildren = stretchMaxPartner.childItems;
- // Only wait for maxChildHeight if our partner has visible items:
- if (stretchMaxChildren && stretchMaxChildren.length) {
- maxHeight = mmax(maxHeight, stretchMaxPartner.getProp('maxChildHeight'));
- if (isNaN(maxHeight)) {
- return false;
- }
- }
- }
- ownerContext[names.setContentHeight](maxHeight + me.padding[heightName] +
- ownerContext.targetContext.getPaddingInfo()[heightName]);
- // We have to publish the contentHeight with the additional scrollbarHeight
- // to encourage our container to accomodate it, but we must remove the height
- // of the scrollbar as we go to sizing or centering the children.
- if (shrinkWrapParallelOverflow) {
- maxHeight -= scrollbarHeight;
- }
- plan.maxSize = maxHeight;
- if (isStretchMax) {
- height = maxHeight;
- } else if (isCenter || hasPercentageSizes) {
- height = heightShrinkWrap ? maxHeight : mmax(availHeight, maxHeight);
- // 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 publishInnerCtSize method explicitly
- // adds the border widths to the set size of the innerCt.
- height -= ownerContext.innerCtContext.getBorderInfo()[heightName];
- }
- }
- for (i = 0; i < childItemsLength; i++) {
- childContext = childItems[i];
- childMargins = childContext.marginInfo || childContext.getMarginInfo();
- childTop = top + childMargins[topName];
- if (isStretch) {
- childContext[setHeightName](height - childMargins[heightName]);
- } else {
- percentagePerpendicular = childContext.percentagePerpendicular;
- if (heightShrinkWrap && percentagePerpendicular) {
- childMargins = childContext.marginInfo || childContext.getMarginInfo();
- childHeight = percentagePerpendicular * height - childMargins[heightName];
- childHeight = childContext.setHeight(childHeight);
- }
- if (isCenter) {
- diff = height - childContext.props[heightName];
- if (diff > 0) {
- childTop = top + Math.round(diff / 2);
- }
- }
- }
- childContext.setProp(topPositionName, childTop);
- }
- return true;
- },
- calculateStretchMax: function (ownerContext, names, plan) {
- var me = this,
- heightName = names.height,
- widthName = names.width,
- childItems = ownerContext.childItems,
- length = childItems.length,
- height = plan.maxSize,
- onBeforeInvalidateChild = me.onBeforeInvalidateChild,
- onAfterInvalidateChild = me.onAfterInvalidateChild,
- childContext, props, i, childHeight;
- for (i = 0; i < length; ++i) {
- childContext = childItems[i];
- props = childContext.props;
- childHeight = height - childContext.getMarginInfo()[heightName];
- if (childHeight != props[heightName] || // if (wrong height ...
- childContext[names.heightModel].constrained) { // ...or needs invalidation)
- // When we invalidate a child, since we won't be around to size or position
- // it, we include an after callback that will be run after the invalidate
- // that will (re)do that work. The good news here is that we can read the
- // results of all that from the childContext props.
- //
- // We also include a before callback to change the sizeModel to calculated
- // prior to the layout being invoked.
- childContext.invalidate({
- before: onBeforeInvalidateChild,
- after: onAfterInvalidateChild,
- layout: me,
- // passing this data avoids a 'scope' and its Function.bind
- childWidth: props[widthName],
- // subtract margins from the maximum value
- childHeight: childHeight,
- childX: props.x,
- childY: props.y,
- names: names
- });
- }
- }
- },
- completeLayout: function(ownerContext) {
- var me = this,
- names = ownerContext.boxNames,
- invalidateScrollX = ownerContext.invalidateScrollX,
- invalidateScrollY = ownerContext.invalidateScrollY,
- dom, el, overflowX, overflowY, styles;
- me.overflowHandler.completeLayout(ownerContext);
- if (invalidateScrollX || invalidateScrollY) {
- el = me.getTarget();
- dom = el.dom;
- styles = dom.style;
- if (invalidateScrollX) {
- // get computed style to see if we are 'auto'
- overflowX = el.getStyle('overflowX');
- if (overflowX == 'auto') {
- // capture the inline style (if any) so we can restore it later:
- overflowX = styles.overflowX;
- styles.overflowX = 'scroll'; // force the scrollbar to appear
- } else {
- invalidateScrollX = false; // no work really since not 'auto'
- }
- }
- if (invalidateScrollY) {
- // get computed style to see if we are 'auto'
- overflowY = el.getStyle('overflowY');
- if (overflowY == 'auto') {
- // capture the inline style (if any) so we can restore it later:
- overflowY = styles.overflowY;
- styles.overflowY = 'scroll'; // force the scrollbar to appear
- } else {
- invalidateScrollY = false; // no work really since not 'auto'
- }
- }
- if (invalidateScrollX || invalidateScrollY) { // if (some form of 'auto' in play)
- // force a reflow...
- dom.scrollWidth;
- if (invalidateScrollX) {
- styles.overflowX = overflowX; // restore inline style
- }
- if (invalidateScrollY) {
- styles.overflowY = overflowY; // restore inline style
- }
- }
- }
- // If we are scrolling parallel, restore the saved scroll position
- if (me.scrollParallel) {
- me.owner.getTargetEl().dom[names.scrollLeft] = me.scrollPos;
- }
- },
- finishedLayout: function(ownerContext) {
- this.overflowHandler.finishedLayout(ownerContext);
- this.callParent(arguments);
- // Fix for an obscure webkit bug (EXTJSIV-5962) caused by the targetEl's 20000px
- // width. We set a very large width on the targetEl at the beginning of the
- // layout cycle to prevent any "crushing" effect on the child items, however
- // in some cases the very large width makes it possible to scroll the innerCt
- // by dragging on certain child elements. To prevent this from happening we ensure
- // that the targetEl's width is the same as the innerCt.
- if (Ext.isWebKit) {
- this.targetEl.setWidth(ownerContext.innerCtContext.props.width);
- }
- },
- onBeforeInvalidateChild: function (childContext, options) {
- // NOTE: No "this" pointer in here...
- var heightModelName = options.names.heightModel;
- // Change the childItem to calculated (i.e., "set by ownerCt"). The component layout
- // of the child can course-correct (like dock layout does for a collapsed panel),
- // so we must make these changes here before that layout's beginLayoutCycle is
- // called.
- if (!childContext[heightModelName].constrainedMax) {
- // if the child hit a max constraint, it needs to be at its configured size, so
- // we leave the sizeModel alone...
- childContext[heightModelName] = Ext.layout.SizeModel.calculated;
- }
- },
- onAfterInvalidateChild: function (childContext, options) {
- // NOTE: No "this" pointer in here...
- var names = options.names,
- scrollbarSize = Ext.getScrollbarSize(),
- childHeight = options.childHeight,
- childWidth = options.childWidth;
- childContext.setProp('x', options.childX);
- childContext.setProp('y', options.childY);
- if (childContext[names.heightModel].calculated) {
- // We need to respect a child that is still not calculated (such as a collapsed
- // panel)...
- childContext[names.setHeight](childHeight);
- }
- if (childContext[names.widthModel].calculated) {
- childContext[names.setWidth](childWidth);
- }
- },
- publishInnerCtSize: function(ownerContext, reservedSpace) {
- var me = this,
- names = ownerContext.boxNames,
- heightName = names.height,
- widthName = names.width,
- align = ownerContext.boxOptions.align,
- dock = me.owner.dock,
- padding = me.padding,
- plan = ownerContext.state.boxPlan,
- targetSize = plan.targetSize,
- height = targetSize[heightName],
- innerCtContext = ownerContext.innerCtContext,
- innerCtWidth = (ownerContext.parallelSizeModel.shrinkWrap || (plan.tooNarrow && me.scrollParallel)
- ? ownerContext.state.contentWidth
- : targetSize[widthName]) - (reservedSpace || 0),
- innerCtHeight;
- if (align.stretch) {
- innerCtHeight = height;
- } else {
- innerCtHeight = plan.maxSize + padding[names.top] + padding[names.bottom] + innerCtContext.getBorderInfo()[heightName];
- if (!ownerContext.perpendicularSizeModel.shrinkWrap && align.center) {
- innerCtHeight = Math.max(height, innerCtHeight);
- }
- }
- innerCtContext[names.setWidth](innerCtWidth);
- innerCtContext[names.setHeight](innerCtHeight);
- // If unable to publish both dimensions, this layout needs to run again
- if (isNaN(innerCtWidth + innerCtHeight)) {
- me.done = false;
- }
- // If a calculated width has been found (this only happens for widthModel.shrinkWrap
- // vertical docked Components in old Microsoft browsers) then, if the Component has
- // not assumed the size of its content, set it to do so.
- //
- // We MUST pass the dirty flag to get that into the DOM, and because we are a Container
- // layout, and not really supposed to perform sizing, we must also use the force flag.
- if (plan.calculatedWidth && (dock == 'left' || dock == 'right')) {
- // TODO: setting the owner size should be the job of the component layout.
- ownerContext.setWidth(plan.calculatedWidth, true, true);
- }
- },
- onRemove: function(comp){
- var me = this;
- me.callParent(arguments);
- if (me.overflowHandler) {
- me.overflowHandler.onRemove(comp);
- }
- if (comp.layoutMarginCap == me.id) {
- delete comp.layoutMarginCap;
- }
- },
- <span id='Ext-layout-container-Box-method-initOverflowHandler'> /**
- </span> * @private
- */
- initOverflowHandler: function() {
- var me = this,
- handler = me.overflowHandler,
- handlerType,
- constructor;
- if (typeof handler == 'string') {
- handler = {
- type: handler
- };
- }
- handlerType = 'None';
- if (handler && handler.type !== undefined) {
- handlerType = handler.type;
- }
- constructor = Ext.layout.container.boxOverflow[handlerType];
- if (constructor[me.type]) {
- constructor = constructor[me.type];
- }
- me.overflowHandler = Ext.create('Ext.layout.container.boxOverflow.' + handlerType, me, handler);
- },
- // Overridden method from Ext.layout.container.Container.
- // Used in the beforeLayout method to render all items into.
- getRenderTarget: function() {
- return this.targetEl;
- },
- // Overridden method from Ext.layout.container.Container.
- // Used by Container classes to insert special DOM elements which must exist in addition to the child components
- getElementTarget: function() {
- return this.innerCt;
- },
- //<debug>
- calculateChildBox: Ext.deprecated(),
- calculateChildBoxes: Ext.deprecated(),
- updateChildBoxes: Ext.deprecated(),
- //</debug>
- <span id='Ext-layout-container-Box-method-destroy'> /**
- </span> * @private
- */
- destroy: function() {
- Ext.destroy(this.innerCt, this.overflowHandler);
- this.callParent(arguments);
- }
- });
- </pre>
- </body>
- </html>
|