Upgrade to ExtJS 3.2.2 - Released 06/02/2010
[extjs.git] / src / core / Element.style-more.js
1 /*!
2  * Ext JS Library 3.2.2
3  * Copyright(c) 2006-2010 Ext JS, Inc.
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /**
8  * @class Ext.Element
9  */
10
11 // special markup used throughout Ext when box wrapping elements
12 Ext.Element.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
13
14 Ext.Element.addMethods(function(){
15     var INTERNAL = "_internal",
16         pxMatch = /(\d+\.?\d+)px/;
17     return {
18         /**
19          * More flexible version of {@link #setStyle} for setting style properties.
20          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
21          * a function which returns such a specification.
22          * @return {Ext.Element} this
23          */
24         applyStyles : function(style){
25             Ext.DomHelper.applyStyles(this.dom, style);
26             return this;
27         },
28
29         /**
30          * Returns an object with properties matching the styles requested.
31          * For example, el.getStyles('color', 'font-size', 'width') might return
32          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
33          * @param {String} style1 A style name
34          * @param {String} style2 A style name
35          * @param {String} etc.
36          * @return {Object} The style object
37          */
38         getStyles : function(){
39             var ret = {};
40             Ext.each(arguments, function(v) {
41                ret[v] = this.getStyle(v);
42             },
43             this);
44             return ret;
45         },
46
47         // private  ==> used by ext full
48         setOverflow : function(v){
49             var dom = this.dom;
50             if(v=='auto' && Ext.isMac && Ext.isGecko2){ // work around stupid FF 2.0/Mac scroll bar bug
51                 dom.style.overflow = 'hidden';
52                 (function(){dom.style.overflow = 'auto';}).defer(1);
53             }else{
54                 dom.style.overflow = v;
55             }
56         },
57
58        /**
59         * <p>Wraps the specified element with a special 9 element markup/CSS block that renders by default as
60         * a gray container with a gradient background, rounded corners and a 4-way shadow.</p>
61         * <p>This special markup is used throughout Ext when box wrapping elements ({@link Ext.Button},
62         * {@link Ext.Panel} when <tt>{@link Ext.Panel#frame frame=true}</tt>, {@link Ext.Window}).  The markup
63         * is of this form:</p>
64         * <pre><code>
65     Ext.Element.boxMarkup =
66     &#39;&lt;div class="{0}-tl">&lt;div class="{0}-tr">&lt;div class="{0}-tc">&lt;/div>&lt;/div>&lt;/div>
67      &lt;div class="{0}-ml">&lt;div class="{0}-mr">&lt;div class="{0}-mc">&lt;/div>&lt;/div>&lt;/div>
68      &lt;div class="{0}-bl">&lt;div class="{0}-br">&lt;div class="{0}-bc">&lt;/div>&lt;/div>&lt;/div>&#39;;
69         * </code></pre>
70         * <p>Example usage:</p>
71         * <pre><code>
72     // Basic box wrap
73     Ext.get("foo").boxWrap();
74
75     // You can also add a custom class and use CSS inheritance rules to customize the box look.
76     // 'x-box-blue' is a built-in alternative -- look at the related CSS definitions as an example
77     // for how to create a custom box wrap style.
78     Ext.get("foo").boxWrap().addClass("x-box-blue");
79         * </code></pre>
80         * @param {String} class (optional) A base CSS class to apply to the containing wrapper element
81         * (defaults to <tt>'x-box'</tt>). Note that there are a number of CSS rules that are dependent on
82         * this name to make the overall effect work, so if you supply an alternate base class, make sure you
83         * also supply all of the necessary rules.
84         * @return {Ext.Element} The outermost wrapping element of the created box structure.
85         */
86         boxWrap : function(cls){
87             cls = cls || 'x-box';
88             var el = Ext.get(this.insertHtml("beforeBegin", "<div class='" + cls + "'>" + String.format(Ext.Element.boxMarkup, cls) + "</div>"));        //String.format('<div class="{0}">'+Ext.Element.boxMarkup+'</div>', cls)));
89             Ext.DomQuery.selectNode('.' + cls + '-mc', el.dom).appendChild(this.dom);
90             return el;
91         },
92
93         /**
94          * Set the size of this Element. If animation is true, both width and height will be animated concurrently.
95          * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
96          * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>
97          * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
98          * <li>A size object in the format <code>{width: widthValue, height: heightValue}</code>.</li>
99          * </ul></div>
100          * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
101          * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels).</li>
102          * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
103          * </ul></div>
104          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
105          * @return {Ext.Element} this
106          */
107         setSize : function(width, height, animate){
108             var me = this;
109             if(typeof width == 'object'){ // in case of object from getSize()
110                 height = width.height;
111                 width = width.width;
112             }
113             width = me.adjustWidth(width);
114             height = me.adjustHeight(height);
115             if(!animate || !me.anim){
116                 me.dom.style.width = me.addUnits(width);
117                 me.dom.style.height = me.addUnits(height);
118             }else{
119                 me.anim({width: {to: width}, height: {to: height}}, me.preanim(arguments, 2));
120             }
121             return me;
122         },
123
124         /**
125          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
126          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
127          * if a height has not been set using CSS.
128          * @return {Number}
129          */
130         getComputedHeight : function(){
131             var me = this,
132                 h = Math.max(me.dom.offsetHeight, me.dom.clientHeight);
133             if(!h){
134                 h = parseFloat(me.getStyle('height')) || 0;
135                 if(!me.isBorderBox()){
136                     h += me.getFrameWidth('tb');
137                 }
138             }
139             return h;
140         },
141
142         /**
143          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
144          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
145          * if a width has not been set using CSS.
146          * @return {Number}
147          */
148         getComputedWidth : function(){
149             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
150             if(!w){
151                 w = parseFloat(this.getStyle('width')) || 0;
152                 if(!this.isBorderBox()){
153                     w += this.getFrameWidth('lr');
154                 }
155             }
156             return w;
157         },
158
159         /**
160          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
161          for more information about the sides.
162          * @param {String} sides
163          * @return {Number}
164          */
165         getFrameWidth : function(sides, onlyContentBox){
166             return onlyContentBox && this.isBorderBox() ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
167         },
168
169         /**
170          * Sets up event handlers to add and remove a css class when the mouse is over this element
171          * @param {String} className
172          * @return {Ext.Element} this
173          */
174         addClassOnOver : function(className){
175             this.hover(
176                 function(){
177                     Ext.fly(this, INTERNAL).addClass(className);
178                 },
179                 function(){
180                     Ext.fly(this, INTERNAL).removeClass(className);
181                 }
182             );
183             return this;
184         },
185
186         /**
187          * Sets up event handlers to add and remove a css class when this element has the focus
188          * @param {String} className
189          * @return {Ext.Element} this
190          */
191         addClassOnFocus : function(className){
192             this.on("focus", function(){
193                 Ext.fly(this, INTERNAL).addClass(className);
194             }, this.dom);
195             this.on("blur", function(){
196                 Ext.fly(this, INTERNAL).removeClass(className);
197             }, this.dom);
198             return this;
199         },
200
201         /**
202          * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
203          * @param {String} className
204          * @return {Ext.Element} this
205          */
206         addClassOnClick : function(className){
207             var dom = this.dom;
208             this.on("mousedown", function(){
209                 Ext.fly(dom, INTERNAL).addClass(className);
210                 var d = Ext.getDoc(),
211                     fn = function(){
212                         Ext.fly(dom, INTERNAL).removeClass(className);
213                         d.removeListener("mouseup", fn);
214                     };
215                 d.on("mouseup", fn);
216             });
217             return this;
218         },
219
220         /**
221          * <p>Returns the dimensions of the element available to lay content out in.<p>
222          * <p>If the element (or any ancestor element) has CSS style <code>display : none</code>, the dimensions will be zero.</p>
223          * example:<pre><code>
224         var vpSize = Ext.getBody().getViewSize();
225
226         // all Windows created afterwards will have a default value of 90% height and 95% width
227         Ext.Window.override({
228             width: vpSize.width * 0.9,
229             height: vpSize.height * 0.95
230         });
231         // To handle window resizing you would have to hook onto onWindowResize.
232         * </code></pre>
233         *
234         * getViewSize utilizes clientHeight/clientWidth which excludes sizing of scrollbars.
235         * To obtain the size including scrollbars, use getStyleSize
236         *
237         * Sizing of the document body is handled at the adapter level which handles special cases for IE and strict modes, etc.
238         */
239
240         getViewSize : function(){
241             var doc = document,
242                 d = this.dom,
243                 isDoc = (d == doc || d == doc.body);
244
245             // If the body, use Ext.lib.Dom
246             if (isDoc) {
247                 var extdom = Ext.lib.Dom;
248                 return {
249                     width : extdom.getViewWidth(),
250                     height : extdom.getViewHeight()
251                 };
252
253             // Else use clientHeight/clientWidth
254             } else {
255                 return {
256                     width : d.clientWidth,
257                     height : d.clientHeight
258                 }
259             }
260         },
261
262         /**
263         * <p>Returns the dimensions of the element available to lay content out in.<p>
264         *
265         * getStyleSize utilizes prefers style sizing if present, otherwise it chooses the larger of offsetHeight/clientHeight and offsetWidth/clientWidth.
266         * To obtain the size excluding scrollbars, use getViewSize
267         *
268         * Sizing of the document body is handled at the adapter level which handles special cases for IE and strict modes, etc.
269         */
270
271         getStyleSize : function(){
272             var me = this,
273                 w, h,
274                 doc = document,
275                 d = this.dom,
276                 isDoc = (d == doc || d == doc.body),
277                 s = d.style;
278
279             // If the body, use Ext.lib.Dom
280             if (isDoc) {
281                 var extdom = Ext.lib.Dom;
282                 return {
283                     width : extdom.getViewWidth(),
284                     height : extdom.getViewHeight()
285                 }
286             }
287             // Use Styles if they are set
288             if(s.width && s.width != 'auto'){
289                 w = parseFloat(s.width);
290                 if(me.isBorderBox()){
291                    w -= me.getFrameWidth('lr');
292                 }
293             }
294             // Use Styles if they are set
295             if(s.height && s.height != 'auto'){
296                 h = parseFloat(s.height);
297                 if(me.isBorderBox()){
298                    h -= me.getFrameWidth('tb');
299                 }
300             }
301             // Use getWidth/getHeight if style not set.
302             return {width: w || me.getWidth(true), height: h || me.getHeight(true)};
303         },
304
305         /**
306          * Returns the size of the element.
307          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
308          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
309          */
310         getSize : function(contentSize){
311             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
312         },
313
314         /**
315          * Forces the browser to repaint this element
316          * @return {Ext.Element} this
317          */
318         repaint : function(){
319             var dom = this.dom;
320             this.addClass("x-repaint");
321             setTimeout(function(){
322                 Ext.fly(dom).removeClass("x-repaint");
323             }, 1);
324             return this;
325         },
326
327         /**
328          * Disables text selection for this element (normalized across browsers)
329          * @return {Ext.Element} this
330          */
331         unselectable : function(){
332             this.dom.unselectable = "on";
333             return this.swallowEvent("selectstart", true).
334                         applyStyles("-moz-user-select:none;-khtml-user-select:none;").
335                         addClass("x-unselectable");
336         },
337
338         /**
339          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
340          * then it returns the calculated width of the sides (see getPadding)
341          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
342          * @return {Object/Number}
343          */
344         getMargins : function(side){
345             var me = this,
346                 key,
347                 hash = {t:"top", l:"left", r:"right", b: "bottom"},
348                 o = {};
349
350             if (!side) {
351                 for (key in me.margins){
352                     o[hash[key]] = parseFloat(me.getStyle(me.margins[key])) || 0;
353                 }
354                 return o;
355             } else {
356                 return me.addStyles.call(me, side, me.margins);
357             }
358         }
359     };
360 }());