source: trunk/web/addons/job_monarch/lib/extjs-30/src/core/core/Fx.js @ 625

Last change on this file since 625 was 625, checked in by ramonb, 15 years ago

lib/extjs-30:

  • new ExtJS 3.0
File size: 39.2 KB
Line 
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(function(){
8    // contants
9    var NULL = null,
10        UNDEFINED = undefined,
11        TRUE = true,
12        FALSE = false,
13        SETX = "setX",
14        SETY = "setY",
15        SETXY = "setXY",
16        LEFT = "left",
17        BOTTOM = "bottom",
18        TOP = "top",
19        RIGHT = "right",
20        HEIGHT = "height",
21        WIDTH = "width",
22        POINTS = "points",
23        HIDDEN = "hidden",
24        ABSOLUTE = "absolute",
25        VISIBLE = "visible",
26        MOTION = "motion",
27        POSITION = "position",
28        EASEOUT = "easeOut",
29        /*
30         * Use a light flyweight here since we are using so many callbacks and are always assured a DOM element
31         */
32        flyEl = new Ext.Element.Flyweight(),
33        queues = {},
34        getObject = function(o){
35            return o || {};
36        },
37        fly = function(dom){
38            flyEl.dom = dom;
39            flyEl.id = Ext.id(dom);
40            return flyEl;
41        },
42        /*
43         * Queueing now stored outside of the element due to closure issues
44         */
45        getQueue = function(id){
46            if(!queues[id]){
47                queues[id] = [];
48            }
49            return queues[id];
50        },
51        setQueue = function(id, value){
52            queues[id] = value;
53        };
54       
55//Notifies Element that fx methods are available
56Ext.enableFx = TRUE;
57
58/**
59 * @class Ext.Fx
60 * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
61 * to the {@link Ext.Element} interface when included, so all effects calls should be performed via {@link Ext.Element}.
62 * Conversely, since the effects are not actually defined in {@link Ext.Element}, Ext.Fx <b>must</b> be
63 * {@link Ext#enableFx included} in order for the Element effects to work.</p><br/>
64 *
65 * <p><b><u>Method Chaining</u></b></p>
66 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
67 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
68 * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
69 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
70 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
71 * expected results and should be done with care.  Also see <tt>{@link #callback}</tt>.</p><br/>
72 *
73 * <p><b><u>Anchor Options for Motion Effects</u></b></p>
74 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
75 * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
76<pre>
77Value  Description
78-----  -----------------------------
79tl     The top left corner
80t      The center of the top edge
81tr     The top right corner
82l      The center of the left edge
83r      The center of the right edge
84bl     The bottom left corner
85b      The center of the bottom edge
86br     The bottom right corner
87</pre>
88 * <b>Note</b>: some Fx methods accept specific custom config parameters.  The options shown in the Config Options
89 * section below are common options that can be passed to any Fx method unless otherwise noted.</b>
90 *
91 * @cfg {Function} callback A function called when the effect is finished.  Note that effects are queued internally by the
92 * Fx class, so a callback is not required to specify another effect -- effects can simply be chained together
93 * and called in sequence (see note for <b><u>Method Chaining</u></b> above), for example:<pre><code>
94 * el.slideIn().highlight();
95 * </code></pre>
96 * The callback is intended for any additional code that should run once a particular effect has completed. The Element
97 * being operated upon is passed as the first parameter.
98 *
99 * @cfg {Object} scope The scope of the <tt>{@link #callback}</tt> function
100 *
101 * @cfg {String} easing A valid Ext.lib.Easing value for the effect:</p><div class="mdetail-params"><ul>
102 * <li><b><tt>backBoth</tt></b></li>
103 * <li><b><tt>backIn</tt></b></li>
104 * <li><b><tt>backOut</tt></b></li>
105 * <li><b><tt>bounceBoth</tt></b></li>
106 * <li><b><tt>bounceIn</tt></b></li>
107 * <li><b><tt>bounceOut</tt></b></li>
108 * <li><b><tt>easeBoth</tt></b></li>
109 * <li><b><tt>easeBothStrong</tt></b></li>
110 * <li><b><tt>easeIn</tt></b></li>
111 * <li><b><tt>easeInStrong</tt></b></li>
112 * <li><b><tt>easeNone</tt></b></li>
113 * <li><b><tt>easeOut</tt></b></li>
114 * <li><b><tt>easeOutStrong</tt></b></li>
115 * <li><b><tt>elasticBoth</tt></b></li>
116 * <li><b><tt>elasticIn</tt></b></li>
117 * <li><b><tt>elasticOut</tt></b></li>
118 * </ul></div>
119 *
120 * @cfg {String} afterCls A css class to apply after the effect
121 * @cfg {Number} duration The length of time (in seconds) that the effect should last
122 *
123 * @cfg {Number} endOpacity Only applicable for {@link #fadeIn} or {@link #fadeOut}, a number between
124 * <tt>0</tt> and <tt>1</tt> inclusive to configure the ending opacity value.
125 * 
126 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
127 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
128 * effects that end with the element being visually hidden, ignored otherwise)
129 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. <tt>"width:100px"</tt>, or an object
130 * in the form <tt>{width:"100px"}</tt>, or a function which returns such a specification that will be applied to the
131 * Element after the effect finishes.
132 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
133 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
134 * @cfg {Boolean} stopFx Whether preceding effects should be stopped and removed before running current effect (only applies to non blocking effects)
135 */
136Ext.Fx = {
137   
138    // private - calls the function taking arguments from the argHash based on the key.  Returns the return value of the function.
139    //           this is useful for replacing switch statements (for example).
140    switchStatements : function(key, fn, argHash){
141        return fn.apply(this, argHash[key]);
142    },
143   
144    /**
145     * Slides the element into view.  An anchor point can be optionally passed to set the point of
146     * origin for the slide effect.  This function automatically handles wrapping the element with
147     * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
148     * Usage:
149     *<pre><code>
150// default: slide the element in from the top
151el.slideIn();
152
153// custom: slide the element in from the right with a 2-second duration
154el.slideIn('r', { duration: 2 });
155
156// common config options shown with default values
157el.slideIn('t', {
158    easing: 'easeOut',
159    duration: .5
160});
161</code></pre>
162     * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
163     * @param {Object} options (optional) Object literal with any of the Fx config options
164     * @return {Ext.Element} The Element
165     */
166    slideIn : function(anchor, o){ 
167        o = getObject(o);
168        var me = this,
169            dom = me.dom,
170            st = dom.style,
171            xy,
172            r,
173            b,             
174            wrap,               
175            after,
176            st,
177            args, 
178            pt,
179            bw,
180            bh;
181           
182        anchor = anchor || "t";
183
184        me.queueFx(o, function(){           
185            xy = fly(dom).getXY();
186            // fix display to visibility
187            fly(dom).fixDisplay();           
188           
189            // restore values after effect
190            r = fly(dom).getFxRestore();     
191            b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight};
192            b.right = b.x + b.width;
193            b.bottom = b.y + b.height;
194           
195            // fixed size for slide
196            fly(dom).setWidth(b.width).setHeight(b.height);           
197           
198            // wrap if needed
199            wrap = fly(dom).fxWrap(r.pos, o, HIDDEN);
200           
201            st.visibility = VISIBLE;
202            st.position = ABSOLUTE;
203           
204            // clear out temp styles after slide and unwrap
205            function after(){
206                 fly(dom).fxUnwrap(wrap, r.pos, o);
207                 st.width = r.width;
208                 st.height = r.height;
209                 fly(dom).afterFx(o);
210            }
211           
212            // time to calculate the positions       
213            pt = {to: [b.x, b.y]}; 
214            bw = {to: b.width};
215            bh = {to: b.height};
216               
217            function argCalc(wrap, style, ww, wh, sXY, sXYval, s1, s2, w, h, p){                   
218                var ret = {};
219                fly(wrap).setWidth(ww).setHeight(wh);
220                if(fly(wrap)[sXY]){
221                    fly(wrap)[sXY](sXYval);                 
222                }
223                style[s1] = style[s2] = "0";                   
224                if(w){
225                    ret.width = w
226                };
227                if(h){
228                    ret.height = h;
229                }
230                if(p){
231                    ret.points = p;
232                }
233                return ret;
234            };
235
236            args = fly(dom).switchStatements(anchor.toLowerCase(), argCalc, {
237                    t  : [wrap, st, b.width, 0, NULL, NULL, LEFT, BOTTOM, NULL, bh, NULL],
238                    l  : [wrap, st, 0, b.height, NULL, NULL, RIGHT, TOP, bw, NULL, NULL],
239                    r  : [wrap, st, b.width, b.height, SETX, b.right, LEFT, TOP, NULL, NULL, pt],
240                    b  : [wrap, st, b.width, b.height, SETY, b.bottom, LEFT, TOP, NULL, bh, pt],
241                    tl : [wrap, st, 0, 0, NULL, NULL, RIGHT, BOTTOM, bw, bh, pt],
242                    bl : [wrap, st, 0, 0, SETY, b.y + b.height, RIGHT, TOP, bw, bh, pt],
243                    br : [wrap, st, 0, 0, SETXY, [b.right, b.bottom], LEFT, TOP, bw, bh, pt],
244                    tr : [wrap, st, 0, 0, SETX, b.x + b.width, LEFT, BOTTOM, bw, bh, pt]
245                });
246           
247            st.visibility = VISIBLE;
248            fly(wrap).show();
249
250            arguments.callee.anim = fly(wrap).fxanim(args,
251                o,
252                MOTION,
253                .5,
254                EASEOUT, 
255                after);
256        });
257        return me;
258    },
259   
260    /**
261     * Slides the element out of view.  An anchor point can be optionally passed to set the end point
262     * for the slide effect.  When the effect is completed, the element will be hidden (visibility =
263     * 'hidden') but block elements will still take up space in the document.  The element must be removed
264     * from the DOM using the 'remove' config option if desired.  This function automatically handles
265     * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
266     * Usage:
267     *<pre><code>
268// default: slide the element out to the top
269el.slideOut();
270
271// custom: slide the element out to the right with a 2-second duration
272el.slideOut('r', { duration: 2 });
273
274// common config options shown with default values
275el.slideOut('t', {
276    easing: 'easeOut',
277    duration: .5,
278    remove: false,
279    useDisplay: false
280});
281</code></pre>
282     * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
283     * @param {Object} options (optional) Object literal with any of the Fx config options
284     * @return {Ext.Element} The Element
285     */
286    slideOut : function(anchor, o){
287        o = getObject(o);
288        var me = this,
289            dom = me.dom,
290            st = dom.style,
291            xy = me.getXY(),
292            wrap,
293            r,
294            b,
295            a,
296            zero = {to: 0}; 
297                   
298        anchor = anchor || "t";
299
300        me.queueFx(o, function(){
301           
302            // restore values after effect
303            r = fly(dom).getFxRestore(); 
304            b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight};
305            b.right = b.x + b.width;
306            b.bottom = b.y + b.height;
307               
308            // fixed size for slide   
309            fly(dom).setWidth(b.width).setHeight(b.height);
310
311            // wrap if needed
312            wrap = fly(dom).fxWrap(r.pos, o, VISIBLE);
313               
314            st.visibility = VISIBLE;
315            st.position = ABSOLUTE;
316            fly(wrap).setWidth(b.width).setHeight(b.height);           
317
318            function after(){
319                o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();               
320                fly(dom).fxUnwrap(wrap, r.pos, o);
321                st.width = r.width;
322                st.height = r.height;
323                fly(dom).afterFx(o);
324            }           
325           
326            function argCalc(style, s1, s2, p1, v1, p2, v2, p3, v3){                   
327                var ret = {};
328               
329                style[s1] = style[s2] = "0";
330                ret[p1] = v1;               
331                if(p2){
332                    ret[p2] = v2;               
333                }
334                if(p3){
335                    ret[p3] = v3;
336                }
337               
338                return ret;
339            };
340           
341            a = fly(dom).switchStatements(anchor.toLowerCase(), argCalc, {
342                t  : [st, LEFT, BOTTOM, HEIGHT, zero],
343                l  : [st, RIGHT, TOP, WIDTH, zero],
344                r  : [st, LEFT, TOP, WIDTH, zero, POINTS, {to : [b.right, b.y]}],
345                b  : [st, LEFT, TOP, HEIGHT, zero, POINTS, {to : [b.x, b.bottom]}],
346                tl : [st, RIGHT, BOTTOM, WIDTH, zero, HEIGHT, zero],
347                bl : [st, RIGHT, TOP, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.x, b.bottom]}],
348                br : [st, LEFT, TOP, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.x + b.width, b.bottom]}],
349                tr : [st, LEFT, BOTTOM, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.right, b.y]}]
350            });
351           
352            arguments.callee.anim = fly(wrap).fxanim(a,
353                o,
354                MOTION,
355                .5,
356                EASEOUT, 
357                after);
358        });
359        return me;
360    },
361
362    /**
363     * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the
364     * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
365     * The element must be removed from the DOM using the 'remove' config option if desired.
366     * Usage:
367     *<pre><code>
368// default
369el.puff();
370
371// common config options shown with default values
372el.puff({
373    easing: 'easeOut',
374    duration: .5,
375    remove: false,
376    useDisplay: false
377});
378</code></pre>
379     * @param {Object} options (optional) Object literal with any of the Fx config options
380     * @return {Ext.Element} The Element
381     */
382    puff : function(o){
383        o = getObject(o);
384        var me = this,
385            dom = me.dom,
386            st = dom.style,
387            width,
388            height,
389            r;
390
391        me.queueFx(o, function(){
392            width = fly(dom).getWidth();
393            height = fly(dom).getHeight();
394            fly(dom).clearOpacity();
395            fly(dom).show();
396
397            // restore values after effect
398            r = fly(dom).getFxRestore();                   
399           
400            function after(){
401                o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();                 
402                fly(dom).clearOpacity(); 
403                fly(dom).setPositioning(r.pos);
404                st.width = r.width;
405                st.height = r.height;
406                st.fontSize = '';
407                fly(dom).afterFx(o);
408            }   
409
410            arguments.callee.anim = fly(dom).fxanim({
411                    width : {to : fly(dom).adjustWidth(width * 2)},
412                    height : {to : fly(dom).adjustHeight(height * 2)},
413                    points : {by : [-width * .5, -height * .5]},
414                    opacity : {to : 0},
415                    fontSize: {to : 200, unit: "%"}
416                },
417                o,
418                MOTION,
419                .5,
420                EASEOUT,
421                 after);
422        });
423        return me;
424    },
425
426    /**
427     * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
428     * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
429     * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
430     * Usage:
431     *<pre><code>
432// default
433el.switchOff();
434
435// all config options shown with default values
436el.switchOff({
437    easing: 'easeIn',
438    duration: .3,
439    remove: false,
440    useDisplay: false
441});
442</code></pre>
443     * @param {Object} options (optional) Object literal with any of the Fx config options
444     * @return {Ext.Element} The Element
445     */
446    switchOff : function(o){
447        o = getObject(o);
448        var me = this,
449            dom = me.dom,
450            st = dom.style,
451            r;
452
453        me.queueFx(o, function(){
454            fly(dom).clearOpacity();
455            fly(dom).clip();
456
457            // restore values after effect
458            r = fly(dom).getFxRestore();
459               
460            function after(){
461                o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide(); 
462                fly(dom).clearOpacity();
463                fly(dom).setPositioning(r.pos);
464                st.width = r.width;
465                st.height = r.height;   
466                fly(dom).afterFx(o);
467            };
468
469            fly(dom).fxanim({opacity : {to : 0.3}}, 
470                NULL, 
471                NULL, 
472                .1, 
473                NULL, 
474                function(){                                 
475                    fly(dom).clearOpacity();
476                        (function(){                           
477                            fly(dom).fxanim({
478                                height : {to : 1},
479                                points : {by : [0, fly(dom).getHeight() * .5]}
480                            }, 
481                            o, 
482                            MOTION, 
483                            0.3, 
484                            'easeIn', 
485                            after);
486                        }).defer(100);
487                });
488        });
489        return me;
490    },
491
492    /**
493     * Highlights the Element by setting a color (applies to the background-color by default, but can be
494     * changed using the "attr" config option) and then fading back to the original color. If no original
495     * color is available, you should provide the "endColor" config option which will be cleared after the animation.
496     * Usage:
497<pre><code>
498// default: highlight background to yellow
499el.highlight();
500
501// custom: highlight foreground text to blue for 2 seconds
502el.highlight("0000ff", { attr: 'color', duration: 2 });
503
504// common config options shown with default values
505el.highlight("ffff9c", {
506    attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
507    endColor: (current color) or "ffffff",
508    easing: 'easeIn',
509    duration: 1
510});
511</code></pre>
512     * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
513     * @param {Object} options (optional) Object literal with any of the Fx config options
514     * @return {Ext.Element} The Element
515     */ 
516    highlight : function(color, o){
517        o = getObject(o);
518        var me = this,
519            dom = me.dom,
520            attr = o.attr || "backgroundColor",
521            a = {},
522            restore;
523
524        me.queueFx(o, function(){
525            fly(dom).clearOpacity();
526            fly(dom).show();
527
528            function after(){
529                dom.style[attr] = restore;
530                fly(dom).afterFx(o);
531            }           
532            restore = dom.style[attr];
533            a[attr] = {from: color || "ffff9c", to: o.endColor || fly(dom).getColor(attr) || "ffffff"};
534            arguments.callee.anim = fly(dom).fxanim(a,
535                o,
536                'color',
537                1,
538                'easeIn', 
539                after);
540        });
541        return me;
542    },
543
544   /**
545    * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
546    * Usage:
547<pre><code>
548// default: a single light blue ripple
549el.frame();
550
551// custom: 3 red ripples lasting 3 seconds total
552el.frame("ff0000", 3, { duration: 3 });
553
554// common config options shown with default values
555el.frame("C3DAF9", 1, {
556    duration: 1 //duration of each individual ripple.
557    // Note: Easing is not configurable and will be ignored if included
558});
559</code></pre>
560    * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
561    * @param {Number} count (optional) The number of ripples to display (defaults to 1)
562    * @param {Object} options (optional) Object literal with any of the Fx config options
563    * @return {Ext.Element} The Element
564    */
565    frame : function(color, count, o){
566        o = getObject(o);
567        var me = this,
568            dom = me.dom,
569            proxy,
570            active;
571
572        me.queueFx(o, function(){
573            color = color || "#C3DAF9"
574            if(color.length == 6){
575                color = "#" + color;
576            }           
577            count = count || 1;
578            fly(dom).show();
579
580            var xy = fly(dom).getXY(),
581                b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight},
582                queue = function(){
583                    proxy = fly(document.body || document.documentElement).createChild({
584                        style:{
585                            visbility: HIDDEN,
586                            position : ABSOLUTE,
587                            "z-index": 35000, // yee haw
588                            border : "0px solid " + color
589                        }
590                    });
591                    return proxy.queueFx({}, animFn);
592                };
593           
594           
595            arguments.callee.anim = {
596                isAnimated: true,
597                stop: function() {
598                    count = 0;
599                    proxy.stopFx();
600                }
601            };
602           
603            function animFn(){
604                var scale = Ext.isBorderBox ? 2 : 1;
605                active = proxy.anim({
606                    top : {from : b.y, to : b.y - 20},
607                    left : {from : b.x, to : b.x - 20},
608                    borderWidth : {from : 0, to : 10},
609                    opacity : {from : 1, to : 0},
610                    height : {from : b.height, to : b.height + 20 * scale},
611                    width : {from : b.width, to : b.width + 20 * scale}
612                },{
613                    duration: o.duration || 1,
614                    callback: function() {
615                        proxy.remove();
616                        --count > 0 ? queue() : fly(dom).afterFx(o);
617                    }
618                });
619                arguments.callee.anim = {
620                    isAnimated: true,
621                    stop: function(){
622                        active.stop();
623                    }
624                };
625            };
626            queue();
627        });
628        return me;
629    },
630
631   /**
632    * Creates a pause before any subsequent queued effects begin.  If there are
633    * no effects queued after the pause it will have no effect.
634    * Usage:
635<pre><code>
636el.pause(1);
637</code></pre>
638    * @param {Number} seconds The length of time to pause (in seconds)
639    * @return {Ext.Element} The Element
640    */
641    pause : function(seconds){       
642        var dom = this.dom,
643            t;
644
645        this.queueFx({}, function(){
646            t = setTimeout(function(){
647                fly(dom).afterFx({});
648            }, seconds * 1000);
649            arguments.callee.anim = {
650                isAnimated: true,
651                stop: function(){
652                    clearTimeout(t);
653                    fly(dom).afterFx({});
654                }
655            };
656        });
657        return this;
658    },
659
660   /**
661    * Fade an element in (from transparent to opaque).  The ending opacity can be specified
662    * using the <tt>{@link #endOpacity}</tt> config option.
663    * Usage:
664<pre><code>
665// default: fade in from opacity 0 to 100%
666el.fadeIn();
667
668// custom: fade in from opacity 0 to 75% over 2 seconds
669el.fadeIn({ endOpacity: .75, duration: 2});
670
671// common config options shown with default values
672el.fadeIn({
673    endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
674    easing: 'easeOut',
675    duration: .5
676});
677</code></pre>
678    * @param {Object} options (optional) Object literal with any of the Fx config options
679    * @return {Ext.Element} The Element
680    */
681    fadeIn : function(o){
682        o = getObject(o);
683        var me = this,
684            dom = me.dom,
685            to = o.endOpacity || 1;
686       
687        me.queueFx(o, function(){
688            fly(dom).setOpacity(0);
689            fly(dom).fixDisplay();
690            dom.style.visibility = VISIBLE;
691            arguments.callee.anim = fly(dom).fxanim({opacity:{to:to}},
692                o, NULL, .5, EASEOUT, function(){
693                if(to == 1){
694                    fly(dom).clearOpacity();
695                }
696                fly(dom).afterFx(o);
697            });
698        });
699        return me;
700    },
701
702   /**
703    * Fade an element out (from opaque to transparent).  The ending opacity can be specified
704    * using the <tt>{@link #endOpacity}</tt> config option.  Note that IE may require
705    * <tt>{@link #useDisplay}:true</tt> in order to redisplay correctly.
706    * Usage:
707<pre><code>
708// default: fade out from the element's current opacity to 0
709el.fadeOut();
710
711// custom: fade out from the element's current opacity to 25% over 2 seconds
712el.fadeOut({ endOpacity: .25, duration: 2});
713
714// common config options shown with default values
715el.fadeOut({
716    endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
717    easing: 'easeOut',
718    duration: .5,
719    remove: false,
720    useDisplay: false
721});
722</code></pre>
723    * @param {Object} options (optional) Object literal with any of the Fx config options
724    * @return {Ext.Element} The Element
725    */
726    fadeOut : function(o){
727        o = getObject(o);
728        var me = this,
729            dom = me.dom,
730            style = dom.style,
731            to = o.endOpacity || 0;         
732       
733        me.queueFx(o, function(){ 
734            arguments.callee.anim = fly(dom).fxanim({ 
735                opacity : {to : to}},
736                o, 
737                NULL, 
738                .5, 
739                EASEOUT, 
740                function(){
741                    if(to == 0){
742                        Ext.Element.data(dom, 'visibilityMode') == Ext.Element.DISPLAY || o.useDisplay ? 
743                            style.display = "none" :
744                            style.visibility = HIDDEN;
745                           
746                        fly(dom).clearOpacity();
747                    }
748                    fly(dom).afterFx(o);
749            });
750        });
751        return me;
752    },
753
754   /**
755    * Animates the transition of an element's dimensions from a starting height/width
756    * to an ending height/width.  This method is a convenience implementation of {@link shift}.
757    * Usage:
758<pre><code>
759// change height and width to 100x100 pixels
760el.scale(100, 100);
761
762// common config options shown with default values.  The height and width will default to
763// the element&#39;s existing values if passed as null.
764el.scale(
765    [element&#39;s width],
766    [element&#39;s height], {
767        easing: 'easeOut',
768        duration: .35
769    }
770);
771</code></pre>
772    * @param {Number} width  The new width (pass undefined to keep the original width)
773    * @param {Number} height  The new height (pass undefined to keep the original height)
774    * @param {Object} options (optional) Object literal with any of the Fx config options
775    * @return {Ext.Element} The Element
776    */
777    scale : function(w, h, o){
778        this.shift(Ext.apply({}, o, {
779            width: w,
780            height: h
781        }));
782        return this;
783    },
784
785   /**
786    * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
787    * Any of these properties not specified in the config object will not be changed.  This effect
788    * requires that at least one new dimension, position or opacity setting must be passed in on
789    * the config object in order for the function to have any effect.
790    * Usage:
791<pre><code>
792// slide the element horizontally to x position 200 while changing the height and opacity
793el.shift({ x: 200, height: 50, opacity: .8 });
794
795// common config options shown with default values.
796el.shift({
797    width: [element&#39;s width],
798    height: [element&#39;s height],
799    x: [element&#39;s x position],
800    y: [element&#39;s y position],
801    opacity: [element&#39;s opacity],
802    easing: 'easeOut',
803    duration: .35
804});
805</code></pre>
806    * @param {Object} options  Object literal with any of the Fx config options
807    * @return {Ext.Element} The Element
808    */
809    shift : function(o){
810        o = getObject(o);
811        var dom = this.dom,
812            a = {};
813               
814        this.queueFx(o, function(){
815            for (var prop in o) {
816                if (o[prop] != UNDEFINED) {                                                 
817                    a[prop] = {to : o[prop]};                   
818                }
819            } 
820           
821            a.width ? a.width.to = fly(dom).adjustWidth(o.width) : a;
822            a.height ? a.height.to = fly(dom).adjustWidth(o.height) : a;   
823           
824            if (a.x || a.y || a.xy) {
825                a.points = a.xy || 
826                           {to : [ a.x ? a.x.to : fly(dom).getX(),
827                                   a.y ? a.y.to : fly(dom).getY()]};                 
828            }
829
830            arguments.callee.anim = fly(dom).fxanim(a,
831                o, 
832                MOTION, 
833                .35, 
834                EASEOUT, 
835                function(){
836                    fly(dom).afterFx(o);
837                });
838        });
839        return this;
840    },
841
842    /**
843     * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the
844     * ending point of the effect.
845     * Usage:
846     *<pre><code>
847// default: slide the element downward while fading out
848el.ghost();
849
850// custom: slide the element out to the right with a 2-second duration
851el.ghost('r', { duration: 2 });
852
853// common config options shown with default values
854el.ghost('b', {
855    easing: 'easeOut',
856    duration: .5,
857    remove: false,
858    useDisplay: false
859});
860</code></pre>
861     * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
862     * @param {Object} options (optional) Object literal with any of the Fx config options
863     * @return {Ext.Element} The Element
864     */
865    ghost : function(anchor, o){
866        o = getObject(o);
867        var me = this,
868            dom = me.dom,
869            st = dom.style,
870            a = {opacity: {to: 0}, points: {}},
871            pt = a.points,
872            r,
873            w,
874            h;
875           
876        anchor = anchor || "b";
877
878        me.queueFx(o, function(){
879            // restore values after effect
880            r = fly(dom).getFxRestore();
881            w = fly(dom).getWidth();
882            h = fly(dom).getHeight();
883           
884            function after(){
885                o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();   
886                fly(dom).clearOpacity();
887                fly(dom).setPositioning(r.pos);
888                st.width = r.width;
889                st.height = r.height;
890                fly(dom).afterFx(o);
891            }
892               
893            pt.by = fly(dom).switchStatements(anchor.toLowerCase(), function(v1,v2){ return [v1, v2];}, {
894               t  : [0, -h],
895               l  : [-w, 0],
896               r  : [w, 0],
897               b  : [0, h],
898               tl : [-w, -h],
899               bl : [-w, h],
900               br : [w, h],
901               tr : [w, -h] 
902            });
903               
904            arguments.callee.anim = fly(dom).fxanim(a,
905                o,
906                MOTION,
907                .5,
908                EASEOUT, after);
909        });
910        return me;
911    },
912
913    /**
914     * Ensures that all effects queued after syncFx is called on the element are
915     * run concurrently.  This is the opposite of {@link #sequenceFx}.
916     * @return {Ext.Element} The Element
917     */
918    syncFx : function(){
919        var me = this;
920        me.fxDefaults = Ext.apply(me.fxDefaults || {}, {
921            block : FALSE,
922            concurrent : TRUE,
923            stopFx : FALSE
924        });
925        return me;
926    },
927
928    /**
929     * Ensures that all effects queued after sequenceFx is called on the element are
930     * run in sequence.  This is the opposite of {@link #syncFx}.
931     * @return {Ext.Element} The Element
932     */
933    sequenceFx : function(){
934        var me = this;
935        me.fxDefaults = Ext.apply(me.fxDefaults || {}, {
936            block : FALSE,
937            concurrent : FALSE,
938            stopFx : FALSE
939        });
940        return me;
941    },
942
943    /* @private */
944    nextFx : function(){       
945        var ef = getQueue(this.dom.id)[0];
946        if(ef){
947            ef.call(this);
948        }
949    },
950
951    /**
952     * Returns true if the element has any effects actively running or queued, else returns false.
953     * @return {Boolean} True if element has active effects, else false
954     */
955    hasActiveFx : function(){
956        return getQueue(this.dom.id)[0];
957    },
958
959    /**
960     * Stops any running effects and clears the element's internal effects queue if it contains
961     * any additional effects that haven't started yet.
962     * @return {Ext.Element} The Element
963     */
964    stopFx : function(finish){
965        var me = this,
966            id = me.dom.id;
967        if(me.hasActiveFx()){
968            var cur = getQueue(id)[0];
969            if(cur && cur.anim){
970                if(cur.anim.isAnimated){
971                    setQueue(id, [cur]); //clear
972                    cur.anim.stop(finish !== undefined ? finish : TRUE);
973                }else{
974                    setQueue(id, []);
975                }
976            }
977        }
978        return me;
979    },
980
981    /* @private */
982    beforeFx : function(o){
983        if(this.hasActiveFx() && !o.concurrent){
984           if(o.stopFx){
985               this.stopFx();
986               return TRUE;
987           }
988           return FALSE;
989        }
990        return TRUE;
991    },
992
993    /**
994     * Returns true if the element is currently blocking so that no other effect can be queued
995     * until this effect is finished, else returns false if blocking is not set.  This is commonly
996     * used to ensure that an effect initiated by a user action runs to completion prior to the
997     * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
998     * @return {Boolean} True if blocking, else false
999     */
1000    hasFxBlock : function(){
1001        var q = getQueue(this.dom.id);
1002        return q && q[0] && q[0].block;
1003    },
1004
1005    /* @private */
1006    queueFx : function(o, fn){
1007        var me = this;
1008        if(!me.hasFxBlock()){
1009            Ext.applyIf(o, me.fxDefaults);
1010            if(!o.concurrent){
1011                var run = me.beforeFx(o);
1012                fn.block = o.block;
1013                getQueue(me.dom.id).push(fn);
1014                if(run){
1015                    me.nextFx();
1016                }
1017            }else{
1018                fn.call(me);
1019            }
1020        }
1021        return me;
1022    },
1023
1024    /* @private */
1025    fxWrap : function(pos, o, vis){ 
1026        var dom = this.dom,
1027            wrap,
1028            wrapXY;
1029        if(!o.wrap || !(wrap = Ext.getDom(o.wrap))){           
1030            if(o.fixPosition){
1031                wrapXY = fly(dom).getXY();
1032            }
1033            var div = document.createElement("div");
1034            div.style.visibility = vis;
1035            wrap = dom.parentNode.insertBefore(div, dom);
1036            fly(wrap).setPositioning(pos);
1037            if(fly(wrap).isStyle(POSITION, "static")){
1038                fly(wrap).position("relative");
1039            }
1040            fly(dom).clearPositioning('auto');
1041            fly(wrap).clip();
1042            wrap.appendChild(dom);
1043            if(wrapXY){
1044                fly(wrap).setXY(wrapXY);
1045            }
1046        }
1047        return wrap;
1048    },
1049
1050    /* @private */
1051    fxUnwrap : function(wrap, pos, o){     
1052        var dom = this.dom;
1053        fly(dom).clearPositioning();
1054        fly(dom).setPositioning(pos);
1055        if(!o.wrap){
1056            wrap.parentNode.insertBefore(dom, wrap);
1057            fly(wrap).remove();
1058        }
1059    },
1060
1061    /* @private */
1062    getFxRestore : function(){
1063        var st = this.dom.style;
1064        return {pos: this.getPositioning(), width: st.width, height : st.height};
1065    },
1066
1067    /* @private */
1068    afterFx : function(o){
1069        var dom = this.dom,
1070            id = dom.id,
1071            notConcurrent = !o.concurrent;
1072        if(o.afterStyle){
1073            fly(dom).setStyle(o.afterStyle);           
1074        }
1075        if(o.afterCls){
1076            fly(dom).addClass(o.afterCls);
1077        }
1078        if(o.remove == TRUE){
1079            fly(dom).remove();
1080        }
1081        if(notConcurrent){
1082            getQueue(id).shift();
1083        }
1084        if(o.callback){
1085            o.callback.call(o.scope, fly(dom));
1086        }
1087        if(notConcurrent){
1088            fly(dom).nextFx();
1089        }
1090    },
1091
1092    /* @private */
1093    fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
1094        animType = animType || 'run';
1095        opt = opt || {};
1096        var anim = Ext.lib.Anim[animType](
1097                this.dom, 
1098                args,
1099                (opt.duration || defaultDur) || .35,
1100                (opt.easing || defaultEase) || EASEOUT,
1101                cb,           
1102                this
1103            );
1104        opt.anim = anim;
1105        return anim;
1106    }
1107};
1108
1109// backwards compat
1110Ext.Fx.resize = Ext.Fx.scale;
1111
1112//When included, Ext.Fx is automatically applied to Element so that all basic
1113//effects are available directly via the Element API
1114Ext.Element.addMethods(Ext.Fx);
1115})();
Note: See TracBrowser for help on using the repository browser.