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