(function( jQuery ) { var fxNow, timerId, iframe, iframeDoc, elemdisplay = {}, rfxtypes = /^(?:toggle|show|hide)$/, rfxnum = /^([\-+]=)?((?:\d*\.)?\d+)([a-z%]*)$/i, rrun = /\.run$/, animationPrefilters = [], tweeners = { "*": [function( prop, value ) { var end, unit, tween = this.createTween( prop, value ), parts = rfxnum.exec( value ), start = tween.cur(); if ( parts ) { end = +parts[2]; unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" ); // We need to compute starting value if ( unit !== "px" ) { jQuery.style( this, prop, (end || 1) + unit); start = start * (end || 1) / tween.cur() || 0; jQuery.style( this, prop, start + unit); } tween.unit = unit; tween.start = start; // If a +=/-= token was provided, we're doing a relative animation tween.end = parts[1] ? start + end * ( parts[1] === "-=" ? -1 : 1 ) : end; } return tween; }] }, oldToggle = jQuery.fn.toggle; // Animations created synchronously will run synchronously function createFxNow() { setTimeout(function() { fxNow = undefined; }, 0 ); return ( fxNow = jQuery.now() ); } function callTweeners( animation, props ) { jQuery.each( props, function( prop, value ) { var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ), index = 0, length = collection.length; for ( ; index < length; index++ ) { if ( collection[ index ].call( animation, prop, value ) ) { // we're done with this property return; } } }); } function Animation( elem, properties, options ) { var result, index = 0, tweenerIndex = 0, length = animationPrefilters.length, finished = jQuery.Deferred(), deferred = jQuery.Deferred().always(function( ended ) { // remove cirular reference delete animation.tick; if ( deferred.state() === "resolved" || ended ) { // fire callbacks finished.resolveWith( this ); } }), animation = deferred.promise({ elem: elem, originalProperties: properties, originalOptions: options, props: jQuery.extend( {}, properties ), opts: jQuery.extend( {}, options ), startTime: fxNow || createFxNow(), duration: options.duration, finish: finished.done, tweens: [], createTween: function( prop, end, easing ) { var tween = jQuery.Tween( elem, animation.opts, prop, end, animation.opts.specialEasing[ prop ] || animation.opts.easing ); animation.tweens.push( tween ); return tween; }, tick: function() { var currentTime = fxNow || createFxNow(), remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), percent = 1 - ( remaining / animation.duration || 0 ), index = 0, length = animation.tweens.length; for ( ; index < length ; index++ ) { animation.tweens[ index ].run( percent ); } if ( percent < 1 && length ) { return remaining; } else { deferred.resolveWith( elem, [ currentTime ] ); return false; } }, stop: function( gotoEnd ) { var index = 0, // if we are going to the end, we want to run all the tweens // otherwise we skip this part length = gotoEnd ? animation.tweens.length : 0; for ( ; index < length ; index++ ) { animation.tweens[ index ].run( 1 ); } deferred.rejectWith( elem, [ gotoEnd ] ); return this; } }), props = animation.props; propFilter( props ); for ( ; index < length ; index++ ) { result = animationPrefilters[ index ].call( animation, elem, props, animation.opts ); if ( result ) { return result; } } callTweeners( animation, props ); jQuery.extend( animation.tick, { anim: animation, queue: animation.opts.queue, elem: elem }); jQuery.fx.timer( animation.tick ); return animation; } function propFilter( props ) { var index, name, hooks, replace; // camelCase and expand cssHook pass for ( index in props ) { name = jQuery.camelCase( index ); if ( index !== name ) { props[ name ] = props[ index ]; delete props[ index ]; } hooks = jQuery.cssHooks[ name ]; if ( hooks && "expand" in hooks ) { replace = hooks.expand( props[ name ] ); delete props[ name ]; // not quite $.extend, this wont overwrite keys already present. // also - reusing 'index' from above because we have the correct "name" for ( index in replace ) { if ( index in props ) { continue; } props[ index ] = replace[ index ]; } } } } jQuery.Animation = jQuery.extend( Animation, { tweener: function( props, callback ) { if ( jQuery.isFunction( props ) ) { callback = props; props = [ "*" ]; } else { props = props.split(" "); } var prop, index = 0, length = props.length; for ( ; index < length ; index++ ) { prop = props[ index ]; tweeners[ prop ] = tweeners[ prop ] || []; tweeners[ prop ].unshift( callback ); } }, prefilter: function( callback, prepend ) { if ( prepend ) { animationPrefilters.unshift( callback ); } else { animationPrefilters.push( callback ); } } }); Animation.prefilter(function( elem, props, opts ) { var index, value, style = elem.style; // custom easing pass opts.specialEasing = opts.specialEasing || {}; for ( index in props ) { value = props[ index ]; if ( jQuery.isArray( value ) ) { opts.specialEasing[ index ] = value[ 1 ]; value = props[ index ] = value[ 0 ]; } } // height/width overflow pass if ( elem.nodeType === 1 && ( props.height || props.width ) ) { // Make sure that nothing sneaks out // Record all 3 overflow attributes because IE does not // change the overflow attribute when overflowX and // overflowY are set to the same value opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; // Set display property to inline-block for height/width // animations on inline elements that are having width/height animated if ( jQuery.css( elem, "display" ) === "inline" && jQuery.css( elem, "float" ) === "none" ) { // inline-level elements accept inline-block; // block-level elements need to be inline with layout if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( elem.nodeName ) === "inline" ) { style.display = "inline-block"; } else { style.zoom = 1; } } } if ( opts.overflow ) { style.overflow = "hidden"; this.finish(function() { style.overflow = opts.overflow[ 0 ]; style.overflowX = opts.overflow[ 1 ]; style.overflowY = opts.overflow[ 2 ]; }); } }); // special case show/hide prefilter Animation.prefilter(function( elem, props, opts ) { var index, prop, value, length, dataShow, tween, orig = {}, handled = [], hidden = jQuery( elem ).is(":hidden"); for ( index in props ) { value = props[ index ]; if ( rfxtypes.exec( value ) ) { delete props[ index ]; if ( value === ( hidden ? "hide" : "show" ) ) { continue; } handled.push( index ); } } length = handled.length; if ( length ) { dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} ); if ( hidden ) { showHide([ elem ], true ); } else { this.finish(function() { showHide([ elem ]); }); } this.finish(function() { var prop; jQuery.removeData( elem, "fxshow", true ); for ( prop in orig ) { jQuery.style( elem, prop, orig[ prop ] ); } }); for ( index = 0 ; index < length ; index++ ) { prop = handled[ index ]; tween = this.createTween( prop, hidden ? dataShow[ prop ] : 0 ); orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop ); if ( !( prop in dataShow ) ) { dataShow[ prop ] = tween.start; if ( hidden ) { tween.end = tween.start; tween.start = prop === "width" || prop === "height" ? 1 : 0; } } } } }); function Tween( elem, options, prop, end, easing ) { return new Tween.prototype.init( elem, options, prop, end, easing ); } jQuery.Tween = Tween; Tween.prototype = { constructor: Tween, init: function( elem, options, prop, end, easing, unit ) { this.elem = elem; this.prop = prop; this.easing = easing || "swing"; this.options = options; this.start = this.now = this.cur(); this.end = end; this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); }, cur: function() { var hooks = Tween.propHooks[ this.prop ]; return hooks && hooks.get ? hooks.get( this ) : Tween.propHooks._default.get( this ); }, run: function( percent ) { var eased, hooks = Tween.propHooks[ this.prop ]; this.pos = eased = jQuery.easing[ this.easing ]( percent, this.options.duration * percent, 0, 1, this.options.duration ); this.now = ( this.end - this.start ) * eased + this.start; if ( this.options.step ) { this.options.step.call( this.elem, this.now, this ); } if ( hooks && hooks.set ) { hooks.set( this ); } else { Tween.propHooks._default.set( this ); } return this; } }; Tween.prototype.init.prototype = Tween.prototype; Tween.propHooks = { _default: { get: function( tween ) { var parsed, result; if ( tween.elem[ tween.prop ] != null && (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) { return tween.elem[ tween.prop ]; } result = jQuery.css( tween.elem, tween.prop ); // Empty strings, null, undefined and "auto" are converted to 0, // complex values such as "rotate(1rad)" are returned as is, // simple values such as "10px" are parsed to Float. return isNaN( parsed = parseFloat( result ) ) ? !result || result === "auto" ? 0 : result : parsed; }, set: function( tween ) { // use step hook for back compat - use cssHook if its there - use .style if its // available and use plain properties where available if ( jQuery.fx.step[ tween.prop ] ) { jQuery.fx.step[ tween.prop ]( tween ); } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) { jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); } else { tween.elem[ tween.prop ] = tween.now; } } } }; function showHide( elements, show ) { var elem, display, values = [], index = 0, length = elements.length; for ( ; index < length; index++ ) { elem = elements[ index ]; if ( !elem.style ) { continue; } values[ index ] = jQuery._data( elem, "olddisplay" ); if ( show ) { // Reset the inline display of this element to learn if it is // being hidden by cascaded rules or not if ( !values[ index ] && elem.style.display === "none" ) { elem.style.display = ""; } // Set elements which have been overridden with display: none // in a stylesheet to whatever the default browser style is // for such an element if ( (elem.style.display === "" && jQuery.css( elem, "display" ) === "none") || !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) { values[ index ] = jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) ); } } else { display = jQuery.css( elem, "display" ); if ( !values[ index ] && display !== "none" ) { jQuery._data( elem, "olddisplay", display ); } } } // Set the display of most of the elements in a second loop // to avoid the constant reflow for ( index = 0; index < length; index++ ) { elem = elements[ index ]; if ( !elem.style ) { continue; } if ( !show || elem.style.display === "none" || elem.style.display === "" ) { elem.style.display = show ? values[ index ] || "" : "none"; } } return elements; } jQuery.fn.extend({ show: function( speed, easing, callback ) { return speed || speed === 0 ? this.animate( genFx( "show", true ), speed, easing, callback ) : showHide( this, true ); }, hide: function( speed, easing, callback ) { return speed || speed === 0 ? this.animate( genFx( "hide", true ), speed, easing, callback ) : showHide( this ); }, toggle: function( fn, fn2, callback ) { var bool = typeof fn === "boolean"; if ( jQuery.isFunction( fn ) && jQuery.isFunction( fn2 ) ) { oldToggle.apply( this, arguments ); } else if ( fn == null || bool ) { this.each(function() { var state = bool ? fn : jQuery( this ).is(":hidden"); showHide([ this ], state ); }); } else { this.animate( genFx( "toggle", true ), fn, fn2, callback ); } return this; }, fadeTo: function( speed, to, easing, callback ) { return this.filter(":hidden").css("opacity", 0).show().end() .animate({opacity: to}, speed, easing, callback); }, animate: function( prop, speed, easing, callback ) { var optall = jQuery.speed( speed, easing, callback ), doAnimation = function() { Animation( this, prop, optall ).finish( optall.complete ); }; if ( jQuery.isEmptyObject( prop ) ) { return this.each( optall.complete, [ false ] ); } // Do not change referenced properties as per-property easing will be lost prop = jQuery.extend( {}, prop ); return optall.queue === false ? this.each( doAnimation ) : this.queue( optall.queue, doAnimation ); }, stop: function( type, clearQueue, gotoEnd ) { var stopQueue = function( elem, data, index ) { var hooks = data[ index ]; jQuery.removeData( elem, index, true ); hooks.stop( gotoEnd ); }; if ( typeof type !== "string" ) { gotoEnd = clearQueue; clearQueue = type; type = undefined; } if ( clearQueue && type !== false ) { this.queue( type || "fx", [] ); } return this.each(function() { var index, hadTimers = false, timers = jQuery.timers, data = jQuery._data( this ); // clear marker counters if we know they won't be if ( !gotoEnd ) { jQuery._unmark( true, this ); } if ( type == null ) { for ( index in data ) { if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { stopQueue( this, data, index ); } } } else if ( data[ index = type + ".run" ] && data[ index ].stop ){ stopQueue( this, data, index ); } for ( index = timers.length; index--; ) { if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) { timers[ index ].anim.stop( gotoEnd ); hadTimers = true; timers.splice( index, 1 ); } } // start the next in the queue if the last step wasn't forced // timers currently will call their complete callbacks, which will dequeue // but only if they were gotoEnd if ( !( gotoEnd && hadTimers ) ) { jQuery.dequeue( this, type ); } }); } }); // Generate parameters to create a standard animation function genFx( type, includeWidth ) { var which, attrs = { height: type }, i = 0; // if we include width, step value is 1 to do all cssExpand values, // if we don't include width, step value is 2 to skip over Left and Right for( ; i < 4 ; i += 2 - includeWidth ) { which = jQuery.cssExpand[ i ]; attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; } if ( includeWidth ) { attrs.opacity = attrs.width = type; } return attrs; } // Generate shortcuts for custom animations jQuery.each({ slideDown: genFx("show"), slideUp: genFx("hide"), slideToggle: genFx("toggle"), fadeIn: { opacity: "show" }, fadeOut: { opacity: "hide" }, fadeToggle: { opacity: "toggle" } }, function( name, props ) { jQuery.fn[ name ] = function( speed, easing, callback ) { return this.animate( props, speed, easing, callback ); }; }); jQuery.speed = function( speed, easing, fn ) { var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { complete: fn || !fn && easing || jQuery.isFunction( speed ) && speed, duration: speed, easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing }; opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; // normalize opt.queue - true/undefined/null -> "fx" if ( opt.queue == null || opt.queue === true ) { opt.queue = "fx"; } // Queueing opt.old = opt.complete; opt.complete = function( noUnmark ) { if ( jQuery.isFunction( opt.old ) ) { opt.old.call( this ); } if ( opt.queue ) { jQuery.dequeue( this, opt.queue ); } else if ( noUnmark !== false ) { jQuery._unmark( this ); } }; return opt; }; jQuery.easing = { linear: function( p ) { return p; }, swing: function( p ) { return 0.5 - Math.cos( p*Math.PI ) / 2; } }; jQuery.timers = []; jQuery.fx = Tween.prototype.init; jQuery.fx.tick = function() { var timer, timers = jQuery.timers, i = 0; for ( ; i < timers.length; i++ ) { timer = timers[ i ]; // Checks the timer has not already been removed if ( !timer() && timers[ i ] === timer ) { timers.splice( i--, 1 ); } } if ( !timers.length ) { jQuery.fx.stop(); } }; jQuery.fx.timer = function( timer ) { if ( timer() && jQuery.timers.push( timer ) && !timerId ) { timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval ); } }; jQuery.fx.interval = 13; jQuery.fx.stop = function() { clearInterval( timerId ); timerId = null; }; jQuery.fx.speeds = { slow: 600, fast: 200, // Default speed _default: 400 }; // Back Compat <1.8 extension point jQuery.fx.step = {}; if ( jQuery.expr && jQuery.expr.filters ) { jQuery.expr.filters.animated = function( elem ) { return jQuery.grep(jQuery.timers, function( fn ) { return elem === fn.elem; }).length; }; } // Try to restore the default display value of an element function defaultDisplay( nodeName ) { if ( elemdisplay[ nodeName ] ) { return elemdisplay[ nodeName ]; } var elem = jQuery( "<" + nodeName + ">" ).appendTo( document.body ), display = elem.css("display"); elem.remove(); // If the simple way fails, // get element's real default display by attaching it to a temp iframe if ( display === "none" || display === "" ) { // Use the already-created iframe if possible iframe = document.body.appendChild( iframe || jQuery.extend( document.createElement("iframe"), { frameBorder: 0, width: 0, height: 0 }) ); // Create a cacheable copy of the iframe document on first call. // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML // document to it; WebKit & Firefox won't allow reusing the iframe document. if ( !iframeDoc || !iframe.createElement ) { iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; iframeDoc.write( ( jQuery.support.boxModel ? "" : "" ) + "" ); iframeDoc.close(); } elem = iframeDoc.body.appendChild( iframeDoc.createElement(nodeName) ); display = jQuery.css( elem, "display" ); document.body.removeChild( iframe ); } // Store the correct default display elemdisplay[ nodeName ] = display; return display; } })( jQuery );