diff --git a/src/attributes/attr.js b/src/attributes/attr.js index 4c43eb1fc..c68c87647 100644 --- a/src/attributes/attr.js +++ b/src/attributes/attr.js @@ -10,7 +10,13 @@ define( [ "use strict"; var boolHook, - attrHandle = jQuery.expr.attrHandle; + attrHandle = jQuery.expr.attrHandle, + + // Some formerly boolean attributes gained new values with special meaning. + // Skip the old boolean attr logic for those values. + extraBoolAttrValues = { + hidden: [ "until-found" ] + }; jQuery.fn.extend( { attr: function( name, value ) { @@ -110,8 +116,13 @@ boolHook = { // Remove boolean attributes when set to false jQuery.removeAttr( elem, name ); - } else { + } else if ( + ( extraBoolAttrValues[ name.toLowerCase() ] || [] ) + .indexOf( String( value ).toLowerCase() ) === -1 + ) { elem.setAttribute( name, name ); + } else { + elem.setAttribute( name, value ); } return name; } @@ -129,9 +140,16 @@ jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) // Avoid an infinite loop by temporarily removing this function from the getter handle = attrHandle[ lowercaseName ]; attrHandle[ lowercaseName ] = ret; - ret = getter( elem, name, isXML ) != null ? - lowercaseName : - null; + + ret = getter( elem, name, isXML ); + if ( ret != null ) { + if ( ( extraBoolAttrValues[ lowercaseName ] || [] ) + .indexOf( ret.toLowerCase() ) === -1 + ) { + ret = lowercaseName; + } + } + attrHandle[ lowercaseName ] = handle; } return ret; diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 34bf579b8..b2360dfc9 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -479,6 +479,24 @@ QUnit.test( "attr(String, Object)", function( assert ) { assert.equal( jQuery( "#name" ).attr( "nonexisting", undefined ).attr( "nonexisting" ), undefined, ".attr('attribute', undefined) does not create attribute (trac-5571)" ); } ); +QUnit.test( "attr( previously-boolean-attr, non-boolean-value)", function( assert ) { + assert.expect( 3 ); + + var div = jQuery( "
" ).appendTo( "#qunit-fixture" ); + + div.attr( "hidden", "foo" ); + assert.strictEqual( div.attr( "hidden" ), "hidden", + "Values normalized for previously-boolean hidden attribute" ); + + div.attr( "hidden", "until-found" ); + assert.strictEqual( div.attr( "hidden" ), "until-found", + "`until-found` value preserved for hidden attribute" ); + + div.attr( "hiDdeN", "uNtil-fOund" ); + assert.strictEqual( div.attr( "hidden" ), "uNtil-fOund", + "`uNtil-fOund` different casing preserved" ); +} ); + QUnit.test( "attr(non-ASCII)", function( assert ) { assert.expect( 2 );