From dba93f79c405373ec3a492fd0a4bf89b3136a6e6 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Mon, 11 Jan 2016 02:26:55 -0500 Subject: [PATCH] CSS: Restore cascade-override behavior in .show Fixes gh-2654 Fixes gh-2308 Close gh-2810 Ref 86419b10bfa5e3b71a7d416288ab806d47a31d1f --- src/css/showHide.js | 44 ++++++- src/effects.js | 13 +- test/data/testsuite.css | 14 +- test/unit/css.js | 275 ++++++++++++++++++++++++++++++++++++---- test/unit/effects.js | 161 ++++++++++++----------- 5 files changed, 391 insertions(+), 116 deletions(-) diff --git a/src/css/showHide.js b/src/css/showHide.js index 29e2d8bc8..9c62d5564 100644 --- a/src/css/showHide.js +++ b/src/css/showHide.js @@ -4,6 +4,31 @@ define( [ "../css/var/isHidden" ], function( jQuery, dataPriv, isHidden ) { +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ), + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + function showHide( elements, show ) { var display, elem, values = [], @@ -19,23 +44,30 @@ function showHide( elements, show ) { display = elem.style.display; if ( show ) { - if ( display === "none" ) { - // Restore a pre-hide() value if we have one - values[ index ] = dataPriv.get( elem, "display" ) || ""; + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && jQuery.css( elem, "display" ) === "none" ) { + values[ index ] = getDefaultDisplay( elem ); } } else { if ( display !== "none" ) { values[ index ] = "none"; - // Remember the value we're replacing + // Remember what we're overwriting dataPriv.set( elem, "display", display ); } } } - // Set the display of the elements in a second loop - // to avoid the constant reflow + // Set the display of the elements in a second loop to avoid constant reflow for ( index = 0; index < length; index++ ) { if ( values[ index ] != null ) { elements[ index ].style.display = values[ index ]; diff --git a/src/effects.js b/src/effects.js index 64f9353ef..43162e1fb 100644 --- a/src/effects.js +++ b/src/effects.js @@ -154,9 +154,16 @@ function defaultPrefilter( elem, props, opts ) { } display = jQuery.css( elem, "display" ); if ( display === "none" ) { - display = restoreDisplay || swap( elem, { "display": "" }, function() { - return jQuery.css( elem, "display" ); - } ); + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } } // Animate inline elements as inline-block diff --git a/test/data/testsuite.css b/test/data/testsuite.css index 50619b98d..253bea998 100644 --- a/test/data/testsuite.css +++ b/test/data/testsuite.css @@ -20,10 +20,6 @@ div#fx-tests div.overflow { overflow: visible; } -div.inline { - display: inline; -} - div.autoheight { height: auto; } @@ -68,11 +64,6 @@ div.noopacity { opacity: 0; } -div.hidden, -span.hidden { - display: none; -} - div#fx-tests div.widewidth { background-repeat: repeat-x; } @@ -134,3 +125,8 @@ section { background:#f0f; display:block; } #span-14824 { display: block; } #display { display: list-item !important; } + +.block { display: block; } +.inline { display: inline; } +.list-item { display: list-item; } +.hidden, .none { display: none; } diff --git a/test/unit/css.js b/test/unit/css.js index 4b4017ab8..4ecd08a68 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -474,26 +474,7 @@ QUnit.test( "css(Object) where values are Functions with incoming values", funct // .show(), .hide(), can be excluded from the build if ( jQuery.fn.show && jQuery.fn.hide ) { -QUnit.test( "show(); hide()", function( assert ) { - - assert.expect( 4 ); - - var hiddendiv, div; - - hiddendiv = jQuery( "div.hidden" ); - hiddendiv.hide(); - assert.equal( hiddendiv.css( "display" ), "none", "Cascade-hidden div after hide()" ); - hiddendiv.show(); - assert.equal( hiddendiv.css( "display" ), "none", "Show does not trump CSS cascade" ); - - div = jQuery( "
" ).hide(); - assert.equal( div.css( "display" ), "none", "Detached div hidden" ); - div.appendTo( "#qunit-fixture" ).show(); - assert.equal( div.css( "display" ), "block", "Initially-detached div after show()" ); - -} ); - -QUnit.test( "show();", function( assert ) { +QUnit.test( "show()", function( assert ) { assert.expect( 18 ); @@ -557,11 +538,20 @@ QUnit.test( "show();", function( assert ) { jQuery( "
test
text test" ).hide().remove(); } ); -QUnit.test( "show() resolves correct default display for detached nodes", function( assert ) { - assert.expect( 16 ); +QUnit.test( "show/hide detached nodes", function( assert ) { + assert.expect( 19 ); var div, span, tr; + div = jQuery( "
" ).hide(); + assert.equal( div.css( "display" ), "none", "hide() updates inline style of a detached div" ); + div.appendTo( "#qunit-fixture" ); + assert.equal( div.css( "display" ), "none", + "A hidden-while-detached div is hidden after attachment" ); + div.show(); + assert.equal( div.css( "display" ), "block", + "A hidden-while-detached div can be shown after attachment" ); + div = jQuery( "