From c72b0f3256672424a193040509ed63c755c805a2 Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 6 May 2011 13:49:20 -0400 Subject: [PATCH 1/9] Check empty string instead of specified as specified is inconsistent on the name attribute. Fixes #9148. --- src/attributes.js | 4 ++-- test/unit/attributes.js | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index c22e89b7..86f2d74a 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -491,8 +491,8 @@ if ( !jQuery.support.getSetAttribute ) { return elem.getAttribute( name ); } ret = elem.getAttributeNode( name ); - // Return undefined if not specified instead of empty string - return ret && ret.specified ? + // Return undefined if nodeValue is empty string + return ret && ret.nodeValue !== "" ? ret.nodeValue : undefined; }, diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 257d02d0..e0198236 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -144,7 +144,7 @@ test("attr(Hash)", function() { }); test("attr(String, Object)", function() { - expect(57); + expect(58); var div = jQuery("div").attr("foo", "bar"), fail = false; @@ -164,6 +164,8 @@ test("attr(String, Object)", function() { equals( jQuery("#name").attr("name"), "something", "Set name attribute" ); jQuery("#name").attr("name", null); equals( jQuery("#name").attr("name"), undefined, "Remove name attribute" ); + var $input = jQuery("", { name: "something" }); + equals( $input.attr("name"), "something", "Check element creation gets/sets the name attribute." ); jQuery("#check2").prop("checked", true).prop("checked", false).attr("checked", true); equals( document.getElementById("check2").checked, true, "Set checked attribute" ); From c864455ccfad13895d2af6ba287f265ee64bd348 Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 6 May 2011 14:54:47 -0400 Subject: [PATCH 2/9] Global found in dataAttr function --- src/data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data.js b/src/data.js index c2fd558f..9e5d1ab0 100644 --- a/src/data.js +++ b/src/data.js @@ -284,7 +284,7 @@ function dataAttr( elem, key, data ) { // If nothing was found internally, try to fetch any // data from the HTML5 data-* attribute if ( data === undefined && elem.nodeType === 1 ) { - name = "data-" + key.replace( rmultiDash, "$1-$2" ).toLowerCase(); + var name = "data-" + key.replace( rmultiDash, "$1-$2" ).toLowerCase(); data = elem.getAttribute( name ); From 09c0cf995b84e0cff6d86c9f63bdad2b0440466a Mon Sep 17 00:00:00 2001 From: timmywil Date: Sat, 7 May 2011 11:48:42 -0400 Subject: [PATCH 3/9] Global found in valHook for select(get) --- src/attributes.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/attributes.js b/src/attributes.js index 86f2d74a..9326f69d 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -219,7 +219,8 @@ jQuery.extend({ }, select: { get: function( elem ) { - var index = elem.selectedIndex, + var value, + index = elem.selectedIndex, values = [], options = elem.options, one = elem.type === "select-one"; From c08556327032daa21493f2b3a77f2138352fadf8 Mon Sep 17 00:00:00 2001 From: timmywil Date: Sat, 7 May 2011 14:49:04 -0400 Subject: [PATCH 4/9] Reduce the boolean list only to those that have corresponding IDLs that don't require being added to propFix; only set the IDL if it exists - See http://jsfiddle.net/timmywil/u5NLn/ for how boolean attributes are handled in every browser. --- src/attributes.js | 27 +++++++++++++++++---------- test/unit/attributes.js | 2 +- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 9326f69d..4d164470 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -6,7 +6,7 @@ var rclass = /[\n\t\r]/g, rtype = /^(?:button|input)$/i, rfocusable = /^(?:button|input|object|select|textarea)$/i, rclickable = /^a(?:rea)?$/i, - rboolean = /^(?:autofocus|autoplay|async|checked|controls|declare|defer|disabled|draggable|formnovalidate|hidden|ismap|loop|multiple|muted|noresize|noshade|nowrap|novalidate|open|pubdate|readonly|required|reversed|scoped|seamless|selected|truespeed)$/i, + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, rinvalidChar = /\:/, formHook, boolHook; @@ -311,15 +311,15 @@ jQuery.extend({ hooks = jQuery.attrHooks[ name ]; if ( !hooks ) { - // Use formHook for forms and if the name contains certain characters - if ( formHook && (jQuery.nodeName( elem, "form" ) || rinvalidChar.test( name )) ) { - hooks = formHook; - // Use boolHook for boolean attributes - } else if ( rboolean.test( name ) && - (typeof value === "boolean" || value === undefined) ) { + if ( rboolean.test( name ) && + (typeof value === "boolean" || value === undefined || value.toLowerCase() === name.toLowerCase()) ) { hooks = boolHook; + + // Use formHook for forms and if the name contains certain characters + } else if ( formHook && (jQuery.nodeName( elem, "form" ) || rinvalidChar.test( name )) ) { + hooks = formHook; } } @@ -352,6 +352,7 @@ jQuery.extend({ }, removeAttr: function( elem, name ) { + var propName; if ( elem.nodeType === 1 ) { name = jQuery.attrFix[ name ] || name; @@ -364,8 +365,8 @@ jQuery.extend({ } // Set corresponding property to false for boolean attributes - if ( rboolean.test( name ) ) { - elem[ jQuery.propFix[ name ] || name ] = false; + if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) { + elem[ propName ] = false; } } }, @@ -465,13 +466,19 @@ boolHook = { undefined; }, set: function( elem, value, name ) { + var propName; if ( value === false ) { // Remove boolean attributes when set to false jQuery.removeAttr( elem, name ); } else { // value is true since we know at this point it's type boolean and not false // Set boolean attributes to the same name and set the DOM property - elem[ jQuery.propFix[ name ] || name ] = value; + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = value; + } + elem.setAttribute( name, name.toLowerCase() ); } return name; diff --git a/test/unit/attributes.js b/test/unit/attributes.js index e0198236..3724f360 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -502,7 +502,7 @@ test("removeProp(String)", function() { strictEqual( ele.nonexisting, undefined, "removeProp works correctly on non DOM element nodes (bug #7500)." ); }); jQuery.each( [commentNode, textNode, attributeNode], function( i, ele ) { - $ele = jQuery( ele ); + var $ele = jQuery( ele ); $ele.prop( "nonexisting", "foo" ).removeProp( "nonexisting" ); strictEqual( ele.nonexisting, undefined, "removeProp works correctly on non DOM element nodes (bug #7500)." ); }); From 31268449b9255b21fad4bafd7da13c910a00af37 Mon Sep 17 00:00:00 2001 From: gnarf Date: Sat, 7 May 2011 19:18:52 -0400 Subject: [PATCH 5/9] Landing pull request 372. Test for numeric properties was using wrong variable. Fixes #9074. More Details: - https://github.com/jquery/jquery/pull/372 --- src/effects.js | 3 +-- test/unit/effects.js | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/effects.js b/src/effects.js index 832ef5da..7023461b 100644 --- a/src/effects.js +++ b/src/effects.js @@ -202,7 +202,6 @@ jQuery.fn.extend({ for ( p in prop ) { e = new jQuery.fx( this, opt, p ); - val = prop[p]; if ( rfxtypes.test(val) ) { @@ -214,7 +213,7 @@ jQuery.fn.extend({ if ( parts ) { end = parseFloat( parts[2] ); - unit = parts[3] || ( jQuery.cssNumber[ name ] ? "" : "px" ); + unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" ); // We need to compute starting value if ( unit !== "px" ) { diff --git a/test/unit/effects.js b/test/unit/effects.js index d0518217..2a43c115 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -32,7 +32,8 @@ test("show()", function() { hiddendiv.css("display",""); - var pass = true, div = jQuery("#qunit-fixture div"); + var pass = true; + div = jQuery("#qunit-fixture div"); div.show().each(function(){ if ( this.style.display == "none" ) pass = false; }); @@ -582,7 +583,7 @@ jQuery.checkOverflowDisplay = function(){ equals(jQuery.css( this, "display" ), "inline", "Display shouldn't be tampered with."); start(); -} +}; test( "jQuery.fx.prototype.cur()", 6, function() { var div = jQuery( "
" ).appendTo( "#qunit-fixture" ).css({ @@ -901,7 +902,7 @@ jQuery.makeTest = function( text ){ .after( elem ); return elem; -} +}; jQuery.makeTest.id = 1; @@ -993,3 +994,30 @@ test("animate unit-less properties (#4966)", 2, function() { start(); }); }); + +test( "animate properties missing px w/ opacity as last (#9074)", 2, function() { + expect( 6 ); + stop(); + var div = jQuery( "
" ) + .appendTo( "#qunit-fixture" ); + function cssInt( prop ) { + return parseInt( div.css( prop ), 10 ); + } + equal( cssInt( "marginLeft" ), 0, "Margin left is 0" ); + equal( cssInt( "left" ), 0, "Left is 0" ); + div.animate({ + left: 200, + marginLeft: 200, + opacity: 0 + }, 1000); + setTimeout(function() { + var ml = cssInt( "marginLeft" ), + l = cssInt( "left" ); + notEqual( ml, 0, "Margin left is not 0 after partial animate" ); + notEqual( ml, 200, "Margin left is not 200 after partial animate" ); + notEqual( l, 0, "Left is not 0 after partial animate" ); + notEqual( l, 200, "Left is not 200 after partial animate" ); + div.stop().remove(); + start(); + }, 100); +}); From 3d1c27d52ec667cea5735366a41f65344ab17a5e Mon Sep 17 00:00:00 2001 From: Daniel Pihlstrom Date: Wed, 4 May 2011 01:07:24 +0200 Subject: [PATCH 6/9] Fix per-property easing. Fixes #9067 --- src/effects.js | 9 ++++++--- test/unit/effects.js | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/effects.js b/src/effects.js index 7023461b..06be2c60 100644 --- a/src/effects.js +++ b/src/effects.js @@ -191,9 +191,12 @@ jQuery.fn.extend({ } // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default) - opt.animatedProperties[name] = jQuery.isArray( val ) ? - val[1]: - opt.specialEasing && opt.specialEasing[name] || opt.easing || 'swing'; + if(jQuery.isArray(val)) { + opt.animatedProperties[name] = val[1]; + prop[name] = val[0]; + } else { + opt.animatedProperties[name] = easing || opt.specialEasing && opt.specialEasing[name] || opt.easing || 'swing'; + } } if ( opt.overflow != null ) { diff --git a/test/unit/effects.js b/test/unit/effects.js index 2a43c115..a98b0987 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -923,9 +923,10 @@ test("jQuery.show('fast') doesn't clear radio buttons (bug #1095)", function () test("animate with per-property easing", function(){ - expect(3); + expect(5); stop(); + var data = {a:0,b:0,c:0}; var _test1_called = false; var _test2_called = false; var _default_test_called = false; @@ -934,23 +935,30 @@ test("animate with per-property easing", function(){ _test1_called = true; }; - jQuery.easing["_test2"] = function() { + jQuery.easing["_test2"] = function(p) { _test2_called = true; + return p; }; - jQuery.easing["_default_test"] = function() { + jQuery.easing["_default_test"] = function(p) { _default_test_called = true; + return p; }; - jQuery({a:0,b:0,c:0}).animate({ + jQuery(data).animate({ a: [100, "_test1"], b: [100, "_test2"], c: 100 }, 400, "_default_test", function(){ start(); + ok(_test1_called, "Easing function (1) called"); + ok(_test2_called, "Easing function (2) called"); + ok(data.b == 100, "Easing function (2) assigned correct value"); + ok(_default_test_called, "Easing function (_default) called"); + ok(data.c == 100, "Easing function (_default) assigned correct value"); }); }); From 8bb6e95b66413c484006288691a82c44ba50554e Mon Sep 17 00:00:00 2001 From: timmywil Date: Sat, 7 May 2011 20:46:38 -0400 Subject: [PATCH 7/9] Set val before hide/show check and fix easing setting; also update attributes test for autofocus - The object passed should not change so it can be used in future animates, updated src and tests accordingly. --- src/effects.js | 34 +++++++++++++++++----------------- test/unit/attributes.js | 10 +++++++--- test/unit/effects.js | 27 ++++++++++++--------------- 3 files changed, 36 insertions(+), 35 deletions(-) diff --git a/src/effects.js b/src/effects.js index 06be2c60..801f3f10 100644 --- a/src/effects.js +++ b/src/effects.js @@ -134,7 +134,7 @@ jQuery.fn.extend({ jQuery._mark( this ); } - var opt = jQuery.extend({}, optall), + var opt = jQuery.extend( {}, optall ), isElement = this.nodeType === 1, hidden = isElement && jQuery(this).is(":hidden"), name, val, p, @@ -153,10 +153,18 @@ jQuery.fn.extend({ delete prop[ p ]; } - val = prop[name]; + val = prop[ name ]; + + // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default) + if ( jQuery.isArray( val ) ) { + opt.animatedProperties[ name ] = val[ 1 ]; + val = val[ 0 ]; + } else { + opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing'; + } if ( val === "hide" && hidden || val === "show" && !hidden ) { - return opt.complete.call(this); + return opt.complete.call( this ); } if ( isElement && ( name === "height" || name === "width" ) ) { @@ -175,7 +183,7 @@ jQuery.fn.extend({ this.style.display = "inline-block"; } else { - display = defaultDisplay(this.nodeName); + display = defaultDisplay( this.nodeName ); // inline-level elements accept inline-block; // block-level elements need to be inline with layout @@ -189,14 +197,6 @@ jQuery.fn.extend({ } } } - - // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default) - if(jQuery.isArray(val)) { - opt.animatedProperties[name] = val[1]; - prop[name] = val[0]; - } else { - opt.animatedProperties[name] = easing || opt.specialEasing && opt.specialEasing[name] || opt.easing || 'swing'; - } } if ( opt.overflow != null ) { @@ -205,13 +205,13 @@ jQuery.fn.extend({ for ( p in prop ) { e = new jQuery.fx( this, opt, p ); - val = prop[p]; + val = prop[ p ]; if ( rfxtypes.test(val) ) { e[ val === "toggle" ? hidden ? "show" : "hide" : val ](); } else { - parts = rfxnum.exec(val); + parts = rfxnum.exec( val ); start = e.cur(); if ( parts ) { @@ -227,7 +227,7 @@ jQuery.fn.extend({ // If a +=/-= token was provided, we're doing a relative animation if ( parts[1] ) { - end = ((parts[1] === "-=" ? -1 : 1) * end) + start; + end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start; } e.custom( start, end, unit ); @@ -503,10 +503,10 @@ jQuery.fx.prototype = { this.now = t; } else { n = t - this.startTime; - this.state = n / options.duration; + // Perform the easing function, defaults to swing - this.pos = jQuery.easing[options.animatedProperties[this.prop]](this.state, n, 0, 1, options.duration); + this.pos = jQuery.easing[ options.animatedProperties[ this.prop ] ]( this.state, n, 0, 1, options.duration ); this.now = this.start + ((this.end - this.start) * this.pos); } // Perform the next step of the animation diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 3724f360..37e93d0a 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -138,8 +138,8 @@ test("attr(Hash)", function() { if ( this.getAttribute("foo") != "baz" && this.getAttribute("zoo") != "ping" ) pass = false; }); ok( pass, "Set Multiple Attributes" ); - equals( jQuery("#text1").attr({value: function() { return this.id; }})[0].value, "text1", "Set attribute to computed value #1" ); - equals( jQuery("#text1").attr({title: function(i) { return i; }}).attr("title"), "0", "Set attribute to computed value #2"); + equals( jQuery("#text1").attr({value: function() { return this.id; }})[0].value, "text1", "Set attribute to computed value #1" ); + equals( jQuery("#text1").attr({title: function(i) { return i; }}).attr("title"), "0", "Set attribute to computed value #2"); }); @@ -211,7 +211,11 @@ test("attr(String, Object)", function() { $p.removeAttr("nonexisting"); var $text = jQuery("#text1").attr("autofocus", true); - equals( $text.attr("autofocus"), "autofocus", "Set boolean attributes to the same name"); + if ( "autofocus" in $text[0] ) { + equals( $text.attr("autofocus"), "autofocus", "Set boolean attributes to the same name"); + } else { + equals( $text.attr("autofocus"), undefined, "autofocus stays undefined in browsers that do not support it(F<4)"); + } equals( $text.attr("autofocus", false).attr("autofocus"), undefined, "Setting autofocus attribute to false removes it"); equals( $text.attr("data-something", true).data("something"), true, "Setting data attributes are not affected by boolean settings"); equals( $text.attr("data-another", false).data("another"), false, "Setting data attributes are not affected by boolean settings" ); diff --git a/test/unit/effects.js b/test/unit/effects.js index a98b0987..56798c3f 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -695,8 +695,8 @@ jQuery.each( { jQuery(elem).css(prop,prop == "opacity" ? 0 : "0px"); return 0; } -}, function(fn, f){ - jQuery.each( { +}, function( fn, f ) { + jQuery.each({ "show": function(elem,prop){ jQuery(elem).hide().addClass("wide"+prop); return "show"; @@ -923,16 +923,17 @@ test("jQuery.show('fast') doesn't clear radio buttons (bug #1095)", function () test("animate with per-property easing", function(){ - expect(5); + expect(3); stop(); - var data = {a:0,b:0,c:0}; - var _test1_called = false; - var _test2_called = false; - var _default_test_called = false; + var data = { a:0, b:0, c:0 }, + _test1_called = false, + _test2_called = false, + _default_test_called = false; - jQuery.easing["_test1"] = function() { + jQuery.easing["_test1"] = function(p) { _test1_called = true; + return p; }; jQuery.easing["_test2"] = function(p) { @@ -952,13 +953,9 @@ test("animate with per-property easing", function(){ }, 400, "_default_test", function(){ start(); - ok(_test1_called, "Easing function (1) called"); - - ok(_test2_called, "Easing function (2) called"); - ok(data.b == 100, "Easing function (2) assigned correct value"); - - ok(_default_test_called, "Easing function (_default) called"); - ok(data.c == 100, "Easing function (_default) assigned correct value"); + ok( _test1_called, "Easing function (_test1) called" ); + ok( _test2_called, "Easing function (_test2) called" ); + ok( _default_test_called, "Easing function (_default) called" ); }); }); From 90f37aaf7aa7c6da96ab15488b63b2eb45a2e799 Mon Sep 17 00:00:00 2001 From: timmywil Date: Sat, 7 May 2011 21:26:02 -0400 Subject: [PATCH 8/9] Call extend on prop to avoid changing original properties so that per-property easing is not lost in multiple animations with the same props --- src/effects.js | 5 ++++- test/unit/effects.js | 17 ++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/effects.js b/src/effects.js index 801f3f10..88661e0e 100644 --- a/src/effects.js +++ b/src/effects.js @@ -126,6 +126,9 @@ jQuery.fn.extend({ return this.each( optall.complete, [ false ] ); } + // Do not change referenced properties as per-property easing will be lost + prop = jQuery.extend( {}, prop ); + return this[ optall.queue === false ? "each" : "queue" ](function() { // XXX 'this' does not always have a nodeName when running the // test suite @@ -158,7 +161,7 @@ jQuery.fn.extend({ // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default) if ( jQuery.isArray( val ) ) { opt.animatedProperties[ name ] = val[ 1 ]; - val = val[ 0 ]; + val = prop[ name ] = val[ 0 ]; } else { opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing'; } diff --git a/test/unit/effects.js b/test/unit/effects.js index 56798c3f..ea7f4e72 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -923,13 +923,18 @@ test("jQuery.show('fast') doesn't clear radio buttons (bug #1095)", function () test("animate with per-property easing", function(){ - expect(3); + expect(5); stop(); var data = { a:0, b:0, c:0 }, _test1_called = false, _test2_called = false, - _default_test_called = false; + _default_test_called = false, + props = { + a: [ 100, "_test1" ], + b: [ 100, "_test2" ], + c: 100 + }; jQuery.easing["_test1"] = function(p) { _test1_called = true; @@ -946,16 +951,14 @@ test("animate with per-property easing", function(){ return p; }; - jQuery(data).animate({ - a: [100, "_test1"], - b: [100, "_test2"], - c: 100 - }, 400, "_default_test", function(){ + jQuery(data).animate( props, 400, "_default_test", function(){ start(); ok( _test1_called, "Easing function (_test1) called" ); ok( _test2_called, "Easing function (_test2) called" ); ok( _default_test_called, "Easing function (_default) called" ); + equal( props.a[ 1 ], "_test1", "animate does not change original props (per-property easing would be lost)"); + equal( props.b[ 1 ], "_test2", "animate does not change original props (per-property easing would be lost)"); }); }); From 18b1cf2942cc082c1c97a2ac9bc33ad77f42d775 Mon Sep 17 00:00:00 2001 From: timmywil Date: Sat, 7 May 2011 22:01:10 -0400 Subject: [PATCH 9/9] Remove value check from formHook; other elements can use value hook --- src/attributes.js | 3 --- test/unit/attributes.js | 4 +++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 4d164470..c207a001 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -495,9 +495,6 @@ if ( !jQuery.support.getSetAttribute ) { formHook = jQuery.attrHooks.name = jQuery.attrHooks.value = jQuery.valHooks.button = { get: function( elem, name ) { var ret; - if ( name === "value" && !jQuery.nodeName( elem, "button" ) ) { - return elem.getAttribute( name ); - } ret = elem.getAttributeNode( name ); // Return undefined if nodeValue is empty string return ret && ret.nodeValue !== "" ? diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 37e93d0a..ce7775d1 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -144,7 +144,7 @@ test("attr(Hash)", function() { }); test("attr(String, Object)", function() { - expect(58); + expect(59); var div = jQuery("div").attr("foo", "bar"), fail = false; @@ -244,6 +244,8 @@ test("attr(String, Object)", function() { table.attr("cellspacing", "2"); equals( table[0].cellSpacing, "2", "Check cellspacing is correctly set" ); + equals( jQuery("#area1").attr("value"), undefined, "Value attribute retrieved correctly on textarea." ); + // for #1070 jQuery("#name").attr("someAttr", "0"); equals( jQuery("#name").attr("someAttr"), "0", "Set attribute to a string of \"0\"" );