Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / src / layout / component / Button.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * Component layout for buttons
17  * @class Ext.layout.component.Button
18  * @extends Ext.layout.component.Component
19  * @private
20  */
21 Ext.define('Ext.layout.component.Button', {
22
23     /* Begin Definitions */
24
25     alias: ['layout.button'],
26
27     extend: 'Ext.layout.component.Component',
28
29     /* End Definitions */
30
31     type: 'button',
32
33     cellClsRE: /-btn-(tl|br)\b/,
34     htmlRE: /<.*>/,
35
36     beforeLayout: function() {
37         return this.callParent(arguments) || this.lastText !== this.owner.text;
38     },
39
40     /**
41      * Set the dimensions of the inner &lt;button&gt; element to match the
42      * component dimensions.
43      */
44     onLayout: function(width, height) {
45         var me = this,
46             isNum = Ext.isNumber,
47             owner = me.owner,
48             ownerEl = owner.el,
49             btnEl = owner.btnEl,
50             btnInnerEl = owner.btnInnerEl,
51             btnIconEl = owner.btnIconEl,
52             sizeIconEl = (owner.icon || owner.iconCls) && (owner.iconAlign == "top" || owner.iconAlign == "bottom"),
53             minWidth = owner.minWidth,
54             maxWidth = owner.maxWidth,
55             ownerWidth, btnFrameWidth, metrics;
56
57         me.getTargetInfo();
58         me.callParent(arguments);
59
60         btnInnerEl.unclip();
61         me.setTargetSize(width, height);
62
63         if (!isNum(width)) {
64             // In IE7 strict mode button elements with width:auto get strange extra side margins within
65             // the wrapping table cell, but they go away if the width is explicitly set. So we measure
66             // the size of the text and set the width to match.
67             if (owner.text && (Ext.isIE6 || Ext.isIE7) && Ext.isStrict && btnEl && btnEl.getWidth() > 20) {
68                 btnFrameWidth = me.btnFrameWidth;
69                 metrics = Ext.util.TextMetrics.measure(btnInnerEl, owner.text);
70                 ownerEl.setWidth(metrics.width + btnFrameWidth + me.adjWidth);
71                 btnEl.setWidth(metrics.width + btnFrameWidth);
72                 btnInnerEl.setWidth(metrics.width + btnFrameWidth);
73
74                 if (sizeIconEl) {
75                     btnIconEl.setWidth(metrics.width + btnFrameWidth);
76                 }
77             } else {
78                 // Remove any previous fixed widths
79                 ownerEl.setWidth(null);
80                 btnEl.setWidth(null);
81                 btnInnerEl.setWidth(null);
82                 btnIconEl.setWidth(null);
83             }
84
85             // Handle maxWidth/minWidth config
86             if (minWidth || maxWidth) {
87                 ownerWidth = ownerEl.getWidth();
88                 if (minWidth && (ownerWidth < minWidth)) {
89                     me.setTargetSize(minWidth, height);
90                 }
91                 else if (maxWidth && (ownerWidth > maxWidth)) {
92                     btnInnerEl.clip();
93                     me.setTargetSize(maxWidth, height);
94                 }
95             }
96         }
97
98         this.lastText = owner.text;
99     },
100
101     setTargetSize: function(width, height) {
102         var me = this,
103             owner = me.owner,
104             isNum = Ext.isNumber,
105             btnInnerEl = owner.btnInnerEl,
106             btnWidth = (isNum(width) ? width - me.adjWidth : width),
107             btnHeight = (isNum(height) ? height - me.adjHeight : height),
108             btnFrameHeight = me.btnFrameHeight,
109             text = owner.getText(),
110             textHeight;
111
112         me.callParent(arguments);
113         me.setElementSize(owner.btnEl, btnWidth, btnHeight);
114         me.setElementSize(btnInnerEl, btnWidth, btnHeight);
115         if (btnHeight >= 0) {
116             btnInnerEl.setStyle('line-height', btnHeight - btnFrameHeight + 'px');
117         }
118
119         // Button text may contain markup that would force it to wrap to more than one line (e.g. 'Button<br>Label').
120         // When this happens, we cannot use the line-height set above for vertical centering; we instead reset the
121         // line-height to normal, measure the rendered text height, and add padding-top to center the text block
122         // vertically within the button's height. This is more expensive than the basic line-height approach so
123         // we only do it if the text contains markup.
124         if (text && this.htmlRE.test(text)) {
125             btnInnerEl.setStyle('line-height', 'normal');
126             textHeight = Ext.util.TextMetrics.measure(btnInnerEl, text).height;
127             btnInnerEl.setStyle('padding-top', me.btnFrameTop + Math.max(btnInnerEl.getHeight() - btnFrameHeight - textHeight, 0) / 2 + 'px');
128             me.setElementSize(btnInnerEl, btnWidth, btnHeight);
129         }
130     },
131
132     getTargetInfo: function() {
133         var me = this,
134             owner = me.owner,
135             ownerEl = owner.el,
136             frameSize = me.frameSize,
137             frameBody = owner.frameBody,
138             btnWrap = owner.btnWrap,
139             innerEl = owner.btnInnerEl;
140
141         if (!('adjWidth' in me)) {
142             Ext.apply(me, {
143                 // Width adjustment must take into account the arrow area. The btnWrap is the <em> which has padding to accommodate the arrow.
144                 adjWidth: frameSize.left + frameSize.right + ownerEl.getBorderWidth('lr') + ownerEl.getPadding('lr') +
145                           btnWrap.getPadding('lr') + (frameBody ? frameBody.getFrameWidth('lr') : 0),
146                 adjHeight: frameSize.top + frameSize.bottom + ownerEl.getBorderWidth('tb') + ownerEl.getPadding('tb') +
147                            btnWrap.getPadding('tb') + (frameBody ? frameBody.getFrameWidth('tb') : 0),
148                 btnFrameWidth: innerEl.getFrameWidth('lr'),
149                 btnFrameHeight: innerEl.getFrameWidth('tb'),
150                 btnFrameTop: innerEl.getFrameWidth('t')
151             });
152         }
153
154         return me.callParent();
155     }
156 });