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