aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRichard Gibson <richard.gibson@gmail.com>2015-04-02 16:57:33 -0400
committerRichard Gibson <richard.gibson@gmail.com>2015-05-11 13:00:49 -0400
commit86419b10bfa5e3b71a7d416288ab806d47a31d1f (patch)
tree0e67bab0273e904df2f308ab26980291ec22adeb /src
parent5c3101fee60046fa7976b3131fada8dfe9fbd53e (diff)
downloadjquery-86419b10bfa5e3b71a7d416288ab806d47a31d1f.tar.gz
jquery-86419b10bfa5e3b71a7d416288ab806d47a31d1f.zip
CSS: Ignore the CSS cascade in show()/hide()/etc.
Fixes gh-1767 Fixes gh-2071 Closes gh-2180
Diffstat (limited to 'src')
-rw-r--r--src/css.js64
-rw-r--r--src/css/defaultDisplay.js71
-rw-r--r--src/css/showHide.js47
-rw-r--r--src/effects.js178
4 files changed, 151 insertions, 209 deletions
diff --git a/src/css.js b/src/css.js
index 286eef64b..7b011668e 100644
--- a/src/css.js
+++ b/src/css.js
@@ -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
index 3771be6d1..000000000
--- a/src/css/defaultDisplay.js
+++ /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
index 000000000..d0cca589b
--- /dev/null
+++ b/src/css/showHide.js
@@ -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;
+
+});
diff --git a/src/effects.js b/src/effects.js
index 4ead51ccd..3268fcda9 100644
--- a/src/effects.js
+++ b/src/effects.js
@@ -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;
}
}