aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Gibson <richard.gibson@gmail.com>2016-01-11 02:26:55 -0500
committerTimmy Willison <timmywillisn@gmail.com>2016-01-13 16:05:09 -0500
commitdba93f79c405373ec3a492fd0a4bf89b3136a6e6 (patch)
tree49aca78a21bb34ebb7d834a270c090b9de91522a
parenta268f5225cad9ab380494e61a10105cc9eb107e7 (diff)
downloadjquery-dba93f79c405373ec3a492fd0a4bf89b3136a6e6.tar.gz
jquery-dba93f79c405373ec3a492fd0a4bf89b3136a6e6.zip
CSS: Restore cascade-override behavior in .show
Fixes gh-2654 Fixes gh-2308 Close gh-2810 Ref 86419b10bfa5e3b71a7d416288ab806d47a31d1f
-rw-r--r--src/css/showHide.js44
-rw-r--r--src/effects.js13
-rw-r--r--test/data/testsuite.css14
-rw-r--r--test/unit/css.js275
-rw-r--r--test/unit/effects.js161
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( "<div>" ).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( "<div>test</div> text <span>test</span>" ).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( "<div>" ).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( "<div class='hidden'>" );
div.show().appendTo( "#qunit-fixture" );
assert.equal( div.css( "display" ), "none",
@@ -664,6 +654,247 @@ QUnit.test( "show() after hide() should always set display to initial value (#14
assert.equal( div.css( "display" ), "list-item", "should get last set display value" );
} );
+QUnit.test( "show/hide 3.0, default display", function( assert ) {
+
+ assert.expect( 36 );
+
+ var i,
+ $elems = jQuery( "<div/>" )
+ .appendTo( "#qunit-fixture" )
+ .html( "<div data-expected-display='block'/>" +
+ "<span data-expected-display='inline'/>" +
+ "<ul><li data-expected-display='list-item'/></ul>" )
+ .find( "[data-expected-display]" );
+
+ $elems.each( function() {
+ var $elem = jQuery( this ),
+ name = this.nodeName,
+ expected = this.getAttribute( "data-expected-display" ),
+ sequence = [];
+
+ if ( this.className ) {
+ name += "." + this.className;
+ }
+ if ( this.getAttribute( "style" ) ) {
+ name += "[style='" + this.getAttribute( "style" ) + "']";
+ }
+ name += " ";
+
+ for ( i = 0; i < 3; i++ ) {
+ sequence.push( ".show()" );
+ $elem.show();
+ assert.equal( $elem.css( "display" ), expected,
+ name + sequence.join( "" ) + " computed" );
+ assert.equal( this.style.display, "", name + sequence.join( "" ) + " inline" );
+
+ sequence.push( ".hide()" );
+ $elem.hide();
+ assert.equal( $elem.css( "display" ), "none",
+ name + sequence.join( "" ) + " computed" );
+ assert.equal( this.style.display, "none", name + sequence.join( "" ) + " inline" );
+ }
+ } );
+} );
+
+QUnit.test( "show/hide 3.0, default body display", function( assert ) {
+
+ assert.expect( 2 );
+
+ var hideBody = supportjQuery( "<style>body{display:none}</style>" ).appendTo( document.head ),
+ body = jQuery( document.body );
+
+ assert.equal( body.css( "display" ), "none", "Correct initial display" );
+
+ body.show();
+
+ assert.equal( body.css( "display" ), "block", "Correct display after .show()" );
+
+ hideBody.remove();
+} );
+
+QUnit.test( "show/hide 3.0, cascade display", function( assert ) {
+
+ assert.expect( 36 );
+
+ var i,
+ $elems = jQuery( "<div/>" )
+ .appendTo( "#qunit-fixture" )
+ .html( "<span class='block'/><div class='inline'/><div class='list-item'/>" )
+ .children();
+
+ $elems.each( function() {
+ var $elem = jQuery( this ),
+ name = this.nodeName,
+ sequence = [];
+
+ if ( this.className ) {
+ name += "." + this.className;
+ }
+ if ( this.getAttribute( "style" ) ) {
+ name += "[style='" + this.getAttribute( "style" ) + "']";
+ }
+ name += " ";
+
+ for ( i = 0; i < 3; i++ ) {
+ sequence.push( ".show()" );
+ $elem.show();
+ assert.equal( $elem.css( "display" ), this.className,
+ name + sequence.join( "" ) + " computed" );
+ assert.equal( this.style.display, "", name + sequence.join( "" ) + " inline" );
+
+ sequence.push( ".hide()" );
+ $elem.hide();
+ assert.equal( $elem.css( "display" ), "none",
+ name + sequence.join( "" ) + " computed" );
+ assert.equal( this.style.display, "none", name + sequence.join( "" ) + " inline" );
+ }
+ } );
+} );
+
+QUnit.test( "show/hide 3.0, inline display", function( assert ) {
+
+ assert.expect( 96 );
+
+ var i,
+ $elems = jQuery( "<div/>" )
+ .appendTo( "#qunit-fixture" )
+ .html( "<span data-expected-display='block' style='display:block'/>" +
+ "<span class='list-item' data-expected-display='block' style='display:block'/>" +
+ "<div data-expected-display='inline' style='display:inline'/>" +
+ "<div class='list-item' data-expected-display='inline' style='display:inline'/>" +
+ "<ul>" +
+ "<li data-expected-display='block' style='display:block'/>" +
+ "<li class='inline' data-expected-display='block' style='display:block'/>" +
+ "<li data-expected-display='inline' style='display:inline'/>" +
+ "<li class='block' data-expected-display='inline' style='display:inline'/>" +
+ "</ul>" )
+ .find( "[data-expected-display]" );
+
+ $elems.each( function() {
+ var $elem = jQuery( this ),
+ name = this.nodeName,
+ expected = this.getAttribute( "data-expected-display" ),
+ sequence = [];
+
+ if ( this.className ) {
+ name += "." + this.className;
+ }
+ if ( this.getAttribute( "style" ) ) {
+ name += "[style='" + this.getAttribute( "style" ) + "']";
+ }
+ name += " ";
+
+ for ( i = 0; i < 3; i++ ) {
+ sequence.push( ".show()" );
+ $elem.show();
+ assert.equal( $elem.css( "display" ), expected,
+ name + sequence.join( "" ) + " computed" );
+ assert.equal( this.style.display, expected, name + sequence.join( "" ) + " inline" );
+
+ sequence.push( ".hide()" );
+ $elem.hide();
+ assert.equal( $elem.css( "display" ), "none",
+ name + sequence.join( "" ) + " computed" );
+ assert.equal( this.style.display, "none", name + sequence.join( "" ) + " inline" );
+ }
+ } );
+} );
+
+QUnit.test( "show/hide 3.0, cascade hidden", function( assert ) {
+
+ assert.expect( 72 );
+
+ var i,
+ $elems = jQuery( "<div/>" )
+ .appendTo( "#qunit-fixture" )
+ .html( "<div class='hidden' data-expected-display='block'/>" +
+ "<div class='hidden' data-expected-display='block' style='display:none'/>" +
+ "<span class='hidden' data-expected-display='inline'/>" +
+ "<span class='hidden' data-expected-display='inline' style='display:none'/>" +
+ "<ul>" +
+ "<li class='hidden' data-expected-display='list-item'/>" +
+ "<li class='hidden' data-expected-display='list-item' style='display:none'/>" +
+ "</ul>" )
+ .find( "[data-expected-display]" );
+
+ $elems.each( function() {
+ var $elem = jQuery( this ),
+ name = this.nodeName,
+ expected = this.getAttribute( "data-expected-display" ),
+ sequence = [];
+
+ if ( this.className ) {
+ name += "." + this.className;
+ }
+ if ( this.getAttribute( "style" ) ) {
+ name += "[style='" + this.getAttribute( "style" ) + "']";
+ }
+ name += " ";
+
+ for ( i = 0; i < 3; i++ ) {
+ sequence.push( ".hide()" );
+ $elem.hide();
+ assert.equal( $elem.css( "display" ), "none",
+ name + sequence.join( "" ) + " computed" );
+ assert.equal( this.style.display, "none", name + sequence.join( "" ) + " inline" );
+
+ sequence.push( ".show()" );
+ $elem.show();
+ assert.equal( $elem.css( "display" ), expected,
+ name + sequence.join( "" ) + " computed" );
+ assert.equal( this.style.display, expected, name + sequence.join( "" ) + " inline" );
+ }
+ } );
+} );
+
+QUnit.test( "show/hide 3.0, inline hidden", function( assert ) {
+
+ assert.expect( 84 );
+
+ var i,
+ $elems = jQuery( "<div/>" )
+ .appendTo( "#qunit-fixture" )
+ .html( "<span data-expected-display='inline' style='display:none'/>" +
+ "<span class='list-item' data-expected-display='list-item' style='display:none'/>" +
+ "<div data-expected-display='block' style='display:none'/>" +
+ "<div class='list-item' data-expected-display='list-item' style='display:none'/>" +
+ "<ul>" +
+ "<li data-expected-display='list-item' style='display:none'/>" +
+ "<li class='block' data-expected-display='block' style='display:none'/>" +
+ "<li class='inline' data-expected-display='inline' style='display:none'/>" +
+ "</ul>" )
+ .find( "[data-expected-display]" );
+
+ $elems.each( function() {
+ var $elem = jQuery( this ),
+ name = this.nodeName,
+ expected = this.getAttribute( "data-expected-display" ),
+ sequence = [];
+
+ if ( this.className ) {
+ name += "." + this.className;
+ }
+ if ( this.getAttribute( "style" ) ) {
+ name += "[style='" + this.getAttribute( "style" ) + "']";
+ }
+ name += " ";
+
+ for ( i = 0; i < 3; i++ ) {
+ sequence.push( ".hide()" );
+ $elem.hide();
+ assert.equal( $elem.css( "display" ), "none",
+ name + sequence.join( "" ) + " computed" );
+ assert.equal( this.style.display, "none", name + sequence.join( "" ) + " inline" );
+
+ sequence.push( ".show()" );
+ $elem.show();
+ assert.equal( $elem.css( "display" ), expected,
+ name + sequence.join( "" ) + " computed" );
+ assert.equal( this.style.display, "", name + sequence.join( "" ) + " inline" );
+ }
+ } );
+} );
+
}
QUnit[ jQuery.find.compile && jQuery.fn.toggle ? "test" : "skip" ]( "toggle()", function( assert ) {
diff --git a/test/unit/effects.js b/test/unit/effects.js
index 33357deda..ae43674bd 100644
--- a/test/unit/effects.js
+++ b/test/unit/effects.js
@@ -5,7 +5,11 @@ if ( !jQuery.fx ) {
return;
}
-var oldRaf = window.requestAnimationFrame;
+var oldRaf = window.requestAnimationFrame,
+ hideOptions = {
+ inline: function() { jQuery.style( this, "display", "none" ); },
+ cascade: function() { this.className = "hidden"; }
+ };
QUnit.module( "effects", {
setup: function() {
@@ -131,98 +135,103 @@ QUnit.test( "show()", function( assert ) {
jQuery( "<div>test</div> text <span>test</span>" ).hide().remove();
} );
-QUnit.test( "show(Number) - other displays", function( assert ) {
- assert.expect( 30 );
-
- jQuery(
- "<div id='show-tests'>" +
- "<div><p><a href='#'></a></p><code></code><pre></pre><span></span></div>" +
- "<table><thead><tr><th></th></tr></thead><tbody><tr><td></td></tr></tbody></table>" +
- "<ul><li></li></ul></div>" +
- "<table id='test-table'></table>"
- ).appendTo( "#qunit-fixture" ).find( "*" ).css( "display", "none" );
-
- var test,
- old = jQuery( "#test-table" ).show().css( "display" ) !== "table";
-
- jQuery( "#test-table" ).remove();
-
- // Note: inline elements are expected to be inline-block
- // because we're showing width/height
- // Can't animate width/height inline
- // See #14344
- test = {
- "div": "block",
- "p": "block",
- "a": "inline",
- "code": "inline",
- "pre": "block",
- "span": "inline",
- "table": old ? "block" : "table",
- "thead": old ? "block" : "table-header-group",
- "tbody": old ? "block" : "table-row-group",
- "tr": old ? "block" : "table-row",
- "th": old ? "block" : "table-cell",
- "td": old ? "block" : "table-cell",
- "ul": "block",
- "li": old ? "block" : "list-item"
- };
+supportjQuery.each( hideOptions, function( type, setup ) {
+ QUnit.test( "show(Number) - " + type + " hidden", function( assert ) {
+ assert.expect( 30 );
+
+ jQuery(
+ "<div id='show-tests'>" +
+ "<div><p><a href='#'></a></p><code></code><pre></pre><span></span></div>" +
+ "<table><thead><tr><th></th></tr></thead><tbody><tr><td></td></tr></tbody>" +
+ "</table>" +
+ "<ul><li></li></ul></div>" +
+ "<table id='test-table'></table>"
+ ).appendTo( "#qunit-fixture" ).find( "*" ).each( setup );
+
+ var test,
+ old = jQuery( "#test-table" ).show().css( "display" ) !== "table";
+
+ jQuery( "#test-table" ).remove();
+
+ // Note: inline elements are expected to be inline-block
+ // because we're showing width/height
+ // Can't animate width/height inline
+ // See #14344
+ test = {
+ "div": "block",
+ "p": "block",
+ "a": "inline",
+ "code": "inline",
+ "pre": "block",
+ "span": "inline",
+ "table": old ? "block" : "table",
+ "thead": old ? "block" : "table-header-group",
+ "tbody": old ? "block" : "table-row-group",
+ "tr": old ? "block" : "table-row",
+ "th": old ? "block" : "table-cell",
+ "td": old ? "block" : "table-cell",
+ "ul": "block",
+ "li": old ? "block" : "list-item"
+ };
- jQuery.each( test, function( selector ) {
- jQuery( selector, "#show-tests" ).show( 100 );
- } );
- this.clock.tick( 50 );
- jQuery.each( test, function( selector, expected ) {
- jQuery( selector, "#show-tests" ).each( function() {
- assert.equal(
- jQuery( this ).css( "display" ),
- expected === "inline" ? "inline-block" : expected,
- "Correct display type during animation for " + selector
- );
+ jQuery.each( test, function( selector ) {
+ jQuery( selector, "#show-tests" ).show( 100 );
} );
- } );
- this.clock.tick( 50 );
- jQuery.each( test, function( selector, expected ) {
- jQuery( selector, "#show-tests" ).each( function() {
- assert.equal( jQuery( this ).css( "display" ), expected,
- "Correct display type after animation for " + selector );
+ this.clock.tick( 50 );
+ jQuery.each( test, function( selector, expected ) {
+ jQuery( selector, "#show-tests" ).each( function() {
+ assert.equal(
+ jQuery( this ).css( "display" ),
+ expected === "inline" ? "inline-block" : expected,
+ "Correct display type during animation for " + selector
+ );
+ } );
+ } );
+ this.clock.tick( 50 );
+ jQuery.each( test, function( selector, expected ) {
+ jQuery( selector, "#show-tests" ).each( function() {
+ assert.equal( jQuery( this ).css( "display" ), expected,
+ "Correct display type after animation for " + selector );
+ } );
} );
- } );
- jQuery( "#show-tests" ).remove();
+ jQuery( "#show-tests" ).remove();
+ } );
} );
// Supports #7397
-QUnit.test( "Persist correct display value", function( assert ) {
- assert.expect( 3 );
+supportjQuery.each( hideOptions, function( type, setup ) {
+ QUnit.test( "Persist correct display value - " + type + " hidden", function( assert ) {
+ assert.expect( 3 );
- jQuery( "<div id='show-tests'><span style='position:absolute;'>foo</span></div>" )
- .appendTo( "#qunit-fixture" ).find( "*" ).css( "display", "none" );
+ jQuery( "<div id='show-tests'><span style='position:absolute;'>foo</span></div>" )
+ .appendTo( "#qunit-fixture" ).find( "*" ).each( setup );
- var $span = jQuery( "#show-tests span" ),
- displayNone = $span.css( "display" ),
- display = "",
- clock = this.clock;
+ var $span = jQuery( "#show-tests span" ),
+ displayNone = $span.css( "display" ),
+ display = "",
+ clock = this.clock;
- $span.show();
+ $span.show();
- display = $span.css( "display" );
+ display = $span.css( "display" );
- $span.hide();
+ $span.hide();
- $span.fadeIn( 100, function() {
- assert.equal( $span.css( "display" ), display, "Expecting display: " + display );
- $span.fadeOut( 100, function() {
- assert.equal( $span.css( "display" ), displayNone, "Expecting display: " + displayNone );
- $span.fadeIn( 100, function() {
- assert.equal( $span.css( "display" ), display, "Expecting display: " + display );
+ $span.fadeIn( 100, function() {
+ assert.equal( $span.css( "display" ), display, "Expecting display: " + display );
+ $span.fadeOut( 100, function() {
+ assert.equal( $span.css( "display" ), displayNone, "Expecting display: " + displayNone );
+ $span.fadeIn( 100, function() {
+ assert.equal( $span.css( "display" ), display, "Expecting display: " + display );
+ } );
} );
} );
- } );
- clock.tick( 300 );
+ clock.tick( 300 );
- assert.expectJqData( this, $span, "olddisplay" );
+ assert.expectJqData( this, $span, "olddisplay" );
+ } );
} );
QUnit.test( "animate(Hash, Object, Function)", function( assert ) {