06-attributes.js | |
---|---|
jQuery Annotated Source. | |
Attributes | var rclass = /[\n\t\r]/g,
rspace = /\s+/,
rreturn = /\r/g,
rtype = /^(?:button|input)$/i,
rfocusable = /^(?:button|input|object|select|textarea)$/i,
rclickable = /^a(?:rea)?$/i,
rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
rinvalidChar = /\:|^on/,
formHook, boolHook;
jQuery.fn.extend({
attr: function( name, value ) {
return jQuery.access( this, name, value, true, jQuery.attr );
},
removeAttr: function( name ) {
return this.each(function() {
jQuery.removeAttr( this, name );
});
},
prop: function( name, value ) {
return jQuery.access( this, name, value, true, jQuery.prop );
},
removeProp: function( name ) {
name = jQuery.propFix[ name ] || name;
return this.each(function() { |
try/catch handles cases where IE balks (such as removing a property on window) | try {
this[ name ] = undefined;
delete this[ name ];
} catch( e ) {}
});
},
addClass: function( value ) {
var classNames, i, l, elem,
setClass, c, cl;
if ( jQuery.isFunction( value ) ) {
return this.each(function( j ) {
jQuery( this ).addClass( value.call(this, j, this.className) );
});
}
if ( value && typeof value === "string" ) {
classNames = value.split( rspace );
for ( i = 0, l = this.length; i < l; i++ ) {
elem = this[ i ];
if ( elem.nodeType === 1 ) {
if ( !elem.className && classNames.length === 1 ) {
elem.className = value;
} else {
setClass = " " + elem.className + " ";
for ( c = 0, cl = classNames.length; c < cl; c++ ) {
if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
setClass += classNames[ c ] + " ";
}
}
elem.className = jQuery.trim( setClass );
}
}
}
}
return this;
},
removeClass: function( value ) {
var classNames, i, l, elem, className, c, cl;
if ( jQuery.isFunction( value ) ) {
return this.each(function( j ) {
jQuery( this ).removeClass( value.call(this, j, this.className) );
});
}
if ( (value && typeof value === "string") || value === undefined ) {
classNames = (value || "").split( rspace );
for ( i = 0, l = this.length; i < l; i++ ) {
elem = this[ i ];
if ( elem.nodeType === 1 && elem.className ) {
if ( value ) {
className = (" " + elem.className + " ").replace( rclass, " " );
for ( c = 0, cl = classNames.length; c < cl; c++ ) {
className = className.replace(" " + classNames[ c ] + " ", " ");
}
elem.className = jQuery.trim( className );
} else {
elem.className = "";
}
}
}
}
return this;
},
toggleClass: function( value, stateVal ) {
var type = typeof value,
isBool = typeof stateVal === "boolean";
if ( jQuery.isFunction( value ) ) {
return this.each(function( i ) {
jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
});
}
return this.each(function() {
if ( type === "string" ) { |
toggle individual class names | var className,
i = 0,
self = jQuery( this ),
state = stateVal,
classNames = value.split( rspace );
while ( (className = classNames[ i++ ]) ) { |
check each className given, space seperated list | state = isBool ? state : !self.hasClass( className );
self[ state ? "addClass" : "removeClass" ]( className );
}
} else if ( type === "undefined" || type === "boolean" ) {
if ( this.className ) { |
store className if set | jQuery._data( this, "__className__", this.className );
} |
toggle whole className | this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
}
});
},
hasClass: function( selector ) {
var className = " " + selector + " ";
for ( var i = 0, l = this.length; i < l; i++ ) {
if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
return true;
}
}
return false;
},
val: function( value ) {
var hooks, ret,
elem = this[0];
if ( !arguments.length ) {
if ( elem ) {
hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ];
if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
return ret;
}
ret = elem.value;
return typeof ret === "string" ? |
handle most common string cases | ret.replace(rreturn, "") : |
handle cases where value is null/undef or number | ret == null ? "" : ret;
}
return undefined;
}
var isFunction = jQuery.isFunction( value );
return this.each(function( i ) {
var self = jQuery(this), val;
if ( this.nodeType !== 1 ) {
return;
}
if ( isFunction ) {
val = value.call( this, i, self.val() );
} else {
val = value;
} |
Treat null/undefined as ""; convert numbers to string | if ( val == null ) {
val = "";
} else if ( typeof val === "number" ) {
val += "";
} else if ( jQuery.isArray( val ) ) {
val = jQuery.map(val, function ( value ) {
return value == null ? "" : value + "";
});
}
hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; |
If set returns undefined, fall back to normal setting | if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
this.value = val;
}
});
}
});
jQuery.extend({
valHooks: {
option: {
get: function( elem ) { |
attributes.value is undefined in Blackberry 4.7 but uses .value. See #6932 | var val = elem.attributes.value;
return !val || val.specified ? elem.value : elem.text;
}
},
select: {
get: function( elem ) {
var value,
index = elem.selectedIndex,
values = [],
options = elem.options,
one = elem.type === "select-one"; |
Nothing was selected | if ( index < 0 ) {
return null;
} |
Loop through all the selected options | for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
var option = options[ i ]; |
Don't return options that are disabled or in a disabled optgroup | if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
(!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { |
Get the specific value for the option | value = jQuery( option ).val(); |
We don't need an array for one selects | if ( one ) {
return value;
} |
Multi-Selects return an array | values.push( value );
}
} |
Fixes Bug #2551 -- select.val() broken in IE after form.reset() | if ( one && !values.length && options.length ) {
return jQuery( options[ index ] ).val();
}
return values;
},
set: function( elem, value ) {
var values = jQuery.makeArray( value );
jQuery(elem).find("option").each(function() {
this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
});
if ( !values.length ) {
elem.selectedIndex = -1;
}
return values;
}
}
},
attrFn: {
val: true,
css: true,
html: true,
text: true,
data: true,
width: true,
height: true,
offset: true
},
attrFix: { |
Always normalize to ensure hook usage | tabindex: "tabIndex"
},
attr: function( elem, name, value, pass ) {
var nType = elem.nodeType;
|
don't get/set attributes on text, comment and attribute nodes | if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
return undefined;
}
if ( pass && name in jQuery.attrFn ) {
return jQuery( elem )[ name ]( value );
} |
Fallback to prop when attributes are not supported | if ( !("getAttribute" in elem) ) {
return jQuery.prop( elem, name, value );
}
var ret, hooks,
notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); |
Normalize the name if needed | if ( notxml ) {
name = jQuery.attrFix[ name ] || name;
hooks = jQuery.attrHooks[ name ];
if ( !hooks ) { |
Use boolHook for boolean attributes | if ( rboolean.test( name ) ) {
hooks = boolHook; |
Use formHook for forms and if the name contains certain characters | } else if ( formHook && name !== "className" &&
(jQuery.nodeName( elem, "form" ) || rinvalidChar.test( name )) ) {
hooks = formHook;
}
}
}
if ( value !== undefined ) {
if ( value === null ) {
jQuery.removeAttr( elem, name );
return undefined;
} else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
return ret;
} else {
elem.setAttribute( name, "" + value );
return value;
}
} else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
return ret;
} else {
ret = elem.getAttribute( name ); |
Non-existent attributes return null, we normalize to undefined | return ret === null ?
undefined :
ret;
}
},
removeAttr: function( elem, name ) {
var propName;
if ( elem.nodeType === 1 ) {
name = jQuery.attrFix[ name ] || name;
if ( jQuery.support.getSetAttribute ) { |
Use removeAttribute in browsers that support it | elem.removeAttribute( name );
} else {
jQuery.attr( elem, name, "" );
elem.removeAttributeNode( elem.getAttributeNode( name ) );
} |
Set corresponding property to false for boolean attributes | if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) {
elem[ propName ] = false;
}
}
},
attrHooks: {
type: {
set: function( elem, value ) { |
We can't allow the type property to be changed (since it causes problems in IE) | if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
jQuery.error( "type property can't be changed" );
} else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { |
Setting the type on a radio button after the value resets the value in IE6-9 Reset value to it's default in case type is set after value This is for element creation | var val = elem.value;
elem.setAttribute( "type", value );
if ( val ) {
elem.value = val;
}
return value;
}
}
},
tabIndex: {
get: function( elem ) { |
elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ | var attributeNode = elem.getAttributeNode("tabIndex");
return attributeNode && attributeNode.specified ?
parseInt( attributeNode.value, 10 ) :
rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
0 :
undefined;
}
}, |
Use the value property for back compat Use the formHook for button elements in IE6/7 (#1954) | value: {
get: function( elem, name ) {
if ( formHook && jQuery.nodeName( elem, "button" ) ) {
return formHook.get( elem, name );
}
return name in elem ?
elem.value :
null;
},
set: function( elem, value, name ) {
if ( formHook && jQuery.nodeName( elem, "button" ) ) {
return formHook.set( elem, value, name );
} |
Does not return so that setAttribute is also used | elem.value = value;
}
}
},
propFix: {
tabindex: "tabIndex",
readonly: "readOnly",
"for": "htmlFor",
"class": "className",
maxlength: "maxLength",
cellspacing: "cellSpacing",
cellpadding: "cellPadding",
rowspan: "rowSpan",
colspan: "colSpan",
usemap: "useMap",
frameborder: "frameBorder",
contenteditable: "contentEditable"
},
prop: function( elem, name, value ) {
var nType = elem.nodeType; |
don't get/set properties on text, comment and attribute nodes | if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
return undefined;
}
var ret, hooks,
notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
if ( notxml ) { |
Fix name and attach hooks | name = jQuery.propFix[ name ] || name;
hooks = jQuery.propHooks[ name ];
}
if ( value !== undefined ) {
if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
return ret;
} else {
return (elem[ name ] = value);
}
} else {
if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== undefined ) {
return ret;
} else {
return elem[ name ];
}
}
},
propHooks: {}
}); |
Hook for boolean attributes | boolHook = {
get: function( elem, name ) { |
Align boolean attributes with corresponding properties | return jQuery.prop( elem, name ) ?
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;
}
elem.setAttribute( name, name.toLowerCase() );
}
return name;
}
}; |
IE6/7 do not support getting/setting some attributes with get/setAttribute | if ( !jQuery.support.getSetAttribute ) { |
propFix is more comprehensive and contains all fixes | jQuery.attrFix = jQuery.propFix;
|
Use this for any attribute on a form in IE6/7 | formHook = jQuery.attrHooks.name = jQuery.attrHooks.title = jQuery.valHooks.button = {
get: function( elem, name ) {
var ret;
ret = elem.getAttributeNode( name ); |
Return undefined if nodeValue is empty string | return ret && ret.nodeValue !== "" ?
ret.nodeValue :
undefined;
},
set: function( elem, value, name ) { |
Check form objects in IE (multiple bugs related) Only use nodeValue if the attribute node exists on the form | var ret = elem.getAttributeNode( name );
if ( ret ) {
ret.nodeValue = value;
return value;
}
}
}; |
Set width and height to auto instead of 0 on empty string( Bug #8150 ) This is for removals | jQuery.each([ "width", "height" ], function( i, name ) {
jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
set: function( elem, value ) {
if ( value === "" ) {
elem.setAttribute( name, "auto" );
return value;
}
}
});
});
} |
Some attributes require a special call on IE | if ( !jQuery.support.hrefNormalized ) {
jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
get: function( elem ) {
var ret = elem.getAttribute( name, 2 );
return ret === null ? undefined : ret;
}
});
});
}
if ( !jQuery.support.style ) {
jQuery.attrHooks.style = {
get: function( elem ) { |
Return undefined in the case of empty string Normalize to lowercase since IE uppercases css property names | return elem.style.cssText.toLowerCase() || undefined;
},
set: function( elem, value ) {
return (elem.style.cssText = "" + value);
}
};
} |
Safari mis-reports the default selected property of an option Accessing the parent's selectedIndex property fixes it | if ( !jQuery.support.optSelected ) {
jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
get: function( elem ) {
var parent = elem.parentNode;
if ( parent ) {
parent.selectedIndex; |
Make sure that it also works with optgroups, see #5701 | if ( parent.parentNode ) {
parent.parentNode.selectedIndex;
}
}
}
});
} |
Radios and checkboxes getter/setter | if ( !jQuery.support.checkOn ) {
jQuery.each([ "radio", "checkbox" ], function() {
jQuery.valHooks[ this ] = {
get: function( elem ) { |
Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified | return elem.getAttribute("value") === null ? "on" : elem.value;
}
};
});
}
jQuery.each([ "radio", "checkbox" ], function() {
jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
set: function( elem, value ) {
if ( jQuery.isArray( value ) ) {
return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0);
}
}
});
});
|