]> source.dussan.org Git - jquery.git/commitdiff
CSS: Ignore the CSS cascade in show()/hide()/etc.
authorRichard Gibson <richard.gibson@gmail.com>
Thu, 2 Apr 2015 20:57:33 +0000 (16:57 -0400)
committerRichard Gibson <richard.gibson@gmail.com>
Mon, 11 May 2015 17:00:49 +0000 (13:00 -0400)
Fixes gh-1767
Fixes gh-2071
Closes gh-2180

src/css.js
src/css/defaultDisplay.js [deleted file]
src/css/showHide.js [new file with mode: 0644]
src/effects.js
test/data/testsuite.css
test/unit/css.js
test/unit/effects.js

index 286eef64bf380356c4d1b4a5e035be354ef4a833..7b011668ef6f171ad8338f926c862451c332e263 100644 (file)
@@ -11,16 +11,15 @@ define([
        "./css/var/swap",
        "./css/curCSS",
        "./css/adjustCSS",
-       "./css/defaultDisplay",
        "./css/addGetHookIf",
        "./css/support",
-       "./data/var/dataPriv",
+       "./css/showHide",
 
        "./core/init",
        "./core/ready",
        "./selector" // contains
 ], function( jQuery, pnum, access, rmargin, rcssNum, rnumnonpx, cssExpand, isHidden,
-       getStyles, swap, curCSS, adjustCSS, defaultDisplay, addGetHookIf, support, dataPriv ) {
+       getStyles, swap, curCSS, adjustCSS, addGetHookIf, support, showHide ) {
 
 var
        // Swappable if display is none or starts with table
@@ -151,65 +150,6 @@ function getWidthOrHeight( elem, name, extra ) {
        ) + "px";
 }
 
-function showHide( elements, show ) {
-       var display, elem, hidden,
-               values = [],
-               index = 0,
-               length = elements.length;
-
-       for ( ; index < length; index++ ) {
-               elem = elements[ index ];
-               if ( !elem.style ) {
-                       continue;
-               }
-
-               values[ index ] = dataPriv.get( elem, "olddisplay" );
-               display = elem.style.display;
-               if ( show ) {
-                       // Reset the inline display of this element to learn if it is
-                       // being hidden by cascaded rules or not
-                       if ( !values[ index ] && 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 === "" && isHidden( elem ) ) {
-                               values[ index ] = dataPriv.access(
-                                       elem,
-                                       "olddisplay",
-                                       defaultDisplay(elem.nodeName)
-                               );
-                       }
-               } else {
-                       hidden = isHidden( elem );
-
-                       if ( display !== "none" || !hidden ) {
-                               dataPriv.set(
-                                       elem,
-                                       "olddisplay",
-                                       hidden ? display : jQuery.css( elem, "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.extend({
 
        // Add in style property hooks for overriding the default
diff --git a/src/css/defaultDisplay.js b/src/css/defaultDisplay.js
deleted file mode 100644 (file)
index 3771be6..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-define([
-       "../core",
-       "../var/document",
-       "../manipulation" // appendTo
-], function( jQuery, document ) {
-
-var iframe,
-       elemdisplay = {
-
-               // Support: Firefox
-               // We have to pre-define these values for FF (#10227)
-               HTML: "block",
-               BODY: "block"
-       };
-
-/**
- * Retrieve the actual display of a element
- * @param {String} name nodeName of the element
- * @param {Object} doc Document object
- */
-// Called only from within defaultDisplay
-function actualDisplay( name, doc ) {
-       var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
-
-               display = jQuery.css( elem[ 0 ], "display" );
-
-       // We don't have any data stored on the element,
-       // so use "detach" method as fast way to get rid of the element
-       elem.detach();
-
-       return display;
-}
-
-/**
- * Try to determine the default display value of an element
- * @param {String} nodeName
- */
-function defaultDisplay( nodeName ) {
-       var doc = document,
-               display = elemdisplay[ nodeName ];
-
-       if ( !display ) {
-               display = actualDisplay( nodeName, doc );
-
-               // If the simple way fails, read from inside an iframe
-               if ( display === "none" || !display ) {
-
-                       // Use the already-created iframe if possible
-                       iframe = (iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" ))
-                               .appendTo( doc.documentElement );
-
-                       // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
-                       doc = iframe[ 0 ].contentDocument;
-
-                       // Support: IE
-                       doc.write();
-                       doc.close();
-
-                       display = actualDisplay( nodeName, doc );
-                       iframe.detach();
-               }
-
-               // Store the correct default display
-               elemdisplay[ nodeName ] = display;
-       }
-
-       return display;
-}
-
-return defaultDisplay;
-});
diff --git a/src/css/showHide.js b/src/css/showHide.js
new file mode 100644 (file)
index 0000000..d0cca58
--- /dev/null
@@ -0,0 +1,47 @@
+define([
+       "../data/var/dataPriv"
+], function( dataPriv ) {
+
+function showHide( elements, show ) {
+       var display, elem,
+               values = [],
+               index = 0,
+               length = elements.length;
+
+       // Determine new display value for elements that need to change
+       for ( ; index < length; index++ ) {
+               elem = elements[ index ];
+               if ( !elem.style ) {
+                       continue;
+               }
+
+               display = elem.style.display;
+               if ( show ) {
+                       if ( display === "none" ) {
+                               // Restore a pre-hide() value if we have one
+                               values[ index ] = dataPriv.get( elem, "display" ) || "";
+                       }
+               } else {
+                       if ( display !== "none" ) {
+                               values[ index ] = "none";
+
+                               // Remember the value we're replacing
+                               dataPriv.set( elem, "display", display );
+                       }
+               }
+       }
+
+       // Set the display of the elements in a second loop
+       // to avoid the constant reflow
+       for ( index = 0; index < length; index++ ) {
+               if ( values[ index ] != null ) {
+                       elements[ index ].style.display = values[ index ];
+               }
+       }
+
+       return elements;
+}
+
+return showHide;
+
+});
index 4ead51ccd61bfa6861b509e6383ba4c1cde489b1..3268fcda9a380a206b5608fdd9a691b89d604339 100644 (file)
@@ -4,18 +4,19 @@ define([
        "./var/rcssNum",
        "./css/var/cssExpand",
        "./css/var/isHidden",
+       "./css/var/swap",
        "./css/adjustCSS",
-       "./css/defaultDisplay",
        "./data/var/dataPriv",
+       "./css/showHide",
 
        "./core/init",
-       "./effects/Tween",
        "./queue",
-       "./css",
        "./deferred",
-       "./traversing"
-], function( jQuery, document, rcssNum, cssExpand,
-       isHidden, adjustCSS, defaultDisplay, dataPriv ) {
+       "./traversing",
+       "./manipulation",
+       "./css",
+       "./effects/Tween"
+], function( jQuery, document, rcssNum, cssExpand, isHidden, swap, adjustCSS, dataPriv, showHide ) {
 
 var
        fxNow, timerId,
@@ -82,14 +83,15 @@ function createTween( value, prop, animation ) {
 
 function defaultPrefilter( elem, props, opts ) {
        /* jshint validthis: true */
-       var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
+       var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,
+               isBox = "width" in props || "height" in props,
                anim = this,
                orig = {},
                style = elem.style,
                hidden = elem.nodeType && isHidden( elem ),
                dataShow = dataPriv.get( elem, "fxshow" );
 
-       // Handle queue: false promises
+       // Queue-skipping animations hijack the fx hooks
        if ( !opts.queue ) {
                hooks = jQuery._queueHooks( elem, "fx" );
                if ( hooks.unqueued == null ) {
@@ -114,24 +116,69 @@ function defaultPrefilter( elem, props, opts ) {
                });
        }
 
-       // Height/width overflow pass
-       if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
-               // Make sure that nothing sneaks out
-               // Record all 3 overflow attributes because IE9-10 do not
-               // change the overflow attribute when overflowX and
-               // overflowY are set to the same value
+       // Detect show/hide animations
+       for ( prop in props ) {
+               value = props[ prop ];
+               if ( rfxtypes.test( value ) ) {
+                       delete props[ prop ];
+                       toggle = toggle || value === "toggle";
+                       if ( value === ( hidden ? "hide" : "show" ) ) {
+
+                               // Pretend to be hidden if this is a "show" and
+                               // there is still data from a stopped show/hide
+                               if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
+                                       hidden = true;
+
+                               // Ignore all other no-op show/hide data
+                               } else {
+                                       continue;
+                               }
+                       }
+                       orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
+               }
+       }
+
+       // Bail out if this is a no-op like .hide().hide()
+       propTween = !jQuery.isEmptyObject( props );
+       if ( !propTween && jQuery.isEmptyObject( orig ) ) {
+               return;
+       }
+
+       // Restrict "overflow" and "display" styles during box animations
+       if ( isBox && elem.nodeType === 1 ) {
+               // Support: IE 9 - 11
+               // Record all 3 overflow attributes because IE does not infer the shorthand
+               // from identically-valued overflowX and overflowY
                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
+               // Identify a display type, preferring old show/hide data over the CSS cascade
+               restoreDisplay = dataShow && dataShow.display;
+               if ( restoreDisplay == null ) {
+                       restoreDisplay = dataPriv.get( elem, "display" );
+               }
                display = jQuery.css( elem, "display" );
+               if ( display === "none" ) {
+                       display = restoreDisplay || swap( elem, { "display": "" }, function() {
+                               return jQuery.css( elem, "display" );
+                       } );
+               }
 
-               // Test default display if display is currently "none"
-               checkDisplay = display === "none" ?
-                       dataPriv.get( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
-
-               if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
-                       style.display = "inline-block";
+               // Animate inline elements as inline-block
+               if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) {
+                       if ( jQuery.css( elem, "float" ) === "none" ) {
+
+                               // Restore the original display value at the end of pure show/hide animations
+                               if ( !propTween ) {
+                                       anim.done(function() {
+                                               style.display = restoreDisplay;
+                                       });
+                                       if ( restoreDisplay == null ) {
+                                               display = style.display;
+                                               restoreDisplay = display === "none" ? "" : display;
+                                       }
+                               }
+                               style.display = "inline-block";
+                       }
                }
        }
 
@@ -144,73 +191,52 @@ function defaultPrefilter( elem, props, opts ) {
                });
        }
 
-       // show/hide pass
-       for ( prop in props ) {
-               value = props[ prop ];
-               if ( rfxtypes.exec( value ) ) {
-                       delete props[ prop ];
-                       toggle = toggle || value === "toggle";
-                       if ( value === ( hidden ? "hide" : "show" ) ) {
+       // Implement show/hide animations
+       propTween = false;
+       for ( prop in orig ) {
 
-                               // If there is dataShow left over from a stopped hide or show
-                               // and we are going to proceed with show, we should pretend to be hidden
-                               if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
-                                       hidden = true;
-                               } else {
-                                       continue;
+               // General show/hide setup for this element animation
+               if ( !propTween ) {
+                       if ( dataShow ) {
+                               if ( "hidden" in dataShow ) {
+                                       hidden = dataShow.hidden;
                                }
+                       } else {
+                               dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } );
                        }
-                       orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
 
-               // Any non-fx value stops us from restoring the original display value
-               } else {
-                       display = undefined;
-               }
-       }
+                       // Store hidden/visible for toggle so `.stop().toggle()` "reverses"
+                       if ( toggle ) {
+                               dataShow.hidden = !hidden;
+                       }
 
-       if ( !jQuery.isEmptyObject( orig ) ) {
-               if ( dataShow ) {
-                       if ( "hidden" in dataShow ) {
-                               hidden = dataShow.hidden;
+                       // Show elements before animating them
+                       if ( hidden ) {
+                               showHide( [ elem ], true );
                        }
-               } else {
-                       dataShow = dataPriv.access( elem, "fxshow", {} );
-               }
 
-               // Store state if its toggle - enables .stop().toggle() to "reverse"
-               if ( toggle ) {
-                       dataShow.hidden = !hidden;
-               }
-               if ( hidden ) {
-                       jQuery( elem ).show();
-               } else {
+                       /* jshint -W083 */
                        anim.done(function() {
-                               jQuery( elem ).hide();
+                               // The final step of a "hide" animation is actually hiding the element
+                               if ( !hidden ) {
+                                       showHide( [ elem ] );
+                               }
+                               dataPriv.remove( elem, "fxshow" );
+                               for ( prop in orig ) {
+                                       jQuery.style( elem, prop, orig[ prop ] );
+                               }
                        });
                }
-               anim.done(function() {
-                       var prop;
 
-                       dataPriv.remove( elem, "fxshow" );
-                       for ( prop in orig ) {
-                               jQuery.style( elem, prop, orig[ prop ] );
-                       }
-               });
-               for ( prop in orig ) {
-                       tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
-
-                       if ( !( prop in dataShow ) ) {
-                               dataShow[ prop ] = tween.start;
-                               if ( hidden ) {
-                                       tween.end = tween.start;
-                                       tween.start = prop === "width" || prop === "height" ? 1 : 0;
-                               }
+               // Per-property setup
+               propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+               if ( !( prop in dataShow ) ) {
+                       dataShow[ prop ] = propTween.start;
+                       if ( hidden ) {
+                               propTween.end = propTween.start;
+                               propTween.start = prop === "width" || prop === "height" ? 1 : 0;
                        }
                }
-
-       // If this is a noop like .hide().hide(), restore an overwritten display value
-       } else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) {
-               style.display = display;
        }
 }
 
index cf2ba8c205b1eba22849c402cbac2c4030f8f801..50619b98d75d4edf17102d85333ce01792027e2f 100644 (file)
@@ -68,7 +68,8 @@ div.noopacity {
        opacity: 0;
 }
 
-div.hidden {
+div.hidden,
+span.hidden {
        display: none;
 }
 
@@ -116,19 +117,10 @@ div#fx-tests div.noback {
        display: none;
 }
 
-/* tests to ensure jQuery can determine the native display mode of elements
-   that have been set as display: none in stylesheets */
-div#show-tests * { display: none; }
-
 #nothiddendiv { font-size: 16px; }
 #nothiddendivchild.em { font-size: 2em; }
 #nothiddendivchild.prct { font-size: 150%; }
 
-/* 8099 changes to default styles are read correctly */
-tt { display: none; }
-sup { display: none; }
-dfn { display: none; }
-
 /* #9239 Attach a background to the body( avoid crashes in removing the test element in support ) */
 body, div { background: url(http://static.jquery.com/files/rocker/images/logo_jquery_215x53.gif) no-repeat -1000px 0; }
 
index 3117b12d7dfd8a97d1002d6eeaa87543a6234ffb..b977b067cb3c424a27a1df0442e659acb9c8d7de 100644 (file)
@@ -475,14 +475,14 @@ test("show(); hide()", function() {
 
        hiddendiv = jQuery("div.hidden");
        hiddendiv.hide();
-       equal( hiddendiv.css("display"), "none", "Non-detached div hidden" );
+       equal( hiddendiv.css("display"), "none", "Cascade-hidden div after hide()" );
        hiddendiv.show();
-       equal( hiddendiv.css("display"), "block", "Pre-hidden div shown" );
+       equal( hiddendiv.css("display"), "none", "Show does not trump CSS cascade" );
 
        div = jQuery("<div>").hide();
        equal( div.css("display"), "none", "Detached div hidden" );
        div.appendTo("#qunit-fixture").show();
-       equal( div.css("display"), "block", "Pre-hidden div shown" );
+       equal( div.css("display"), "block", "Initially-detached div after show()" );
 
 });
 
@@ -490,8 +490,8 @@ test("show();", function() {
 
        expect( 18 );
 
-  var hiddendiv, div, pass, old, test;
-       hiddendiv = jQuery("div.hidden");
+       var hiddendiv, div, pass, old, test;
+               hiddendiv = jQuery("div.hidden");
 
        equal(jQuery.css( hiddendiv[0], "display"), "none", "hiddendiv is display: none");
 
@@ -512,8 +512,13 @@ test("show();", function() {
        });
        ok( pass, "Show" );
 
-       // #show-tests * is set display: none in CSS
-       jQuery("#qunit-fixture").append("<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>");
+       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" );
 
        old = jQuery("#test-table").show().css("display") !== "table";
        jQuery("#test-table").remove();
@@ -545,129 +550,88 @@ test("show();", function() {
        jQuery("<div>test</div> text <span>test</span>").hide().remove();
 });
 
-test("show() resolves correct default display #8099", function() {
-       expect(7);
-       var tt8099 = jQuery("<tt/>").appendTo("body"),
-                       dfn8099 = jQuery("<dfn/>", { "html": "foo"}).appendTo("body");
-
-       equal( tt8099.css("display"), "none", "default display override for all tt" );
-       equal( tt8099.show().css("display"), "inline", "Correctly resolves display:inline" );
-
-       equal( jQuery("#foo").hide().show().css("display"), "block", "Correctly resolves display:block after hide/show" );
-
-       equal( tt8099.hide().css("display"), "none", "default display override for all tt" );
-       equal( tt8099.show().css("display"), "inline", "Correctly resolves display:inline" );
-
-       equal( dfn8099.css("display"), "none", "default display override for all dfn" );
-       equal( dfn8099.show().css("display"), "inline", "Correctly resolves display:inline" );
-
-       tt8099.remove();
-       dfn8099.remove();
-});
-
 test( "show() resolves correct default display for detached nodes", function(){
-       expect( 13 );
+       expect( 16 );
 
-       var div, span, tr, trDisplay;
+       var div, span, tr;
 
        div = jQuery("<div class='hidden'>");
        div.show().appendTo("#qunit-fixture");
-       equal( div.css("display"), "block", "Make sure a detached, pre-hidden( through stylesheets ) div is visible." );
+       equal( div.css("display"), "none",
+               "A shown-while-detached div can be hidden by the CSS cascade" );
 
-       div = jQuery("<div style='display: none'>");
+       div = jQuery("<div><div class='hidden'></div></div>").children("div");
        div.show().appendTo("#qunit-fixture");
-       equal( div.css("display"), "block", "Make sure a detached, pre-hidden( through inline style ) div is visible." );
+       equal( div.css("display"), "none",
+               "A shown-while-detached div inside a visible div can be hidden by the CSS cascade" );
 
        span = jQuery("<span class='hidden'/>");
        span.show().appendTo("#qunit-fixture");
-       equal( span.css("display"), "inline", "Make sure a detached, pre-hidden( through stylesheets ) span has default display." );
-
-       span = jQuery("<span style='display: inline'/>");
-       span.show().appendTo("#qunit-fixture");
-       equal( span.css("display"), "inline", "Make sure a detached, pre-hidden( through inline style ) span has default display." );
-
-       div = jQuery("<div><div class='hidden'></div></div>").children("div");
-       div.show().appendTo("#qunit-fixture");
-       equal( div.css("display"), "block", "Make sure a detached, pre-hidden( through stylesheets ) div inside another visible div is visible." );
-
-       div = jQuery("<div><div style='display: none'></div></div>").children("div");
-       div.show().appendTo("#qunit-fixture");
-       equal( div.css("display"), "block", "Make sure a detached, pre-hidden( through inline style ) div inside another visible div is visible." );
+       equal( span.css("display"), "none",
+               "A shown-while-detached span can be hidden by the CSS cascade" );
 
        div = jQuery("div.hidden");
        div.detach().show();
-       equal( div.css("display"), "block", "Make sure a detached( through detach() ), pre-hidden div is visible." );
+       ok( !div[ 0 ].style.display,
+               "show() does not update inline style of a cascade-hidden-before-detach div" );
+       div.appendTo("#qunit-fixture");
+       equal( div.css("display"), "none",
+               "A shown-while-detached cascade-hidden div is hidden after attachment" );
        div.remove();
 
-       span = jQuery("<span>");
-       span.appendTo("#qunit-fixture").detach().show().appendTo("#qunit-fixture" );
-       equal( span.css("display"), "inline", "Make sure a detached( through detach() ), pre-hidden span has default display." );
+       span = jQuery("<span class='hidden'/>");
+       span.appendTo("#qunit-fixture").detach().show().appendTo("#qunit-fixture");
+       equal( span.css("display"), "none",
+               "A shown-while-detached cascade-hidden span is hidden after attachment" );
        span.remove();
 
-       div = jQuery("<div>");
+       div = jQuery( document.createElement("div") );
        div.show().appendTo("#qunit-fixture");
-       ok( !!div.get( 0 ).style.display, "Make sure not hidden div has a inline style." );
+       ok( !div[ 0 ].style.display, "A shown-while-detached div has no inline style" );
+       equal( div.css("display"), "block",
+               "A shown-while-detached div has default display after attachment" );
        div.remove();
 
-       div = jQuery( document.createElement("div") );
+       div = jQuery("<div style='display: none'>");
+       div.show();
+       equal( div[ 0 ].style.display, "",
+               "show() updates inline style of a detached inline-hidden div" );
+       div.appendTo("#qunit-fixture");
+       equal( div.css("display"), "block",
+               "A shown-while-detached inline-hidden div has default display after attachment" );
+
+       div = jQuery("<div><div style='display: none'></div></div>").children("div");
        div.show().appendTo("#qunit-fixture");
-       equal( div.css("display"), "block", "Make sure a pre-created element has default display." );
-       div.remove();
+       equal( div.css("display"), "block",
+               "A shown-while-detached inline-hidden div inside a visible div has default display " +
+               "after attachment" );
+
+       span = jQuery("<span style='display: none'/>");
+       span.show();
+       equal( span[ 0 ].style.display, "",
+               "show() updates inline style of a detached inline-hidden span" );
+       span.appendTo("#qunit-fixture");
+       equal( span.css("display"), "inline",
+               "A shown-while-detached inline-hidden span has default display after attachment" );
 
        div = jQuery("<div style='display: inline'/>");
        div.show().appendTo("#qunit-fixture");
-       equal( div.css("display"), "inline", "Make sure that element has same display when it was created." );
+       equal( div.css("display"), "inline",
+               "show() does not update inline style of a detached inline-visible div" );
        div.remove();
 
        tr = jQuery("<tr/>");
        jQuery("#table").append( tr );
-       trDisplay = tr.css( "display" );
        tr.detach().hide().show();
 
-       equal( tr[ 0 ].style.display, trDisplay, "For detached tr elements, display should always be like for attached trs" );
+       ok( !tr[ 0 ].style.display, "Not-hidden detached tr elements have no inline style" );
        tr.remove();
 
        span = jQuery("<span/>").hide().show();
-       equal( span[ 0 ].style.display, "inline", "For detached span elements, display should always be inline" );
+       ok( !span[ 0 ].style.display, "Not-hidden detached span elements have no inline style" );
        span.remove();
 });
 
-test("show() resolves correct default display #10227", 4, function() {
-       var html = jQuery( document.documentElement ),
-               body = jQuery( "body" );
-
-       body.append( "<p class='ddisplay'>a<style>body{display:none}</style></p>" );
-
-       equal( body.css("display"), "none", "Initial display for body element: none" );
-
-       body.show();
-       equal( body.css("display"), "block", "Correct display for body element: block" );
-
-       body.append( "<p class='ddisplay'>a<style>html{display:none}</style></p>" );
-
-       equal( html.css("display"), "none", "Initial display for html element: none" );
-
-       html.show();
-       equal( html.css( "display" ), "block", "Correct display for html element: block" );
-
-       jQuery( ".ddisplay" ).remove();
-});
-
-test("show() resolves correct default display when iframe display:none #12904", function() {
-       expect(2);
-
-       var ddisplay = jQuery(
-               "<p id='ddisplay'>a<style>p{display:none}iframe{display:none !important}</style></p>"
-       ).appendTo("body");
-
-       equal( ddisplay.css("display"), "none", "Initial display: none" );
-
-       ddisplay.show();
-       equal( ddisplay.css("display"), "block", "Correct display: block" );
-
-       ddisplay.remove();
-});
-
 test("toggle()", function() {
        expect(9);
        var div, oldHide,
@@ -1094,29 +1058,6 @@ asyncTest( "Clearing a Cloned Element's Style Shouldn't Clear the Original Eleme
        window.setTimeout( start, 1000 );
 });
 
-asyncTest( "Make sure initialized display value for disconnected nodes is correct (#13310)", 4, function() {
-       var display = jQuery("#display").css("display"),
-               div = jQuery("<div/>");
-
-       equal( div.css( "display", "inline" ).hide().show().appendTo("body").css( "display" ), "inline", "Initialized display value has returned" );
-       div.remove();
-
-       div.css( "display", "none" ).hide();
-       equal( jQuery._data( div[ 0 ], "olddisplay" ), undefined, "olddisplay is undefined after hiding a detached and hidden element" );
-       div.remove();
-
-       div.css( "display", "inline-block" ).hide().appendTo("body").fadeIn(function() {
-               equal( div.css( "display" ), "inline-block", "Initialized display value has returned" );
-               div.remove();
-
-               start();
-       });
-
-       equal( jQuery._data( jQuery("#display").css( "display", "inline" ).hide()[ 0 ], "olddisplay" ), display,
-       "display: * !Important value should used as initialized display" );
-       jQuery._removeData( jQuery("#display")[ 0 ] );
-});
-
 test( "show() after hide() should always set display to initial value (#14750)", 1, function() {
        var div = jQuery( "<div />" ),
                fixture = jQuery( "#qunit-fixture" );
index b2b053f3b5cb233610e15a9ae0a3d302cb9cafb1..f23342c5600b8a2563843060d717e373a6912bbe 100644 (file)
@@ -30,22 +30,13 @@ test("sanity check", function() {
        equal( jQuery("#dl:visible, #qunit-fixture:visible, #foo:visible").length, 2, "QUnit state is correct for testing effects" );
 });
 
-test("show() basic", 2, function() {
-       var div,
-               hiddendiv = jQuery("div.hidden");
-
-       hiddendiv.hide().show();
-
-       equal( hiddendiv.css("display"), "block", "Make sure a pre-hidden div is visible." );
-
-       div = jQuery("<div>").hide().appendTo("#qunit-fixture").show();
+test("show() basic", 1, function() {
+       var div = jQuery("<div>").hide().appendTo("#qunit-fixture").show();
 
        equal( div.css("display"), "block", "Make sure pre-hidden divs show" );
 
        // Clean up the detached node
        div.remove();
-
-       QUnit.expectJqData( this, hiddendiv, "olddisplay" );
 });
 
 test("show()", 27, function () {
@@ -94,8 +85,13 @@ test("show()", 27, function () {
        // Tolerate data from show()/hide()
        QUnit.expectJqData( this, div, "olddisplay" );
 
-       // #show-tests * is set display: none in CSS
-       jQuery("#qunit-fixture").append("<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>");
+       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" );
 
        old = jQuery("#test-table").show().css("display") !== "table";
        jQuery("#test-table").remove();
@@ -130,13 +126,19 @@ test("show()", 27, function () {
 });
 
 test("show(Number) - other displays", function() {
-       expect(15);
+       expect(30);
 
-       // #show-tests * is set display: none in CSS
-       jQuery("#qunit-fixture").append("<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>");
+       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
@@ -146,10 +148,10 @@ test("show(Number) - other displays", function() {
        test = {
                "div"      : "block",
                "p"        : "block",
-               "a"        : "inline-block",
-               "code"     : "inline-block",
+               "a"        : "inline",
+               "code"     : "inline",
                "pre"      : "block",
-               "span"     : "inline-block",
+               "span"     : "inline",
                "table"    : old ? "block" : "table",
                "thead"    : old ? "block" : "table-header-group",
                "tbody"    : old ? "block" : "table-row-group",
@@ -160,12 +162,26 @@ test("show(Number) - other displays", function() {
                "li"       : old ? "block" : "list-item"
        };
 
-       jQuery.each(test, function(selector, expected) {
-               var elem = jQuery(selector, "#show-tests").show(1, function() {
-                       equal( elem.css("display"), expected, "Show using correct display type 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() {
+                       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() {
+                       equal( jQuery( this ).css( "display" ), expected,
+                               "Correct display type after animation for " + selector );
                });
        });
-       this.clock.tick( 10 );
 
        jQuery("#show-tests").remove();
 });
@@ -174,8 +190,8 @@ test("show(Number) - other displays", function() {
 test("Persist correct display value", function() {
        expect(3);
 
-       // #show-tests * is set display: none in CSS
-       jQuery("#qunit-fixture").append("<div id='show-tests'><span style='position:absolute;'>foo</span></div>");
+       jQuery( "<div id='show-tests'><span style='position:absolute;'>foo</span></div>" )
+               .appendTo( "#qunit-fixture" ).find( "*" ).css( "display", "none" );
 
        var $span = jQuery("#show-tests span"),
                displayNone = $span.css("display"),
@@ -877,7 +893,7 @@ jQuery.each({
 }, function( fn, f ) {
        jQuery.each({
                "show": function( elem, prop ) {
-                       jQuery( elem ).hide( ).addClass( "wide" + prop );
+                       jQuery( elem ).hide().addClass( "wide" + prop );
                        return "show";
                },
                "hide": function( elem, prop ) {
@@ -912,15 +928,15 @@ jQuery.each({
 
                        num = 0;
                        // TODO: uncrowd this
-                       if ( t_h === "show" ) {num++;}
-                       if ( t_w === "show" ) {num++;}
-                       if ( t_w === "hide" || t_w === "show" ) {num++;}
-                       if ( t_h === "hide" || t_h === "show" ) {num++;}
-                       if ( t_o === "hide" || t_o === "show" ) {num++;}
-                       if ( t_w === "hide" ) {num++;}
-                       if ( t_o.constructor === Number ) {num += 2;}
-                       if ( t_w.constructor === Number ) {num += 2;}
-                       if ( t_h.constructor === Number ) {num +=2;}
+                       if ( t_h === "show" ) { num++; }
+                       if ( t_w === "show" ) { num++; }
+                       if ( t_w === "hide" || t_w === "show" ) { num++; }
+                       if ( t_h === "hide" || t_h === "show" ) { num++; }
+                       if ( t_o === "hide" || t_o === "show" ) { num++; }
+                       if ( t_w === "hide" ) { num++; }
+                       if ( t_o.constructor === Number ) { num += 2; }
+                       if ( t_w.constructor === Number ) { num += 2; }
+                       if ( t_h.constructor === Number ) { num += 2; }
 
                        expect( num );
 
@@ -928,13 +944,13 @@ jQuery.each({
 
                        elem.animate(anim, 50);
 
-                       jQuery.when( elem ).done(function( elem ) {
-                               var cur_o, cur_w, cur_h, old_h;
-
-                               elem = elem[ 0 ];
+                       jQuery.when( elem ).done(function( $elem ) {
+                               var cur_o, cur_w, cur_h, old_h,
+                                       elem = $elem[ 0 ];
 
                                if ( t_w === "show" ) {
-                                       equal( elem.style.display, "block", "Showing, display should block: " + elem.style.display );
+                                       equal( $elem.css( "display" ), "block",
+                                               "Showing, display should block: " + elem.style.display );
                                }
 
                                if ( t_w === "hide" || t_w === "show" ) {
@@ -1498,7 +1514,7 @@ test( "User supplied callback called after show when fx off (#8892)", 2, functio
 });
 
 test( "animate should set display for disconnected nodes", function() {
-       expect( 18 );
+       expect( 20 );
 
        var env = this,
                methods = {
@@ -1510,42 +1526,40 @@ test( "animate should set display for disconnected nodes", function() {
                        show: [ 1 ],
                        animate: [{ width: "show" }]
                },
-               $divTest = jQuery("<div>test</div>"),
-               // parentNode = null
                $divEmpty = jQuery("<div/>"),
+               $divTest = jQuery("<div>test</div>"),
                $divNone = jQuery("<div style='display: none;'/>"),
                $divInline = jQuery("<div style='display: inline;'/>"),
+               nullParentDisplay = $divEmpty.css("display"),
+               underFragmentDisplay = $divTest.css("display"),
                clock = this.clock;
 
-       strictEqual( $divTest.show()[ 0 ].style.display, "block", "set display with show() for element with parentNode = document fragment" );
-       strictEqual( $divEmpty.show()[ 0 ].style.display, "block", "set display with show() for element with parentNode = null" );
-       strictEqual( $divNone.show()[ 0 ].style.display, "block", "show() should change display if it already set to none" );
-       strictEqual( $divInline.show()[ 0 ].style.display, "inline", "show() should not change display if it already set" );
+       strictEqual( $divEmpty[ 0 ].parentNode, null, "Setup: element with null parentNode" );
+       strictEqual( ($divTest[ 0 ].parentNode || {}).nodeType, 11, "Setup: element under fragment" );
+
+       strictEqual( $divEmpty.show()[ 0 ].style.display, "",
+               "set display with show() for element with null parentNode" );
+       strictEqual( $divTest.show()[ 0 ].style.display, "",
+               "set display with show() for element under fragment" );
+       strictEqual( $divNone.show()[ 0 ].style.display, "",
+               "show() should change display if it already set to none" );
+       strictEqual( $divInline.show()[ 0 ].style.display, "inline",
+               "show() should not change display if it already set" );
 
-       QUnit.expectJqData( env, $divTest[ 0 ], "olddisplay" );
-       QUnit.expectJqData( env, $divEmpty[ 0 ], "olddisplay" );
        QUnit.expectJqData( env, $divNone[ 0 ], "olddisplay" );
 
        jQuery.each( methods, function( name, opt ) {
-               jQuery.each([
-
-                       // parentNode = document fragment
-                       jQuery("<div>test</div>"),
-
-                       // parentNode = null
-                       jQuery("<div/>")
-
-               ], function() {
-                       var callback = [function () {
-                                       strictEqual( this.style.display, "block", "set display to block with " + name );
-
-                                       QUnit.expectJqData( env, this, "olddisplay" );
+               jQuery.fn[ name ].apply( jQuery("<div/>"), opt.concat( [ function() {
+                       strictEqual( jQuery( this ).css( "display" ), nullParentDisplay,
+                               "." + name + " block with null parentNode" );
+               } ] ) );
 
-                       }];
-                       jQuery.fn[ name ].apply( this, opt.concat( callback ) );
-               });
+               jQuery.fn[ name ].apply( jQuery("<div>test</div>"), opt.concat( [ function() {
+                       strictEqual( jQuery( this ).css( "display" ), underFragmentDisplay,
+                               "." + name + " block under fragment" );
+               } ] ) );
        });
-        clock.tick( 400 );
+       clock.tick( 400 );
 });
 
 test("Animation callback should not show animated element as :animated (#7157)", 1, function() {
@@ -2185,33 +2199,6 @@ test( "Respect display value on inline elements (#14824)", 2, function() {
        clock.tick( 800 );
 });
 
-test( "Animation should go to its end state if document.hidden = true", 1, function() {
-       var height;
-       if ( Object.defineProperty ) {
-
-               // Can't rewrite document.hidden property if its host property
-               try {
-                       Object.defineProperty( document, "hidden", {
-                               get: function() {
-                                       return true;
-                               }
-                       });
-               } catch ( e ) {}
-       } else {
-               document.hidden = true;
-       }
-
-       if ( document.hidden ) {
-               height = jQuery( "#qunit-fixture" ).animate({ height: 500 } ).height();
-
-               equal( height, 500, "Animation should happen immediately if document.hidden = true" );
-               jQuery( document ).removeProp( "hidden" );
-
-       } else {
-               ok( true, "Can't run the test since we can't reproduce correct environment for it" );
-       }
-});
-
 test( "jQuery.easing._default (gh-2218)", function() {
        expect( 2 );
 
@@ -2288,4 +2275,92 @@ test( "jQuery.easing._default in Tween (gh-2218)", function() {
        delete jQuery.easing.custom;
 });
 
+test( "Display value is correct for disconnected nodes (trac-13310)", function() {
+       expect( 3 );
+
+       var div = jQuery("<div/>");
+
+       equal( div.css( "display", "inline" ).hide().show().appendTo("body").css( "display" ), "inline", "Initialized display value has returned" );
+       div.remove();
+
+       div.css( "display", "none" ).hide();
+       equal( jQuery._data( div[ 0 ], "olddisplay" ), undefined, "olddisplay is undefined after hiding a detached and hidden element" );
+       div.remove();
+
+       div.css( "display", "inline-block" ).hide().appendTo("body").fadeIn(function() {
+               equal( div.css( "display" ), "inline-block", "Initialized display value has returned" );
+               div.remove();
+       });
+       this.clock.tick( 1000 );
+});
+
+test( "Show/hide/toggle and display: inline", function() {
+       expect( 40 );
+
+       var clock = this.clock;
+
+       jQuery( "<span/><div style='display:inline' title='inline div'/>" ).each(function() {
+               var completed, interrupted,
+                       N = 100,
+                       fixture = jQuery( "#qunit-fixture" ),
+                       $el = jQuery( this ),
+                       kind = this.title || this.nodeName.toLowerCase();
+
+               // Animations allowed to complete
+               completed = jQuery.map( [
+                       $el.clone().data({ call: "hide", done: "none" }).appendTo( fixture ).hide( N ),
+                       $el.clone().data({ call: "toggle", done: "none" }).appendTo( fixture ).toggle( N ),
+                       $el.clone().data({ call: "hide+show", done: "inline" }).appendTo( fixture )
+                               .hide().show( N ),
+                       $el.clone().data({ call: "hide+toggle", done: "inline" }).appendTo( fixture )
+                               .hide().toggle( N )
+               ], function( $clone ) { return $clone[ 0 ]; } );
+
+               // Animations not allowed to complete
+               interrupted = jQuery.map( [
+                       $el.clone().data({ call: "hide+stop" }).appendTo( fixture ).hide( N ),
+                       $el.clone().data({ call: "toggle+stop" }).appendTo( fixture ).toggle( N ),
+                       $el.clone().data({ call: "hide+show+stop" }).appendTo( fixture ).hide().show( N ),
+                       $el.clone().data({ call: "hide+toggle+stop" }).appendTo( fixture ).hide().toggle( N )
+               ], function( $clone ) { return $clone[ 0 ]; } );
+
+               // All elements should be inline-block during the animation
+               clock.tick( N / 2 );
+               jQuery( completed ).each(function() {
+                       var $el = jQuery( this ),
+                               call = $el.data( "call" );
+                       strictEqual( $el.css( "display" ), "inline-block", kind + " display during " + call );
+               });
+
+               // Interrupted elements should remain inline-block
+               jQuery( interrupted ).stop();
+               clock.tick( N / 2 );
+               jQuery( interrupted ).each(function() {
+                       var $el = jQuery( this ),
+                               call = $el.data( "call" );
+                       strictEqual( $el.css( "display" ), "inline-block", kind + " display after " + call );
+               });
+
+               // Completed elements should not remain inline-block
+               clock.tick( N / 2 );
+               jQuery( completed ).each(function() {
+                       var $el = jQuery( this ),
+                               call = $el.data( "call" ),
+                               display = $el.data( "done" );
+                       strictEqual( $el.css( "display" ), display, kind + " display after " + call );
+               });
+
+               // A post-animation toggle should not make any element inline-block
+               completed = jQuery( completed.concat( interrupted ) );
+               completed.toggle( N / 2 );
+               clock.tick( N );
+               completed.each(function() {
+                       var $el = jQuery( this ),
+                               call = $el.data( "call" );
+                       ok( $el.css( "display" ) !== "inline-block",
+                               kind + " display is not inline-block after " + call + "+toggle" );
+               });
+       });
+});
+
 })();