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