aboutsummaryrefslogtreecommitdiffstats
path: root/src/attributes.js
diff options
context:
space:
mode:
authorRichard Gibson <richard.gibson@gmail.com>2012-12-09 00:26:24 -0500
committerRichard Gibson <richard.gibson@gmail.com>2012-12-15 23:16:48 -0500
commita763ae72775f69509d0a8a6b50702bcf2c7e6fbf (patch)
treeb88d062c5199bec72e02e3145c0120aea542fb1d /src/attributes.js
parent55a8ba52268ba0ef33cb750f5795add38f29d067 (diff)
downloadjquery-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.js83
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;
}
};