diff options
author | Richard Gibson <richard.gibson@gmail.com> | 2012-12-09 00:26:24 -0500 |
---|---|---|
committer | Richard Gibson <richard.gibson@gmail.com> | 2012-12-15 23:16:48 -0500 |
commit | a763ae72775f69509d0a8a6b50702bcf2c7e6fbf (patch) | |
tree | b88d062c5199bec72e02e3145c0120aea542fb1d /src/attributes.js | |
parent | 55a8ba52268ba0ef33cb750f5795add38f29d067 (diff) | |
download | jquery-a763ae72775f69509d0a8a6b50702bcf2c7e6fbf.tar.gz jquery-a763ae72775f69509d0a8a6b50702bcf2c7e6fbf.zip |
Fix #11115: Normalize boolean attributes/properties. Close gh-1066.
Diffstat (limited to 'src/attributes.js')
-rw-r--r-- | src/attributes.js | 83 |
1 files changed, 50 insertions, 33 deletions
diff --git a/src/attributes.js b/src/attributes.js index 9d603e419..bba4efe39 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -3,8 +3,10 @@ var nodeHook, boolHook, rreturn = /\r/g, rfocusable = /^(?:input|select|textarea|button|object)$/i, rclickable = /^(?:a|area)$/i, - rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, - getSetAttribute = jQuery.support.getSetAttribute; + rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i, + ruseDefault = /^(?:checked|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute, + getSetInput = jQuery.support.input; jQuery.fn.extend({ attr: function( name, value ) { @@ -338,26 +340,31 @@ jQuery.extend({ }, removeAttr: function( elem, value ) { - var name, propName, isBool, + var name, propName, i = 0, attrNames = value && value.match( core_rnotwhite ); if ( attrNames && elem.nodeType === 1 ) { while ( (name = attrNames[i++]) ) { propName = jQuery.propFix[ name ] || name; - isBool = rboolean.test( name ); + + // Boolean attributes get special treatment (#10870) + if ( rboolean.test( name ) ) { + // Set corresponding property to false for boolean attributes + // Also clear defaultChecked/defaultSelected (if appropriate) for IE<8 + if ( !getSetAttribute && ruseDefault.test( name ) ) { + elem[ jQuery.camelCase( "default-" + name ) ] = + elem[ propName ] = false; + } else { + elem[ propName ] = false; + } // See #9699 for explanation of this approach (setting first, then removal) - // Do not do this for boolean attributes (see #10870) - if ( !isBool ) { + } else { jQuery.attr( elem, name, "" ); } - elem.removeAttribute( getSetAttribute ? name : propName ); - // Set corresponding property to false for boolean attributes - if ( isBool && propName in elem ) { - elem[ propName ] = false; - } + elem.removeAttribute( getSetAttribute ? name : propName ); } } }, @@ -449,36 +456,48 @@ jQuery.extend({ // Hook for boolean attributes boolHook = { get: function( elem, name ) { - // Align boolean attributes with corresponding properties - // Fall back to attribute presence where some booleans are not supported - var attrNode, - property = jQuery.prop( elem, name ); - return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? + var + // Use .prop to determine if this attribute is understood as boolean + prop = jQuery.prop( elem, name ), + + // Fetch it accordingly + attr = typeof prop === "boolean" && elem.getAttribute( name ), + detail = typeof prop === "boolean" ? + + getSetInput && getSetAttribute ? + attr != null : + // oldIE fabricates an empty string for missing boolean attributes + // and conflates checked/selected into attroperties + ruseDefault.test( name ) ? + elem[ jQuery.camelCase( "default-" + name ) ] : + !!attr : + + // fetch an attribute node for properties not recognized as boolean + elem.getAttributeNode( name ); + + return detail && detail.value !== false ? name.toLowerCase() : 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 - propName = jQuery.propFix[ name ] || name; - if ( propName in elem ) { - // Only set the IDL specifically if it already exists on the element - elem[ propName ] = true; - } + } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { + // IE<8 needs the *property* name + elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name ); - elem.setAttribute( name, name.toLowerCase() ); + // Use defaultChecked and defaultSelected for oldIE + } else { + elem[ jQuery.camelCase( "default-" + name ) ] = true; } + return name; } }; // fix oldIE value attroperty -if ( !getSetAttribute || !jQuery.support.valueAttribute ) { +if ( !getSetInput || !getSetAttribute ) { jQuery.attrHooks.value = { get: function( elem, name ) { var ret = elem.getAttributeNode( name ); @@ -524,12 +543,10 @@ if ( !getSetAttribute ) { ret.value = value += ""; - // Break association with cloned elements (#9646) - if ( name !== "value" && value !== elem.getAttribute( name ) ) { - elem.setAttribute( name, value ); - } - - return value; + // Break association with cloned elements by also using setAttribute (#9646) + return name === "value" || value === elem.getAttribute( name ) ? + value : + undefined; } }; |