diff --git a/src/css.js b/src/css.js index c5c01eca..9db65996 100644 --- a/src/css.js +++ b/src/css.js @@ -9,6 +9,7 @@ var ralpha = /alpha\([^)]*\)/i, rnum = /^-?\d/, rrelNum = /^[+\-]=/, rrelNumFilter = /[^+\-\.\de]+/g, + rinputbutton = /input|button/i, cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssWidth = [ "Left", "Right" ], @@ -338,24 +339,45 @@ curCSS = getComputedStyle || currentStyle; function getWH( elem, name, extra ) { var which = name === "width" ? cssWidth : cssHeight, - val = name === "width" ? elem.offsetWidth : elem.offsetHeight; + cur = curCSS( elem, name ), - if ( extra === "border" ) { - return val; + // We're addressing the way Firefox handles certain inputs and buttons, + // offsetWidth/height actually returns a normal width/height + boxSizing = rinputbutton.test( elem.nodeName ) && + ( curCSS( elem, "-moz-box-sizing" ) === "border-box" || + curCSS( elem, "box-sizing" ) === "border-box" ); + + // IE will return auto if we try to grab a width/height that is not set + if ( boxSizing || cur === "auto" ) { + cur = name === "width" ? elem.offsetWidth : elem.offsetHeight; } - jQuery.each( which, function() { - if ( !extra ) { - val -= parseFloat(jQuery.css( elem, "padding" + this )) || 0; - } + // Make sure that IE7 returns the correct computed value for display + if ( name === "height" ) { + elem.offsetHeight; + } + + var val = parseFloat( cur ) || 0; - if ( extra === "margin" ) { - val += parseFloat(jQuery.css( elem, "margin" + this )) || 0; + if ( extra ) { + for ( var i = 0, len = which.length; i < len ; i++ ) { + var dir = which[i]; - } else { - val -= parseFloat(jQuery.css( elem, "border" + this + "Width" )) || 0; + // outerWidth/height + if ( extra === "border" || extra === "margin" ) { + val += parseFloat(jQuery.css( elem, "border" + dir + "Width" )) || 0; + val += parseFloat(jQuery.css( elem, "padding" + dir )) || 0; + + if ( extra == "margin" ) { + val += parseFloat(jQuery.css( elem, "margin" + dir )) || 0; + } + + // innerWidth/height + } else { + val += parseFloat(jQuery.css( elem, "padding" + dir )) || 0; + } } - }); + } return val; } diff --git a/src/effects.js b/src/effects.js index d19f8f61..80391d89 100644 --- a/src/effects.js +++ b/src/effects.js @@ -1,6 +1,8 @@ (function( jQuery ) { var elemdisplay = {}, + iframe = null, + iframeDoc = null, rfxtypes = /^(?:toggle|show|hide)$/, rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i, timerId, @@ -17,46 +19,6 @@ var elemdisplay = {}, window.mozRequestAnimationFrame || window.oRequestAnimationFrame; -// Animations created synchronously will run synchronously -function createFxNow() { - setTimeout( clearFxNow, 0 ); - return ( fxNow = jQuery.now() ); -} - -function clearFxNow() { - fxNow = undefined; -} - -// Try to restore the default display value of an element -// fails if a display rule has been set for this element, e.g. div { display: inline; } -function defaultDisplay( nodeName ) { - if ( !elemdisplay[ nodeName ] ) { - var elem = jQuery("<" + nodeName + ">").appendTo("body"), - display = elem.css("display"); - - elem.remove(); - - if ( display === "none" || display === "" ) { - display = "block"; - } - - elemdisplay[ nodeName ] = display; - } - - return elemdisplay[ nodeName ]; -} - -// Generate parameters to create a standard animation -function genFx( type, num ) { - var obj = {}; - - jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() { - obj[ this ] = type; - }); - - return obj; -} - jQuery.fn.extend({ show: function( speed, easing, callback ) { var elem, display; @@ -166,7 +128,6 @@ jQuery.fn.extend({ var opt = jQuery.extend({}, optall), isElement = this.nodeType === 1, hidden = isElement && jQuery(this).is(":hidden"), - self = this, name, val, p, easing, display, e, parts, start, end, unit; @@ -187,10 +148,6 @@ jQuery.fn.extend({ val = prop[p]; if ( val === "hide" && hidden || val === "show" && !hidden ) { - return opt.complete.call(self); - } - - if ( prop[p] === "hide" && hidden || prop[p] === "show" && !hidden ) { return opt.complete.call(this); } @@ -240,7 +197,7 @@ jQuery.fn.extend({ } for ( p in prop ) { - e = new jQuery.fx( self, opt, p ); + e = new jQuery.fx( this, opt, p ); val = prop[p]; @@ -257,9 +214,9 @@ jQuery.fn.extend({ // We need to compute starting value if ( unit !== "px" ) { - jQuery.style( self, p, (end || 1) + unit); + jQuery.style( this, p, (end || 1) + unit); start = ((end || 1) / e.cur()) * start; - jQuery.style( self, p, start + unit); + jQuery.style( this, p, start + unit); } // If a +=/-= token was provided, we're doing a relative animation @@ -470,7 +427,8 @@ jQuery.fx.prototype = { var t = fxNow || createFxNow(), done = true, elem = this.elem, - options = this.options; + options = this.options, + i, n; if ( gotoEnd || t >= options.duration + this.startTime ) { this.now = this.end; @@ -479,7 +437,7 @@ jQuery.fx.prototype = { options.animatedProperties[ this.prop ] = true; - for ( var i in options.animatedProperties ) { + for ( i in options.animatedProperties ) { if ( options.animatedProperties[i] !== true ) { done = false; } @@ -517,7 +475,7 @@ jQuery.fx.prototype = { if ( options.duration == Infinity ) { this.now = t; } else { - var n = t - this.startTime; + n = t - this.startTime; this.state = n / options.duration; // Perform the easing function, defaults to swing @@ -534,11 +492,11 @@ jQuery.fx.prototype = { jQuery.extend( jQuery.fx, { tick: function() { - var timers = jQuery.timers; - - for ( var i = 0; i < timers.length; i++ ) { + var timers = jQuery.timers, + i = timers.length; + while ( i-- ) { if ( !timers[i]() ) { - timers.splice(i--, 1); + timers.splice(i, 1); } } @@ -584,4 +542,73 @@ if ( jQuery.expr && jQuery.expr.filters ) { }; } +// Try to restore the default display value of an element +function defaultDisplay( nodeName ) { + + if ( !elemdisplay[ nodeName ] ) { + + var elem = jQuery( "<" + nodeName + ">" ).appendTo( "body" ), + display = elem.css( "display" ); + + elem.remove(); + + if ( display === "none" || display === "" ) { + + // Get element's real default display by attaching it to a temp iframe + // Conritbutions from Louis Remi and Julian Aurbourg + // based on recommendation by Louis Remi + + // No iframe to use yet, so create it + if ( !iframe ) { + iframe = document.createElement( "iframe" ); + iframe.frameBorder = iframe.width = iframe.height = 0; + } + + document.body.appendChild( iframe ); + + // Create a cacheable copy of the iframe document on first call. + // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake html + // document to it, Webkit & Firefox won't allow reusing the iframe document + if ( !iframeDoc || !iframe.createElement ) { + iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; + iframeDoc.write( "" ); + } + + elem = iframeDoc.createElement( nodeName ); + + iframeDoc.body.appendChild( elem ); + + display = jQuery.css( elem, "display" ); + + document.body.removeChild( iframe ); + } + + // Store the correct default display + elemdisplay[ nodeName ] = display; + } + + return elemdisplay[ nodeName ]; +} + +// Animations created synchronously will run synchronously +function createFxNow() { + setTimeout( clearFxNow, 0 ); + return ( fxNow = jQuery.now() ); +} + +function clearFxNow() { + fxNow = undefined; +} + +// Generate parameters to create a standard animation +function genFx( type, num ) { + var obj = {}; + + jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() { + obj[ this ] = type; + }); + + return obj; +} + })( jQuery ); diff --git a/test/data/testsuite.css b/test/data/testsuite.css index a9dd97ba..99851eaa 100644 --- a/test/data/testsuite.css +++ b/test/data/testsuite.css @@ -111,4 +111,9 @@ div#show-tests * { display: none; } #nothiddendivchild.prct { font-size: 150%; } /* For testing type on vml in IE #7071 */ -v\:oval { behavior:url(#default#VML); display:inline-block; } \ No newline at end of file +v\:oval { behavior:url(#default#VML); display:inline-block; } + +/* 8099 changes to default styles are read correctly */ +tt { display: none; } +sup { display: none; } +dfn { display: none; } diff --git a/test/unit/dimensions.js b/test/unit/dimensions.js index 641165f4..7019a288 100644 --- a/test/unit/dimensions.js +++ b/test/unit/dimensions.js @@ -222,3 +222,82 @@ test("outerHeight()", function() { div.remove(); jQuery.removeData($div[0], "olddisplay", true); }); + +test('width(), outerWidth(), innerWidth(), height(), outerHeight() and innerHeight() with inputs', function(){ + expect(47); + + var id = 'input-width-test-group'; + var input_els = 'submit reset button'.split(' '); + var html = '
'; + var style = 'width:35px;height:50px;padding:5px;border:1px solid #000;margin:2px;'; + + html += '
test
'; + html += '
something
'; + html += ''; + jQuery.each(input_els, function() { + html += ''; + }); + html += '
'; + + jQuery('#main').append(html); + + equals(jQuery('#nothing-set-div').width(), 100, 'Width of unset div takes on parent'); + + jQuery('#width-div-1, #width-button-1, .width-input').each(function(){ + + // Test widths + var w = jQuery(this).width(); + var outer_w = jQuery(this).outerWidth(); + var outer_w_margin = jQuery(this).outerWidth(true); + var inner_w = jQuery(this).innerWidth(); + var t = this.tagName.toLowerCase() + ((this.type) ? '[' + this.type + ']' : ''); + + equals(w, 35, 'Make sure width() works for ' + t); + equals(outer_w, 47, 'Make sure outerWidth() works for ' + t); + equals(outer_w_margin, 51, 'Make sure outerWidth(true) works for ' + t); + equals(inner_w, 45, 'Make sure innerWidth() works for ' + t); + + // Test heights + var h = jQuery(this).height(); + var outer_h = jQuery(this).outerHeight(); + var outer_h_margin = jQuery(this).outerHeight(true); + var inner_h = jQuery(this).innerHeight(); + + equals(h, 50, 'Make sure height() works for ' + t); + equals(outer_h, 62, 'Make sure outerHeight() works for ' + t); + equals(outer_h_margin, 66, 'Make sure outerHeight(true) works for ' + t); + equals(inner_h, 60, 'Make sure innerHeight() works for ' + t); + + }); + + var inputsub = jQuery('.width-input').filter('input[type=submit]'); + + inputsub.css({ + width: 10, + padding: 0, + margin: '3px', + border: '1px solid red', + height: 15 + }); + + var w = inputsub.width(); + equals(w, 10, 'width() works after setting css using .css()'); + + var outer_w = inputsub.outerWidth(); + equals(outer_w, 12, 'outerWidth() works after setting css using .css()'); + + var outer_w_margin = inputsub.outerWidth(true); + equals(outer_w_margin, 18, 'outerWidth(true) works after setting css using .css()'); + + var h = inputsub.height(); + equals(h, 15, 'height() works after setting css using .css()'); + + var outer_h = inputsub.outerHeight(); + equals(outer_h, 17, 'outerHeight() works after setting css using .css()'); + + var outer_h_margin = inputsub.outerHeight(true); + equals(outer_h_margin, 23, 'outerHeight(true) works after setting css using .css()'); + + jQuery('#' + id).remove(); + +}); diff --git a/test/unit/effects.js b/test/unit/effects.js index 4faf6174..8b7cf467 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -162,6 +162,28 @@ test("Persist correct display value", function() { }); }); +test("show() resolves correct default display #8099", function() { + expect(7); + var tt8099 = jQuery("").appendTo("body"), + dfn8099 = jQuery("", { html: "foo"}).appendTo("body"); + + equals( tt8099.css("display"), "none", "default display override for all tt" ); + equals( tt8099.show().css("display"), "inline", "Correctly resolves display:inline" ); + + equals( jQuery("#foo").hide().show().css("display"), "block", "Correctly resolves display:block after hide/show" ); + + equals( tt8099.hide().css("display"), "none", "default display override for all tt" ); + equals( tt8099.show().css("display"), "inline", "Correctly resolves display:inline" ); + + equals( dfn8099.css("display"), "none", "default display override for all dfn" ); + equals( dfn8099.show().css("display"), "inline", "Correctly resolves display:inline" ); + + tt8099.remove(); + dfn8099.remove(); + +}); + + test("animate(Hash, Object, Function)", function() { expect(1); stop();