/** * This class is intended to be extended or created via the {@link Ext.Component#componentLayout layout} * configuration property. See {@link Ext.Component#componentLayout} for additional details. * @private */ Ext.define('Ext.layout.component.Component', { /* Begin Definitions */ extend: 'Ext.layout.Layout', /* End Definitions */ type: 'component', isComponentLayout: true, nullBox: {}, usesContentHeight: true, usesContentWidth: true, usesHeight: true, usesWidth: true, beginLayoutCycle: function (ownerContext, firstCycle) { var me = this, owner = me.owner, ownerCtContext = ownerContext.ownerCtContext, heightModel = ownerContext.heightModel, widthModel = ownerContext.widthModel, body = owner.el.dom === document.body, lastBox = owner.lastBox || me.nullBox, lastSize = owner.el.lastBox || me.nullBox, dirty = !body, ownerLayout, v, widthName, heightName; me.callParent(arguments); if (firstCycle) { if (me.usesContentWidth) { ++ownerContext.consumersContentWidth; } if (me.usesContentHeight) { ++ownerContext.consumersContentHeight; } if (me.usesWidth) { ++ownerContext.consumersWidth; } if (me.usesHeight) { ++ownerContext.consumersHeight; } if (ownerCtContext && !ownerCtContext.hasRawContent) { ownerLayout = owner.ownerLayout; if (ownerLayout.usesWidth) { ++ownerContext.consumersWidth; } if (ownerLayout.usesHeight) { ++ownerContext.consumersHeight; } } } // we want to publish configured dimensions as early as possible and since this is // a write phase... if (widthModel.configured) { // If the owner.el is the body, owner.width is not dirty (we don't want to write // it to the body el). For other el's, the width may already be correct in the // DOM (e.g., it is rendered in the markup initially). If the width is not // correct in the DOM, this is only going to be the case on the first cycle. widthName = widthModel.names.width; if (!body) { dirty = firstCycle ? owner[widthName] !== lastSize.width : widthModel.constrained; } ownerContext.setWidth(owner[widthName], dirty); } else if (ownerContext.isTopLevel) { if (widthModel.calculated) { v = lastBox.width; ownerContext.setWidth(v, /*dirty=*/v != lastSize.width); } v = lastBox.x; ownerContext.setProp('x', v, /*dirty=*/v != lastSize.x); } if (heightModel.configured) { heightName = heightModel.names.height; if (!body) { dirty = firstCycle ? owner[heightName] !== lastSize.height : heightModel.constrained; } ownerContext.setHeight(owner[heightName], dirty); } else if (ownerContext.isTopLevel) { if (heightModel.calculated) { v = lastBox.height; ownerContext.setHeight(v, v != lastSize.height); } v = lastBox.y; ownerContext.setProp('y', v, /*dirty=*/v != lastSize.y); } }, finishedLayout: function(ownerContext) { var me = this, elementChildren = ownerContext.children, owner = me.owner, len, i, elContext, lastBox, props, v; // NOTE: In the code below we cannot use getProp because that will generate a layout dependency // Set lastBox on managed child Elements. // So that ContextItem.constructor can snag the lastBox for use by its undo method. if (elementChildren) { len = elementChildren.length; for (i = 0; i < len; i++) { elContext = elementChildren[i]; elContext.el.lastBox = elContext.props; } } // Cache the size from which we are changing so that notifyOwner can notify the owningComponent with all essential information ownerContext.previousSize = me.lastComponentSize; // Cache the currently layed out size me.lastComponentSize = owner.el.lastBox = props = ownerContext.props; // lastBox is a copy of the defined props to allow save/restore of these (panel // collapse needs this) owner.lastBox = lastBox = {}; v = props.x; if (v !== undefined) { lastBox.x = v; } v = props.y; if (v !== undefined) { lastBox.y = v; } v = props.width; if (v !== undefined) { lastBox.width = v; } v = props.height; if (v !== undefined) { lastBox.height = v; } me.callParent(arguments); }, notifyOwner: function(ownerContext) { var me = this, currentSize = me.lastComponentSize, prevSize = ownerContext.previousSize, args = [currentSize.width, currentSize.height]; if (prevSize) { args.push(prevSize.width, prevSize.height); } // Call afterComponentLayout passing new size, and only passing old size if there *was* an old size. me.owner.afterComponentLayout.apply(me.owner, args); }, /** * Returns the owner component's resize element. * @return {Ext.Element} */ getTarget : function() { return this.owner.el; }, /** * Returns the element into which rendering must take place. Defaults to the owner Component's encapsulating element. * * May be overridden in Component layout managers which implement an inner element. * @return {Ext.Element} */ getRenderTarget : function() { return this.owner.el; }, cacheTargetInfo: function(ownerContext) { var me = this, targetInfo = me.targetInfo, target; if (!targetInfo) { target = ownerContext.getEl('getTarget', me); me.targetInfo = targetInfo = { padding: target.getPaddingInfo(), border: target.getBorderInfo() }; } return targetInfo; }, measureAutoDimensions: function (ownerContext, dimensions) { // Subtle But Important: // // We don't want to call getProp/hasProp et.al. unless we in fact need that value // for our results! If we call it and don't need it, the layout manager will think // we depend on it and will schedule us again should it change. var me = this, owner = me.owner, heightModel = ownerContext.heightModel, widthModel = ownerContext.widthModel, boxParent = ownerContext.boxParent, isBoxParent = ownerContext.isBoxParent, props = ownerContext.props, isContainer, ret = { gotWidth: false, gotHeight: false, isContainer: (isContainer = !ownerContext.hasRawContent) }, hv = dimensions || 3, zeroWidth, zeroHeight, needed = 0, got = 0, ready, size; // Note: this method is called *a lot*, so we have to be careful not to waste any // time or make useless calls or, especially, read the DOM when we can avoid it. //--------------------------------------------------------------------- // Width if (widthModel.shrinkWrap && ownerContext.consumersContentWidth) { ++needed; zeroWidth = !(hv & 1); if (isContainer) { // as a componentLayout for a container, we rely on the container layout to // produce contentWidth... if (zeroWidth) { ret.contentWidth = 0; ret.gotWidth = true; ++got; } else if ((ret.contentWidth = ownerContext.getProp('contentWidth')) !== undefined) { ret.gotWidth = true; ++got; } } else { size = props.contentWidth; if (typeof size == 'number') { // if (already determined) ret.contentWidth = size; ret.gotWidth = true; ++got; } else { if (zeroWidth) { ready = true; } else if (!ownerContext.hasDomProp('containerChildrenDone')) { ready = false; } else if (isBoxParent || !boxParent || boxParent.widthModel.shrinkWrap) { // if we have no boxParent, we are ready, but a shrinkWrap boxParent // artificially provides width early in the measurement process so // we are ready to go in that case as well... ready = true; } else { // lastly, we have a boxParent that will be given a width, so we // can wait for that width to be set in order to properly measure // whatever is inside... ready = boxParent.hasDomProp('width'); } if (ready) { if (!isNaN(ret.contentWidth = zeroWidth ? 0 : me.measureContentWidth(ownerContext))) { ownerContext.setContentWidth(ret.contentWidth, true); ret.gotWidth = true; ++got; } } } } } else if (widthModel.natural && ownerContext.consumersWidth) { ++needed; size = props.width; // zeroWidth does not apply if (typeof size == 'number') { // if (already determined) ret.width = size; ret.gotWidth = true; ++got; } else { if (isBoxParent || !boxParent) { ready = true; } else { // lastly, we have a boxParent that will be given a width, so we // can wait for that width to be set in order to properly measure // whatever is inside... ready = boxParent.hasDomProp('width'); } if (ready) { if (!isNaN(ret.width = me.measureOwnerWidth(ownerContext))) { ownerContext.setWidth(ret.width, false); ret.gotWidth = true; ++got; } } } } //--------------------------------------------------------------------- // Height if (heightModel.shrinkWrap && ownerContext.consumersContentHeight) { ++needed; zeroHeight = !(hv & 2); if (isContainer) { // don't ask unless we need to know... if (zeroHeight) { ret.contentHeight = 0; ret.gotHeight = true; ++got; } else if ((ret.contentHeight = ownerContext.getProp('contentHeight')) !== undefined) { ret.gotHeight = true; ++got; } } else { size = props.contentHeight; if (typeof size == 'number') { // if (already determined) ret.contentHeight = size; ret.gotHeight = true; ++got; } else { if (zeroHeight) { ready = true; } else if (!ownerContext.hasDomProp('containerChildrenDone')) { ready = false; } else if (owner.noWrap) { ready = true; } else if (!widthModel.shrinkWrap) { // fixed width, so we need the width to determine the height... ready = (ownerContext.bodyContext || ownerContext).hasDomProp('width');// && (!ownerContext.bodyContext || ownerContext.bodyContext.hasDomProp('width')); } else if (isBoxParent || !boxParent || boxParent.widthModel.shrinkWrap) { // if we have no boxParent, we are ready, but an autoWidth boxParent // artificially provides width early in the measurement process so // we are ready to go in that case as well... ready = true; } else { // lastly, we have a boxParent that will be given a width, so we // can wait for that width to be set in order to properly measure // whatever is inside... ready = boxParent.hasDomProp('width'); } if (ready) { if (!isNaN(ret.contentHeight = zeroHeight ? 0 : me.measureContentHeight(ownerContext))) { ownerContext.setContentHeight(ret.contentHeight, true); ret.gotHeight = true; ++got; } } } } } else if (heightModel.natural && ownerContext.consumersHeight) { ++needed; size = props.height; // zeroHeight does not apply if (typeof size == 'number') { // if (already determined) ret.height = size; ret.gotHeight = true; ++got; } else { if (isBoxParent || !boxParent) { ready = true; } else { // lastly, we have a boxParent that will be given a width, so we // can wait for that width to be set in order to properly measure // whatever is inside... ready = boxParent.hasDomProp('width'); } if (ready) { if (!isNaN(ret.height = me.measureOwnerHeight(ownerContext))) { ownerContext.setHeight(ret.height, false); ret.gotHeight = true; ++got; } } } } if (boxParent) { ownerContext.onBoxMeasured(); } ret.gotAll = got == needed; // see if we can avoid calling this method by storing something on ownerContext. return ret; }, measureContentWidth: function (ownerContext) { // contentWidth includes padding, but not border, framing or margins return ownerContext.el.getWidth() - ownerContext.getFrameInfo().width; }, measureContentHeight: function (ownerContext) { // contentHeight includes padding, but not border, framing or margins return ownerContext.el.getHeight() - ownerContext.getFrameInfo().height; }, measureOwnerHeight: function (ownerContext) { return ownerContext.el.getHeight(); }, measureOwnerWidth: function (ownerContext) { return ownerContext.el.getWidth(); } });