/** * Component layout for buttons * @private */ Ext.define('Ext.layout.component.Button', { /* Begin Definitions */ alias: ['layout.button'], extend: 'Ext.layout.component.Auto', /* End Definitions */ type: 'button', htmlRE: /<.*>/, beginLayout: function(ownerContext) { var me = this, owner = me.owner, text = owner.text; me.callParent(arguments); ownerContext.btnWrapContext = ownerContext.getEl('btnWrap'); ownerContext.btnElContext = ownerContext.getEl('btnEl'); ownerContext.btnInnerElContext = ownerContext.getEl('btnInnerEl'); ownerContext.btnIconElContext = ownerContext.getEl('btnIconEl'); if (text && me.htmlRE.test(text)) { ownerContext.isHtmlText = true; // If the text contains HTML tag(s) we need to account for the possibility // of multi-line-text. We have to remove the default line-height set by the // stylesheet so that we can allow the browser to measure the natural // height of the html content. owner.btnInnerEl.setStyle('line-height', 'normal'); owner.btnInnerEl.setStyle('padding-top', ''); } }, beginLayoutCycle: function(ownerContext) { var owner = this.owner, lastWidthModel = this.lastWidthModel; this.callParent(arguments); if (lastWidthModel && !this.lastWidthModel.shrinkWrap && ownerContext.widthModel.shrinkWrap) { // clear any heights we set last time around if needed owner.btnWrap.setStyle('height', ''); owner.btnEl.setStyle('height', ''); owner.btnInnerEl.setStyle('line-height', ''); } }, calculate: function(ownerContext) { var me = this, owner = me.owner, btnElContext = ownerContext.btnElContext, btnInnerElContext = ownerContext.btnInnerElContext, btnWrapContext = ownerContext.btnWrapContext, mmax = Math.max, ownerHeight, contentHeight, btnElHeight, innerElHeight; me.callParent(arguments); if (ownerContext.heightModel.shrinkWrap) { // Buttons that have a shrink-wrapped height usually do not need any layout // adjustments beause their layout is handled in CSS. An exception is made // for buttons that contain html tags in their "text". These buttons need // special handling to vertically center the inner element inside the button. // measure the btnEl (the anchor element) to determine the available // height for centering the inner element. btnElHeight = owner.btnEl.getHeight(); if (ownerContext.isHtmlText) { me.centerInnerEl( ownerContext, btnElHeight ); me.ieCenterIcon(ownerContext, btnElHeight); } } else { // Buttons with configured or calculated heights may need to stretch their // inner elements to fit. ownerHeight = ownerContext.getProp('height'); // If height is 0, skip out all this if (ownerHeight) { // contentHeight is the total available height inside the button's padding // and framing contentHeight = ownerHeight - ownerContext.getFrameInfo().height - ownerContext.getPaddingInfo().height; // The btnElHeight is the total available height to be shared by the button's // icon and text. For standard buttons this is the same as the contentHeight // but must be adjusted for arrow height if the button has an arrow. btnElHeight = contentHeight; if ((owner.menu || owner.split) && owner.arrowAlign === 'bottom') { // If the button has an arrow, subtract its size from the btnElHeight // padding to account for the possibility of an arrow btnElHeight -= btnWrapContext.getPaddingInfo().bottom; } // The innerElHeight is the total vertical space available for vertically // centering the button text. By default this is the same as btnElHeight // but it must be adjusted by the icon size if the button has a top // or bottom icon. innerElHeight = btnElHeight; if ((owner.icon || owner.iconCls || owner.glyph) && (owner.iconAlign === 'top' || owner.iconAlign === 'bottom')) { innerElHeight -= btnInnerElContext.getPaddingInfo().height; } btnWrapContext.setProp('height', mmax(0, contentHeight)); btnElContext.setProp('height', mmax(0, btnElHeight)); // ensure the button's text is vertically centered if (ownerContext.isHtmlText) { // if the button text contains html it must be vertically centered // by measuring it and adding top padding. me.centerInnerEl(ownerContext, btnElHeight); } else { // if the button text does not contain html we can just center it // using line-height to avoid the extra measurement that happens // inside of centerInnerEl() since multi-line text is not a possiblity btnInnerElContext.setProp('line-height', mmax(0, innerElHeight) + 'px'); } me.ieCenterIcon(ownerContext, btnElHeight); } else if (ownerHeight !== 0) { // Only fail if height was undefined, since it could be 0 me.done = false; } } }, centerInnerEl: function(ownerContext, btnElHeight) { var me = this, btnInnerElContext = ownerContext.btnInnerElContext, innerElHeight = me.owner.btnInnerEl.getHeight(); if (ownerContext.heightModel.shrinkWrap && (btnElHeight < innerElHeight)) { // if the natural height of the html content is greater than the height // of the button element (the anchor el), then expand the button element // to fit ownerContext.btnElContext.setHeight(innerElHeight); } else if (btnElHeight > innerElHeight) { // if the natural height of the html content is smaller than the height // of the button element then we need to pad the top of the btnInnerEl // so that it is vertically centered within the btnEl btnInnerElContext.setProp( 'padding-top', Math.round((btnElHeight - innerElHeight) / 2) + // if the inner element already has top padding, as is the case // when the button has a top-aligned icon, then add the existing // padding to the padding adjustment. btnInnerElContext.getPaddingInfo().top ); } }, ieCenterIcon: function(ownerContext, btnElHeight) { var iconAlign = this.owner.iconAlign; if ((Ext.isIEQuirks || Ext.isIE6) && (iconAlign === 'left' || iconAlign === 'right')) { // Normally right/left aligned icon elements are vertically stretched using // top:0, bottom:0, and the icon is vertically centered inside this element // using background-position. This technique for vertical centering does not // work in IE6 and IE quirks, so the stylesheet sets a fixed height on the // icon element in these browsers. If the layout changes the height of the // button the height of the icon element must also be modified. ownerContext.btnIconElContext.setHeight(btnElHeight); } }, publishInnerWidth: function(ownerContext, width) { if (this.owner.getFrameInfo().table) { // if the framing template uses a table, we need to set the width of the // inner element. Otherwise long text may stretch the element past its // allowable width in IE. ownerContext.btnInnerElContext.setWidth( width - // the inner el must be sized inside the owner's framing and padding ownerContext.getFrameInfo().width - ownerContext.getPaddingInfo().width - // There may also be padding on the btnWrap el, e.g. tab with close icon // or button with arrow. This reduces the inner el size even further. ownerContext.btnWrapContext.getPaddingInfo().width ); } } });