diff --git a/src/effects.js b/src/effects.js index b6a374fb4..ff2d5dedf 100644 --- a/src/effects.js +++ b/src/effects.js @@ -5,7 +5,7 @@ var fxNow, timerId, iframe, iframeDoc, rfxtypes = /^(?:toggle|show|hide)$/, rfxnum = /^([\-+]=)?((?:\d*\.)?\d+)([a-z%]*)$/i, rrun = /\.run$/, - animationPrefilters = [], + animationPrefilters = [ defaultPrefilter ], tweeners = { "*": [function( prop, value ) { var end, unit, @@ -73,10 +73,10 @@ function Animation( elem, properties, options ) { }), animation = deferred.promise({ elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { specialEasing: {} }, options ), originalProperties: properties, originalOptions: options, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( {}, options ), startTime: fxNow || createFxNow(), duration: options.duration, finish: finished.done, @@ -120,7 +120,7 @@ function Animation( elem, properties, options ) { }), props = animation.props; - propFilter( props ); + propFilter( props, animation.opts.specialEasing ); for ( ; index < length ; index++ ) { result = animationPrefilters[ index ].call( animation, @@ -142,30 +142,39 @@ function Animation( elem, properties, options ) { return animation; } -function propFilter( props ) { - var index, name, hooks, replace; +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; - // camelCase and expand cssHook pass + // camelCase, specialEasing and expand cssHook pass for ( index in props ) { name = jQuery.camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( jQuery.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + if ( index !== name ) { - props[ name ] = props[ index ]; + props[ name ] = value; delete props[ index ]; } hooks = jQuery.cssHooks[ name ]; if ( hooks && "expand" in hooks ) { - replace = hooks.expand( props[ name ] ); + value = hooks.expand( value ); 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; + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; } - props[ index ] = replace[ index ]; } + } else { + specialEasing[ name ] = easing; } } } @@ -200,19 +209,12 @@ jQuery.Animation = jQuery.extend( Animation, { } }); -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 ]; - } - } +function defaultPrefilter( elem, props, opts ) { + var index, prop, value, length, dataShow, tween, + style = elem.style, + orig = {}, + handled = [], + hidden = jQuery( elem ).is(":hidden"); // height/width overflow pass if ( elem.nodeType === 1 && ( props.height || props.width ) ) { @@ -246,15 +248,9 @@ Animation.prefilter(function( elem, props, opts ) { 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"); + // show/hide pass for ( index in props ) { value = props[ index ]; if ( rfxtypes.exec( value ) ) { @@ -297,7 +293,7 @@ Animation.prefilter(function( elem, props, opts ) { } } } -}); +} function Tween( elem, options, prop, end, easing ) { return new Tween.prototype.init( elem, options, prop, end, easing ); diff --git a/test/unit/effects.js b/test/unit/effects.js index 74f83e7c4..0fab3f5f2 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -1248,6 +1248,53 @@ test("animate with per-property easing", function(){ }); +test("animate with CSS shorthand properties", function(){ + expect(11); + stop(); + + var _default_count = 0, + _special_count = 0, + propsBasic = { padding: "10 20 30" }, + propsSpecial = { padding: [ "1 2 3", "_special" ] }; + + jQuery.easing["_default"] = function(p) { + if ( p >= 1 ) { + _default_count++; + } + return p; + }; + + jQuery.easing["_special"] = function(p) { + if ( p >= 1 ) { + _special_count++; + } + return p; + }; + + jQuery("#foo") + .animate( propsBasic, 200, "_default", function() { + equal( this.style.paddingTop, "10px", "padding-top was animated" ); + equal( this.style.paddingLeft, "20px", "padding-left was animated" ); + equal( this.style.paddingRight, "20px", "padding-right was animated" ); + equal( this.style.paddingBottom, "30px", "padding-bottom was animated" ); + equal( _default_count, 4, "per-animation default easing called for each property" ); + _default_count = 0; + }) + .animate( propsSpecial, 200, "_default", function() { + equal( this.style.paddingTop, "1px", "padding-top was animated again" ); + equal( this.style.paddingLeft, "2px", "padding-left was animated again" ); + equal( this.style.paddingRight, "2px", "padding-right was animated again" ); + equal( this.style.paddingBottom, "3px", "padding-bottom was animated again" ); + equal( _default_count, 0, "per-animation default easing not called" ); + equal( _special_count, 4, "special easing called for each property" ); + + jQuery(this).css("padding", "0"); + delete jQuery.easing["_default"]; + delete jQuery.easing["_special"]; + start(); + }); +}); + test("hide hidden elements (bug #7141)", function() { expect(3); QUnit.reset();