Attributes: Support the until-found value for the hidden attribute

The `hidden` attribute used to be a boolean one but it gained a new
`until-found` eventually. This led us to change the way we handle boolean
attributes in jQuery 4.0 in gh-5452 to avoid these issues in the future.

That said, currently from the attributes we treat as boolean only `hidden`
has gained an extra value, let's support it.

Ref gh-5388
Ref gh-5452
This commit is contained in:
Michał Gołębiowski-Owczarek 2025-01-05 13:43:25 +01:00
parent fc874a0e12
commit 2aba711389
No known key found for this signature in database
2 changed files with 41 additions and 5 deletions

View File

@ -10,7 +10,13 @@ define( [
"use strict"; "use strict";
var boolHook, 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( { jQuery.fn.extend( {
attr: function( name, value ) { attr: function( name, value ) {
@ -110,8 +116,13 @@ boolHook = {
// Remove boolean attributes when set to false // Remove boolean attributes when set to false
jQuery.removeAttr( elem, name ); jQuery.removeAttr( elem, name );
} else { } else if (
( extraBoolAttrValues[ name.toLowerCase() ] || [] )
.indexOf( String( value ).toLowerCase() ) === -1
) {
elem.setAttribute( name, name ); elem.setAttribute( name, name );
} else {
elem.setAttribute( name, value );
} }
return name; 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 // Avoid an infinite loop by temporarily removing this function from the getter
handle = attrHandle[ lowercaseName ]; handle = attrHandle[ lowercaseName ];
attrHandle[ lowercaseName ] = ret; attrHandle[ lowercaseName ] = ret;
ret = getter( elem, name, isXML ) != null ?
lowercaseName : ret = getter( elem, name, isXML );
null; if ( ret != null ) {
if ( ( extraBoolAttrValues[ lowercaseName ] || [] )
.indexOf( ret.toLowerCase() ) === -1
) {
ret = lowercaseName;
}
}
attrHandle[ lowercaseName ] = handle; attrHandle[ lowercaseName ] = handle;
} }
return ret; return ret;

View File

@ -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)" ); 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( "<div></div>" ).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 ) { QUnit.test( "attr(non-ASCII)", function( assert ) {
assert.expect( 2 ); assert.expect( 2 );