Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / src / Shadow.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  * @class Ext.Shadow
17  * Simple class that can provide a shadow effect for any element.  Note that the element MUST be absolutely positioned,
18  * and the shadow does not provide any shimming.  This should be used only in simple cases -- for more advanced
19  * functionality that can also provide the same shadow effect, see the {@link Ext.Layer} class.
20  */
21 Ext.define('Ext.Shadow', {
22     requires: ['Ext.ShadowPool'],
23
24     /**
25      * Creates new Shadow.
26      * @param {Object} config (optional) Config object.
27      */
28     constructor: function(config) {
29         Ext.apply(this, config);
30         if (typeof this.mode != "string") {
31             this.mode = this.defaultMode;
32         }
33         var offset = this.offset,
34             adjusts = {
35                 h: 0
36             },
37             rad = Math.floor(this.offset / 2);
38
39         switch (this.mode.toLowerCase()) {
40             // all this hideous nonsense calculates the various offsets for shadows
41             case "drop":
42                 if (Ext.supports.CSS3BoxShadow) {
43                     adjusts.w = adjusts.h = -offset;
44                     adjusts.l = adjusts.t = offset;
45                 } else {
46                     adjusts.w = 0;
47                     adjusts.l = adjusts.t = offset;
48                     adjusts.t -= 1;
49                     if (Ext.isIE) {
50                         adjusts.l -= offset + rad;
51                         adjusts.t -= offset + rad;
52                         adjusts.w -= rad;
53                         adjusts.h -= rad;
54                         adjusts.t += 1;
55                     }
56                 }
57                 break;
58             case "sides":
59                 if (Ext.supports.CSS3BoxShadow) {
60                     adjusts.h -= offset;
61                     adjusts.t = offset;
62                     adjusts.l = adjusts.w = 0;
63                 } else {
64                     adjusts.w = (offset * 2);
65                     adjusts.l = -offset;
66                     adjusts.t = offset - 1;
67                     if (Ext.isIE) {
68                         adjusts.l -= (offset - rad);
69                         adjusts.t -= offset + rad;
70                         adjusts.l += 1;
71                         adjusts.w -= (offset - rad) * 2;
72                         adjusts.w -= rad + 1;
73                         adjusts.h -= 1;
74                     }
75                 }
76                 break;
77             case "frame":
78                 if (Ext.supports.CSS3BoxShadow) {
79                     adjusts.l = adjusts.w = adjusts.t = 0;
80                 } else {
81                     adjusts.w = adjusts.h = (offset * 2);
82                     adjusts.l = adjusts.t = -offset;
83                     adjusts.t += 1;
84                     adjusts.h -= 2;
85                     if (Ext.isIE) {
86                         adjusts.l -= (offset - rad);
87                         adjusts.t -= (offset - rad);
88                         adjusts.l += 1;
89                         adjusts.w -= (offset + rad + 1);
90                         adjusts.h -= (offset + rad);
91                         adjusts.h += 1;
92                     }
93                     break;
94                 }
95         }
96         this.adjusts = adjusts;
97     },
98
99     /**
100      * @cfg {String} mode
101      * The shadow display mode.  Supports the following options:<div class="mdetail-params"><ul>
102      * <li><b><tt>sides</tt></b> : Shadow displays on both sides and bottom only</li>
103      * <li><b><tt>frame</tt></b> : Shadow displays equally on all four sides</li>
104      * <li><b><tt>drop</tt></b> : Traditional bottom-right drop shadow</li>
105      * </ul></div>
106      */
107     /**
108      * @cfg {String} offset
109      * The number of pixels to offset the shadow from the element (defaults to <tt>4</tt>)
110      */
111     offset: 4,
112
113     // private
114     defaultMode: "drop",
115
116     /**
117      * Displays the shadow under the target element
118      * @param {Mixed} targetEl The id or element under which the shadow should display
119      */
120     show: function(target) {
121         target = Ext.get(target);
122         if (!this.el) {
123             this.el = Ext.ShadowPool.pull();
124             if (this.el.dom.nextSibling != target.dom) {
125                 this.el.insertBefore(target);
126             }
127         }
128         this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10) - 1);
129         if (Ext.isIE && !Ext.supports.CSS3BoxShadow) {
130             this.el.dom.style.filter = "progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius=" + (this.offset) + ")";
131         }
132         this.realign(
133             target.getLeft(true),
134             target.getTop(true),
135             target.getWidth(),
136             target.getHeight()
137         );
138         this.el.dom.style.display = "block";
139     },
140
141     /**
142      * Returns true if the shadow is visible, else false
143      */
144     isVisible: function() {
145         return this.el ? true: false;
146     },
147
148     /**
149      * Direct alignment when values are already available. Show must be called at least once before
150      * calling this method to ensure it is initialized.
151      * @param {Number} left The target element left position
152      * @param {Number} top The target element top position
153      * @param {Number} width The target element width
154      * @param {Number} height The target element height
155      */
156     realign: function(l, t, targetWidth, targetHeight) {
157         if (!this.el) {
158             return;
159         }
160         var adjusts = this.adjusts,
161             d = this.el.dom,
162             targetStyle = d.style,
163             shadowWidth,
164             shadowHeight,
165             cn,
166             sww, 
167             sws, 
168             shs;
169
170         targetStyle.left = (l + adjusts.l) + "px";
171         targetStyle.top = (t + adjusts.t) + "px";
172         shadowWidth = Math.max(targetWidth + adjusts.w, 0);
173         shadowHeight = Math.max(targetHeight + adjusts.h, 0);
174         sws = shadowWidth + "px";
175         shs = shadowHeight + "px";
176         if (targetStyle.width != sws || targetStyle.height != shs) {
177             targetStyle.width = sws;
178             targetStyle.height = shs;
179             if (Ext.supports.CSS3BoxShadow) {
180                 targetStyle.boxShadow = '0 0 ' + this.offset + 'px 0 #888';
181             } else {
182
183                 // Adjust the 9 point framed element to poke out on the required sides
184                 if (!Ext.isIE) {
185                     cn = d.childNodes;
186                     sww = Math.max(0, (shadowWidth - 12)) + "px";
187                     cn[0].childNodes[1].style.width = sww;
188                     cn[1].childNodes[1].style.width = sww;
189                     cn[2].childNodes[1].style.width = sww;
190                     cn[1].style.height = Math.max(0, (shadowHeight - 12)) + "px";
191                 }
192             }
193         }
194     },
195
196     /**
197      * Hides this shadow
198      */
199     hide: function() {
200         if (this.el) {
201             this.el.dom.style.display = "none";
202             Ext.ShadowPool.push(this.el);
203             delete this.el;
204         }
205     },
206
207     /**
208      * Adjust the z-index of this shadow
209      * @param {Number} zindex The new z-index
210      */
211     setZIndex: function(z) {
212         this.zIndex = z;
213         if (this.el) {
214             this.el.setStyle("z-index", z);
215         }
216     }
217 });