/**
 * @class Ext.core.Element
 */

Ext.applyIf(Ext.core.Element.prototype, {
   
// @private override base Ext.util.Animate mixin for animate for backwards compatibility
    animate
: function(config) {
       
var me = this;
       
if (!me.id) {
            me
= Ext.get(me.dom);
       
}
       
if (Ext.fx.Manager.hasFxBlock(me.id)) {
           
return me;
       
}
       
Ext.fx.Manager.queueFx(Ext.create('Ext.fx.Anim', me.anim(config)));
       
return this;
   
},

   
// @private override base Ext.util.Animate mixin for animate for backwards compatibility
    anim
: function(config) {
       
if (!Ext.isObject(config)) {
           
return (config) ? {} : false;
       
}

       
var me = this,
            duration
= config.duration || Ext.fx.Anim.prototype.duration,
            easing
= config.easing || 'ease',
            animConfig
;

       
if (config.stopAnimation) {
            me
.stopAnimation();
       
}

       
Ext.applyIf(config, Ext.fx.Manager.getFxDefaults(me.id));

       
// Clear any 'paused' defaults.
       
Ext.fx.Manager.setFxDefaults(me.id, {
            delay
: 0
       
});

        animConfig
= {
            target
: me,
            remove
: config.remove,
            alternate
: config.alternate || false,
            duration
: duration,
            easing
: easing,
            callback
: config.callback,
            listeners
: config.listeners,
            iterations
: config.iterations || 1,
            scope
: config.scope,
            block
: config.block,
            concurrent
: config.concurrent,
            delay
: config.delay || 0,
            paused
: true,
            keyframes
: config.keyframes,
            from
: config.from || {},
            to
: Ext.apply({}, config)
       
};
       
Ext.apply(animConfig.to, config.to);

       
// Anim API properties - backward compat
       
delete animConfig.to.to;
       
delete animConfig.to.from;
       
delete animConfig.to.remove;
       
delete animConfig.to.alternate;
       
delete animConfig.to.keyframes;
       
delete animConfig.to.iterations;
       
delete animConfig.to.listeners;
       
delete animConfig.to.target;
       
delete animConfig.to.paused;
       
delete animConfig.to.callback;
       
delete animConfig.to.scope;
       
delete animConfig.to.duration;
       
delete animConfig.to.easing;
       
delete animConfig.to.concurrent;
       
delete animConfig.to.block;
       
delete animConfig.to.stopAnimation;
       
delete animConfig.to.delay;
       
return animConfig;
   
},

    /**
     * Slides the element into view.  An anchor point can be optionally passed to set the point of
     * origin for the slide effect.  This function automatically handles wrapping the element with
     * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
     * Usage:
     *<pre><code>
// default: slide the element in from the top
el.slideIn();

// custom: slide the element in from the right with a 2-second duration
el.slideIn('r', { duration: 2 });

// common config options shown with default values
el.slideIn('t', {
    easing: 'easeOut',
    duration: 500
});
</code></pre>
     * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
     * @param {Object} options (optional) Object literal with any of the Fx config options
     * @return {Ext.core.Element} The Element
     */

    slideIn
: function(anchor, obj, slideOut) {
       
var me = this,
            elStyle
= me.dom.style,
            beforeAnim
, wrapAnim;

        anchor
= anchor || "t";
        obj
= obj || {};

        beforeAnim
= function() {
           
var animScope = this,
                listeners
= obj.listeners,
                box
, position, restoreSize, wrap, anim;

           
if (!slideOut) {
                me
.fixDisplay();
           
}

            box
= me.getBox();
           
if ((anchor == 't' || anchor == 'b') && box.height == 0) {
                box
.height = me.dom.scrollHeight;
           
}
           
else if ((anchor == 'l' || anchor == 'r') && box.width == 0) {
                box
.width = me.dom.scrollWidth;
           
}
           
            position
= me.getPositioning();
            me
.setSize(box.width, box.height);

            wrap
= me.wrap({
                style
: {
                    visibility
: slideOut ? 'visible' : 'hidden'
               
}
           
});
            wrap
.setPositioning(position);
           
if (wrap.isStyle('position', 'static')) {
                wrap
.position('relative');
           
}
            me
.clearPositioning('auto');
            wrap
.clip();

           
// This element is temporarily positioned absolute within its wrapper.
           
// Restore to its default, CSS-inherited visibility setting.
           
// We cannot explicitly poke visibility:visible into its style because that overrides the visibility of the wrap.
            me
.setStyle({
                visibility
: '',
                position
: 'absolute'
           
});
           
if (slideOut) {
                wrap
.setSize(box.width, box.height);
           
}

           
switch (anchor) {
               
case 't':
                    anim
= {
                        from
: {
                            width
: box.width + 'px',
                            height
: '0px'
                       
},
                        to
: {
                            width
: box.width + 'px',
                            height
: box.height + 'px'
                       
}
                   
};
                    elStyle
.bottom = '0px';
                   
break;
               
case 'l':
                    anim
= {
                        from
: {
                            width
: '0px',
                            height
: box.height + 'px'
                       
},
                        to
: {
                            width
: box.width + 'px',
                            height
: box.height + 'px'
                       
}
                   
};
                    elStyle
.right = '0px';
                   
break;
               
case 'r':
                    anim
= {
                        from
: {
                            x
: box.x + box.width,
                            width
: '0px',
                            height
: box.height + 'px'
                       
},
                        to
: {
                            x
: box.x,
                            width
: box.width + 'px',
                            height
: box.height + 'px'
                       
}
                   
};
                   
break;
               
case 'b':
                    anim
= {
                        from
: {
                            y
: box.y + box.height,
                            width
: box.width + 'px',
                            height
: '0px'
                       
},
                        to
: {
                            y
: box.y,
                            width
: box.width + 'px',
                            height
: box.height + 'px'
                       
}
                   
};
                   
break;
               
case 'tl':
                    anim
= {
                        from
: {
                            x
: box.x,
                            y
: box.y,
                            width
: '0px',
                            height
: '0px'
                       
},
                        to
: {
                            width
: box.width + 'px',
                            height
: box.height + 'px'
                       
}
                   
};
                    elStyle
.bottom = '0px';
                    elStyle
.right = '0px';
                   
break;
               
case 'bl':
                    anim
= {
                        from
: {
                            x
: box.x + box.width,
                            width
: '0px',
                            height
: '0px'
                       
},
                        to
: {
                            x
: box.x,
                            width
: box.width + 'px',
                            height
: box.height + 'px'
                       
}
                   
};
                    elStyle
.right = '0px';
                   
break;
               
case 'br':
                    anim
= {
                        from
: {
                            x
: box.x + box.width,
                            y
: box.y + box.height,
                            width
: '0px',
                            height
: '0px'
                       
},
                        to
: {
                            x
: box.x,
                            y
: box.y,
                            width
: box.width + 'px',
                            height
: box.height + 'px'
                       
}
                   
};
                   
break;
               
case 'tr':
                    anim
= {
                        from
: {
                            y
: box.y + box.height,
                            width
: '0px',
                            height
: '0px'
                       
},
                        to
: {
                            y
: box.y,
                            width
: box.width + 'px',
                            height
: box.height + 'px'
                       
}
                   
};
                    elStyle
.bottom = '0px';
                   
break;
           
}

            wrap
.show();
            wrapAnim
= Ext.apply({}, obj);
           
delete wrapAnim.listeners;
            wrapAnim
= Ext.create('Ext.fx.Anim', Ext.applyIf(wrapAnim, {
                target
: wrap,
                duration
: 500,
                easing
: 'ease-out',
                from
: slideOut ? anim.to : anim.from,
                to
: slideOut ? anim.from : anim.to
           
}));

           
// In the absence of a callback, this listener MUST be added first
            wrapAnim
.on('afteranimate', function() {
               
if (slideOut) {
                    me
.setPositioning(position);
                   
if (obj.useDisplay) {
                        me
.setDisplayed(false);
                   
} else {
                        me
.hide();  
                   
}
               
}
               
else {
                    me
.clearPositioning();
                    me
.setPositioning(position);
               
}
               
if (wrap.dom) {
                    wrap
.dom.parentNode.insertBefore(me.dom, wrap.dom);
                    wrap
.remove();
               
}
                me
.setSize(box.width, box.height);
                animScope
.end();
           
});
           
// Add configured listeners after
           
if (listeners) {
                wrapAnim
.on(listeners);
           
}
       
};

        me
.animate({
            duration
: obj.duration ? obj.duration * 2 : 1000,
            listeners
: {
                beforeanimate
: {
                    fn
: beforeAnim
               
},
                afteranimate
: {
                    fn
: function() {
                       
if (wrapAnim && wrapAnim.running) {
                            wrapAnim
.end();
                       
}
                   
}
               
}
           
}
       
});
       
return me;
   
},

   
    /**
     * Slides the element out of view.  An anchor point can be optionally passed to set the end point
     * for the slide effect.  When the effect is completed, the element will be hidden (visibility =
     * 'hidden') but block elements will still take up space in the document.  The element must be removed
     * from the DOM using the 'remove' config option if desired.  This function automatically handles
     * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
     * Usage:
     *<pre><code>
// default: slide the element out to the top
el.slideOut();

// custom: slide the element out to the right with a 2-second duration
el.slideOut('r', { duration: 2 });

// common config options shown with default values
el.slideOut('t', {
    easing: 'easeOut',
    duration: 500,
    remove: false,
    useDisplay: false
});
</code></pre>
     * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
     * @param {Object} options (optional) Object literal with any of the Fx config options
     * @return {Ext.core.Element} The Element
     */

    slideOut
: function(anchor, o) {
       
return this.slideIn(anchor, o, true);
   
},

    /**
     * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the
     * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
     * Usage:
     *<pre><code>
// default
el.puff();

// common config options shown with default values
el.puff({
    easing: 'easeOut',
    duration: 500,
    useDisplay: false
});
</code></pre>
     * @param {Object} options (optional) Object literal with any of the Fx config options
     * @return {Ext.core.Element} The Element
     */


    puff
: function(obj) {
       
var me = this,
            beforeAnim
;
        obj
= Ext.applyIf(obj || {}, {
            easing
: 'ease-out',
            duration
: 500,
            useDisplay
: false
       
});

        beforeAnim
= function() {
            me
.clearOpacity();
            me
.show();

           
var box = me.getBox(),
                fontSize
= me.getStyle('fontSize'),
                position
= me.getPositioning();
           
this.to = {
                width
: box.width * 2,
                height
: box.height * 2,
                x
: box.x - (box.width / 2),
                y
: box.y - (box.height /2),
                opacity
: 0,
                fontSize
: '200%'
           
};
           
this.on('afteranimate',function() {
               
if (me.dom) {
                   
if (obj.useDisplay) {
                        me
.setDisplayed(false);
                   
} else {
                        me
.hide();
                   
}
                    me
.clearOpacity();  
                    me
.setPositioning(position);
                    me
.setStyle({fontSize: fontSize});
               
}
           
});
       
};

        me
.animate({
            duration
: obj.duration,
            easing
: obj.easing,
            listeners
: {
                beforeanimate
: {
                    fn
: beforeAnim
               
}
           
}
       
});
       
return me;
   
},

    /**
     * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
     * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
     * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
     * Usage:
     *<pre><code>
// default
el.switchOff();

// all config options shown with default values
el.switchOff({
    easing: 'easeIn',
    duration: .3,
    remove: false,
    useDisplay: false
});
</code></pre>
     * @param {Object} options (optional) Object literal with any of the Fx config options
     * @return {Ext.core.Element} The Element
     */

    switchOff
: function(obj) {
       
var me = this,
            beforeAnim
;
       
        obj
= Ext.applyIf(obj || {}, {
            easing
: 'ease-in',
            duration
: 500,
            remove
: false,
            useDisplay
: false
       
});

        beforeAnim
= function() {
           
var animScope = this,
                size
= me.getSize(),
                xy
= me.getXY(),
                keyframe
, position;
            me
.clearOpacity();
            me
.clip();
            position
= me.getPositioning();

            keyframe
= Ext.create('Ext.fx.Animator', {
                target
: me,
                duration
: obj.duration,
                easing
: obj.easing,
                keyframes
: {
                   
33: {
                        opacity
: 0.3
                   
},
                   
66: {
                        height
: 1,
                        y
: xy[1] + size.height / 2
                   
},
                   
100: {
                        width
: 1,
                        x
: xy[0] + size.width / 2
                   
}
               
}
           
});
            keyframe
.on('afteranimate', function() {
               
if (obj.useDisplay) {
                    me
.setDisplayed(false);
               
} else {
                    me
.hide();
               
}  
                me
.clearOpacity();
                me
.setPositioning(position);
                me
.setSize(size);
                animScope
.end();
           
});
       
};
        me
.animate({
            duration
: (obj.duration * 2),
            listeners
: {
                beforeanimate
: {
                    fn
: beforeAnim
               
}
           
}
       
});
       
return me;
   
},

   /**
    * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
    * Usage:
<pre><code>
// default: a single light blue ripple
el.frame();

// custom: 3 red ripples lasting 3 seconds total
el.frame("#ff0000", 3, { duration: 3 });

// common config options shown with default values
el.frame("#C3DAF9", 1, {
    duration: 1 //duration of each individual ripple.
    // Note: Easing is not configurable and will be ignored if included
});
</code></pre>
    * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
    * @param {Number} count (optional) The number of ripples to display (defaults to 1)
    * @param {Object} options (optional) Object literal with any of the Fx config options
    * @return {Ext.core.Element} The Element
    */

    frame
: function(color, count, obj){
       
var me = this,
            beforeAnim
;

        color
= color || '#C3DAF9';
        count
= count || 1;
        obj
= obj || {};

        beforeAnim
= function() {
            me
.show();
           
var animScope = this,
                box
= me.getBox(),
                proxy
= Ext.getBody().createChild({
                    style
: {
                        position
: 'absolute',
                       
'pointer-events': 'none',
                       
'z-index': 35000,
                        border
: '0px solid ' + color
                   
}
               
}),
                proxyAnim
;
            proxyAnim
= Ext.create('Ext.fx.Anim', {
                target
: proxy,
                duration
: obj.duration || 1000,
                iterations
: count,
                from
: {
                    top
: box.y,
                    left
: box.x,
                    borderWidth
: 0,
                    opacity
: 1,
                    height
: box.height,
                    width
: box.width
               
},
                to
: {
                    top
: box.y - 20,
                    left
: box.x - 20,
                    borderWidth
: 10,
                    opacity
: 0,
                    height
: box.height + 40,
                    width
: box.width + 40
               
}
           
});
            proxyAnim
.on('afteranimate', function() {
                proxy
.remove();
                animScope
.end();
           
});
       
};

        me
.animate({
            duration
: (obj.duration * 2) || 2000,
            listeners
: {
                beforeanimate
: {
                    fn
: beforeAnim
               
}
           
}
       
});
       
return me;
   
},

    /**
     * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the
     * ending point of the effect.
     * Usage:
     *<pre><code>
// default: slide the element downward while fading out
el.ghost();

// custom: slide the element out to the right with a 2-second duration
el.ghost('r', { duration: 2 });

// common config options shown with default values
el.ghost('b', {
    easing: 'easeOut',
    duration: 500
});
</code></pre>
     * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
     * @param {Object} options (optional) Object literal with any of the Fx config options
     * @return {Ext.core.Element} The Element
     */

    ghost
: function(anchor, obj) {
       
var me = this,
            beforeAnim
;

        anchor
= anchor || "b";
        beforeAnim
= function() {
           
var width = me.getWidth(),
                height
= me.getHeight(),
                xy
= me.getXY(),
                position
= me.getPositioning(),
                to
= {
                    opacity
: 0
               
};
           
switch (anchor) {
               
case 't':
                    to
.y = xy[1] - height;
                   
break;
               
case 'l':
                    to
.x = xy[0] - width;
                   
break;
               
case 'r':
                    to
.x = xy[0] + width;
                   
break;
               
case 'b':
                    to
.y = xy[1] + height;
                   
break;
               
case 'tl':
                    to
.x = xy[0] - width;
                    to
.y = xy[1] - height;
                   
break;
               
case 'bl':
                    to
.x = xy[0] - width;
                    to
.y = xy[1] + height;
                   
break;
               
case 'br':
                    to
.x = xy[0] + width;
                    to
.y = xy[1] + height;
                   
break;
               
case 'tr':
                    to
.x = xy[0] + width;
                    to
.y = xy[1] - height;
                   
break;
           
}
           
this.to = to;
           
this.on('afteranimate', function () {
               
if (me.dom) {
                    me
.hide();
                    me
.clearOpacity();
                    me
.setPositioning(position);
               
}
           
});
       
};

        me
.animate(Ext.applyIf(obj || {}, {
            duration
: 500,
            easing
: 'ease-out',
            listeners
: {
                beforeanimate
: {
                    fn
: beforeAnim
               
}
           
}
       
}));
       
return me;
   
},

    /**
     * Highlights the Element by setting a color (applies to the background-color by default, but can be
     * changed using the "attr" config option) and then fading back to the original color. If no original
     * color is available, you should provide the "endColor" config option which will be cleared after the animation.
     * Usage:
<pre><code>
// default: highlight background to yellow
el.highlight();

// custom: highlight foreground text to blue for 2 seconds
el.highlight("0000ff", { attr: 'color', duration: 2 });

// common config options shown with default values
el.highlight("ffff9c", {
    attr: "backgroundColor", //can be any valid CSS property (attribute) that supports a color value
    endColor: (current color) or "ffffff",
    easing: 'easeIn',
    duration: 1000
});
</code></pre>
     * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
     * @param {Object} options (optional) Object literal with any of the Fx config options
     * @return {Ext.core.Element} The Element
     */

    highlight
: function(color, o) {
       
var me = this,
            dom
= me.dom,
            from
= {},
            restore
, to, attr, lns, event, fn;

        o
= o || {};
        lns
= o.listeners || {};
        attr
= o.attr || 'backgroundColor';
        from
[attr] = color || 'ffff9c';
       
       
if (!o.to) {
            to
= {};
            to
[attr] = o.endColor || me.getColor(attr, 'ffffff', '');
       
}
       
else {
            to
= o.to;
       
}
       
       
// Don't apply directly on lns, since we reference it in our own callbacks below
        o
.listeners = Ext.apply(Ext.apply({}, lns), {
            beforeanimate
: function() {
                restore
= dom.style[attr];
                me
.clearOpacity();
                me
.show();
               
                event
= lns.beforeanimate;
               
if (event) {
                    fn
= event.fn || event;
                   
return fn.apply(event.scope || lns.scope || window, arguments);
               
}
           
},
            afteranimate
: function() {
               
if (dom) {
                    dom
.style[attr] = restore;
               
}
               
                event
= lns.afteranimate;
               
if (event) {
                    fn
= event.fn || event;
                    fn
.apply(event.scope || lns.scope || window, arguments);
               
}
           
}
       
});

        me
.animate(Ext.apply({}, o, {
            duration
: 1000,
            easing
: 'ease-in',
            from
: from,
            to
: to
       
}));
       
return me;
   
},

   /**
    * @deprecated 4.0
    * Creates a pause before any subsequent queued effects begin.  If there are
    * no effects queued after the pause it will have no effect.
    * Usage:
<pre><code>
el.pause(1);
</code></pre>
    * @param {Number} seconds The length of time to pause (in seconds)
    * @return {Ext.Element} The Element
    */

    pause
: function(ms) {
       
var me = this;
       
Ext.fx.Manager.setFxDefaults(me.id, {
            delay
: ms
       
});
       
return me;
   
},

   /**
    * Fade an element in (from transparent to opaque).  The ending opacity can be specified
    * using the <tt>{@link #endOpacity}</tt> config option.
    * Usage:
<pre><code>
// default: fade in from opacity 0 to 100%
el.fadeIn();

// custom: fade in from opacity 0 to 75% over 2 seconds
el.fadeIn({ endOpacity: .75, duration: 2});

// common config options shown with default values
el.fadeIn({
    endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
    easing: 'easeOut',
    duration: 500
});
</code></pre>
    * @param {Object} options (optional) Object literal with any of the Fx config options
    * @return {Ext.Element} The Element
    */

    fadeIn
: function(o) {
       
this.animate(Ext.apply({}, o, {
            opacity
: 1
       
}));
       
return this;
   
},

   /**
    * Fade an element out (from opaque to transparent).  The ending opacity can be specified
    * using the <tt>{@link #endOpacity}</tt> config option.  Note that IE may require
    * <tt>{@link #useDisplay}:true</tt> in order to redisplay correctly.
    * Usage:
<pre><code>
// default: fade out from the element's current opacity to 0
el.fadeOut();

// custom: fade out from the element's current opacity to 25% over 2 seconds
el.fadeOut({ endOpacity: .25, duration: 2});

// common config options shown with default values
el.fadeOut({
    endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
    easing: 'easeOut',
    duration: 500,
    remove: false,
    useDisplay: false
});
</code></pre>
    * @param {Object} options (optional) Object literal with any of the Fx config options
    * @return {Ext.Element} The Element
    */

    fadeOut
: function(o) {
       
this.animate(Ext.apply({}, o, {
            opacity
: 0
       
}));
       
return this;
   
},

   /**
    * @deprecated 4.0
    * Animates the transition of an element's dimensions from a starting height/width
    * to an ending height/width.  This method is a convenience implementation of {@link #shift}.
    * Usage:
<pre><code>
// change height and width to 100x100 pixels
el.scale(100, 100);

// common config options shown with default values.  The height and width will default to
// the element&#39;s existing values if passed as null.
el.scale(
    [element&#39;s width],
    [element&#39;s height], {
        easing: 'easeOut',
        duration: .35
    }
);
</code></pre>
    * @param {Number} width  The new width (pass undefined to keep the original width)
    * @param {Number} height  The new height (pass undefined to keep the original height)
    * @param {Object} options (optional) Object literal with any of the Fx config options
    * @return {Ext.Element} The Element
    */

    scale
: function(w, h, o) {
       
this.animate(Ext.apply({}, o, {
            width
: w,
            height
: h
       
}));
       
return this;
   
},

   /**
    * @deprecated 4.0
    * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
    * Any of these properties not specified in the config object will not be changed.  This effect
    * requires that at least one new dimension, position or opacity setting must be passed in on
    * the config object in order for the function to have any effect.
    * Usage:
<pre><code>
// slide the element horizontally to x position 200 while changing the height and opacity
el.shift({ x: 200, height: 50, opacity: .8 });

// common config options shown with default values.
el.shift({
    width: [element&#39;s width],
    height: [element&#39;s height],
    x: [element&#39;s x position],
    y: [element&#39;s y position],
    opacity: [element&#39;s opacity],
    easing: 'easeOut',
    duration: .35
});
</code></pre>
    * @param {Object} options  Object literal with any of the Fx config options
    * @return {Ext.Element} The Element
    */

    shift
: function(config) {
       
this.animate(config);
       
return this;
   
}
});