diff --git a/src/effects.js b/src/effects.js index f7a317ac9..41e87e3af 100644 --- a/src/effects.js +++ b/src/effects.js @@ -216,7 +216,7 @@ function defaultPrefilter( elem, props, opts ) { style = elem.style, orig = {}, handled = [], - hidden = jQuery( elem ).is(":hidden"); + hidden = elem.nodeType && isHidden( elem ); // height/width overflow pass if ( elem.nodeType === 1 && ( props.height || props.width ) ) { @@ -373,6 +373,11 @@ Tween.propHooks = { } }; +function isHidden( elem, el ) { + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument.documentElement, elem ); +} + function showHide( elements, show ) { var elem, display, values = [], @@ -395,9 +400,8 @@ function showHide( elements, show ) { // 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) ); + if ( elem.style.display === "" && isHidden( elem ) ) { + values[ index ] = jQuery._data( elem, "olddisplay", defaultDisplay( elem.nodeName ) ); } } else { display = jQuery.css( elem, "display" ); @@ -442,7 +446,7 @@ jQuery.fn.extend({ } else if ( fn == null || bool ) { this.each(function() { - var state = bool ? fn : jQuery( this ).is(":hidden"); + var state = bool ? fn : isHidden( this ); showHide([ this ], state ); }); @@ -453,8 +457,12 @@ jQuery.fn.extend({ return this; }, fadeTo: function( speed, to, easing, callback ) { - return this.filter(":hidden").css("opacity", 0).show().end() - .animate({opacity: to}, speed, easing, callback); + + // show any hidden elements after setting opacity to 0 + return this.filter( isHidden ).css( "opacity", 0 ).show() + + // animate to the value specified + .end().animate({ opacity: to }, speed, easing, callback ); }, animate: function( prop, speed, easing, callback ) { var optall = jQuery.speed( speed, easing, callback ), diff --git a/test/unit/effects.js b/test/unit/effects.js index b05dfa0cf..fed25eeb0 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -1480,7 +1480,6 @@ asyncTest( "Animate Option: step: function( percent, tween )", 1, function() { }); }); - asyncTest( "Animate callbacks have correct context", 2, function() { var foo = jQuery( "#foo" ); foo.animate({ @@ -1510,6 +1509,67 @@ asyncTest( "User supplied callback called after show when fx off (#8892)", 2, fu }); }); +test( "animate should set display for disconnected nodes", function() { + expect( 18 ); + + var i = 0, + methods = { + toggle: [ 1 ], + slideToggle: [], + fadeIn: [], + fadeTo: [ "fast", 0.5 ], + slideDown: [ "fast" ], + show: [ 1 ], + animate: [{ width: "show" }] + }, + elems = [ + + // parentNode = document fragment + jQuery("
test
"), + + // parentNode = null + jQuery("
"), + + jQuery('
'), + + jQuery('
') + ]; + + strictEqual( elems[ 0 ].show()[ 0 ].style.display, "block", "set display with show() for element with parentNode = document fragment" ); + strictEqual( elems[ 1 ].show()[ 0 ].style.display, "block", "set display with show() for element with parentNode = null" ); + strictEqual( elems[ 2 ].show()[ 0 ].style.display, "inline", "show() should not change display if it already set" ); + strictEqual( elems[ 3 ].show()[ 0 ].style.display, "block", "show() should change display if it already set to none" ); + + // cleanup + jQuery.each( elems, function() { + jQuery.removeData( this[ 0 ], "olddisplay", true ); + }); + + stop(); + jQuery.each( methods, function( name, opt ) { + jQuery.each([ + + // parentNode = document fragment + jQuery("
test
"), + + // parentNode = null + jQuery("
") + + ], function() { + var callback = [function () { + strictEqual( this.style.display, "block", "set display to block with " + name ); + + jQuery.removeData( this, "olddisplay", true ); + + if ( ++i === 14 ) { + start(); + } + }]; + jQuery.fn[ name ].apply( this, opt.concat( callback ) ); + }); + }); +}); + asyncTest("Animation callback should not show animated element as animated (#7157)", 1, function() { var foo = jQuery( "#foo" ); @@ -1519,4 +1579,52 @@ asyncTest("Animation callback should not show animated element as animated (#715 ok( !foo.is(':animated'), "The element is not animated" ); start(); }); -}); \ No newline at end of file +}); + +asyncTest( "hide called on element within hidden parent should set display to none (#10045)", 3, function() { + var hidden = jQuery(".hidden"), + elems = jQuery("
hide
hide0
hide1
"); + + hidden.append( elems ); + + jQuery.when( + elems.eq( 0 ).hide(), + elems.eq( 1 ).hide( 0 ), + elems.eq( 2 ).hide( 1 ) + ).done(function() { + strictEqual( elems.get( 0 ).style.display, "none", "hide() called on element within hidden parent should set display to none" ); + strictEqual( elems.get( 1 ).style.display, "none", "hide( 0 ) called on element within hidden parent should set display to none" ); + strictEqual( elems.get( 2 ).style.display, "none", "hide( 1 ) called on element within hidden parent should set display to none" ); + + start(); + }); +}); + +asyncTest( "hide, fadeOut and slideUp called on element width height and width = 0 should set display to none", 5, function() { + var foo = jQuery("#foo"), + i = 0, + elems = jQuery(); + + for ( ; i < 5; i++ ) { + elems = elems.add('
'); + } + + foo.append( elems ); + + jQuery.when( + elems.eq( 0 ).hide(), + elems.eq( 1 ).hide( jQuery.noop ), + elems.eq( 2 ).hide( 1 ), + elems.eq( 3 ).fadeOut(), + elems.eq( 4 ).slideUp() + ).done(function() { + strictEqual( elems.get( 0 ).style.display, "none", "hide() called on element width height and width = 0 should set display to none" ); + strictEqual( elems.get( 1 ).style.display, "none", + "hide( jQuery.noop ) called on element width height and width = 0 should set display to none" ); + strictEqual( elems.get( 2 ).style.display, "none", "hide( 1 ) called on element width height and width = 0 should set display to none" ); + strictEqual( elems.get( 3 ).style.display, "none", "fadeOut() called on element width height and width = 0 should set display to none" ); + strictEqual( elems.get( 4 ).style.display, "none", "slideUp() called on element width height and width = 0 should set display to none" ); + + start(); + }); +});