Attributes: revert returning null for non-existant attributes
[jquery.git] / src / attributes / attr.js
blob9c962ef2d9b3955e61ac6650cf078cff831b37e3
1 define([
2         "../core",
3         "../var/rnotwhite",
4         "../core/access",
5         "./support",
6         "./val",
7         "../selector"
8 ], function( jQuery, rnotwhite, access, support ) {
10 var boolHook,
11         attrHandle = jQuery.expr.attrHandle,
12         ruseDefault = /^(?:checked|selected)$/i,
13         getSetInput = support.input;
15 jQuery.fn.extend({
16         attr: function( name, value ) {
17                 return access( this, jQuery.attr, name, value, arguments.length > 1 );
18         },
20         removeAttr: function( name ) {
21                 return this.each(function() {
22                         jQuery.removeAttr( this, name );
23                 });
24         }
25 });
27 jQuery.extend({
28         attr: function( elem, name, value ) {
29                 var hooks, ret,
30                         nType = elem.nodeType;
32                 // don't get/set attributes on text, comment and attribute nodes
33                 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
34                         return;
35                 }
37                 // Fallback to prop when attributes are not supported
38                 if ( typeof elem.getAttribute === "undefined" ) {
39                         return jQuery.prop( elem, name, value );
40                 }
42                 // All attributes are lowercase
43                 // Grab necessary hook if one is defined
44                 if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
45                         name = name.toLowerCase();
46                         hooks = jQuery.attrHooks[ name ] ||
47                                 ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );
48                 }
50                 if ( value !== undefined ) {
52                         if ( value === null ) {
53                                 jQuery.removeAttr( elem, name );
55                         } else if ( hooks && "set" in hooks &&
56                                 (ret = hooks.set( elem, value, name )) !== undefined ) {
58                                 return ret;
60                         } else {
61                                 elem.setAttribute( name, value + "" );
62                                 return value;
63                         }
65                 } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
66                         return ret;
68                 } else {
69                         ret = jQuery.find.attr( elem, name );
71                         // Non-existent attributes return null, we normalize to undefined
72                         return ret == null ?
73                                 undefined :
74                                 ret;
75                 }
76         },
78         removeAttr: function( elem, value ) {
79                 var name, propName,
80                         i = 0,
81                         attrNames = value && value.match( rnotwhite );
83                 if ( attrNames && elem.nodeType === 1 ) {
84                         while ( (name = attrNames[i++]) ) {
85                                 propName = jQuery.propFix[ name ] || name;
87                                 // Boolean attributes get special treatment (#10870)
88                                 if ( jQuery.expr.match.bool.test( name ) ) {
89                                         // Set corresponding property to false
90                                         if ( getSetInput || !ruseDefault.test( name ) ) {
91                                                 elem[ propName ] = false;
92                                         // Support: IE<9
93                                         // Also clear defaultChecked/defaultSelected (if appropriate)
94                                         } else {
95                                                 elem[ jQuery.camelCase( "default-" + name ) ] =
96                                                         elem[ propName ] = false;
97                                         }
98                                 }
100                                 elem.removeAttribute( name );
101                         }
102                 }
103         },
105         attrHooks: {
106                 type: {
107                         set: function( elem, value ) {
108                                 if ( !support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
109                                         // Setting the type on a radio button after the value resets the value in IE8-9
110                                         // Reset value to default in case type is set after value during creation
111                                         var val = elem.value;
112                                         elem.setAttribute( "type", value );
113                                         if ( val ) {
114                                                 elem.value = val;
115                                         }
116                                         return value;
117                                 }
118                         }
119                 }
120         }
123 // Hook for boolean attributes
124 boolHook = {
125         set: function( elem, value, name ) {
126                 if ( value === false ) {
127                         // Remove boolean attributes when set to false
128                         jQuery.removeAttr( elem, name );
129                 } else if ( getSetInput || !ruseDefault.test( name ) ) {
130                         elem.setAttribute( jQuery.propFix[ name ] || name, name );
132                 } else {
133                         // Support: IE<9
134                         // Use defaultChecked and defaultSelected for oldIE
135                         elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
136                 }
138                 return name;
139         }
142 // Retrieve booleans specially
143 jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
145         var getter = attrHandle[ name ] || jQuery.find.attr;
147         attrHandle[ name ] = getSetInput || !ruseDefault.test( name ) ?
148                 function( elem, name, isXML ) {
149                         var ret, handle;
150                         if ( !isXML ) {
151                                 // Avoid an infinite loop by temporarily removing this function from the getter
152                                 handle = attrHandle[ name ];
153                                 attrHandle[ name ] = ret;
154                                 ret = getter( elem, name, isXML ) != null ?
155                                         name.toLowerCase() :
156                                         null;
157                                 attrHandle[ name ] = handle;
158                         }
159                         return ret;
160                 } :
161                 function( elem, name, isXML ) {
162                         if ( !isXML ) {
163                                 return elem[ jQuery.camelCase( "default-" + name ) ] ?
164                                         name.toLowerCase() :
165                                         null;
166                         }
167                 };
170 // fix oldIE attroperties
171 if ( !getSetInput ) {
172         jQuery.attrHooks.value = {
173                 set: function( elem, value ) {
174                         if ( jQuery.nodeName( elem, "input" ) ) {
175                                 // Does not return so that setAttribute is also used
176                                 elem.defaultValue = value;
177                         }
178                 }
179         };
182 if ( !support.style ) {
183         jQuery.attrHooks.style = {
184                 get: function( elem ) {
185                         // Return undefined in the case of empty string
186                         // Note: IE uppercases css property names, but if we were to .toLowerCase()
187                         // .cssText, that would destroy case senstitivity in URL's, like in "background"
188                         return elem.style.cssText || undefined;
189                 },
190                 set: function( elem, value ) {
191                         return ( elem.style.cssText = value + "" );
192                 }
193         };