mirror of
https://github.com/jquery/jquery.git
synced 2024-11-23 02:54:22 +00:00
650 lines
17 KiB
JavaScript
650 lines
17 KiB
JavaScript
(function( jQuery ) {
|
|
|
|
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,
|
|
getSetAttribute = jQuery.support.getSetAttribute,
|
|
nodeHook, boolHook, fixSpecified;
|
|
|
|
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 + " ",
|
|
i = 0,
|
|
l = this.length;
|
|
for ( ; i < l; i++ ) {
|
|
if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
},
|
|
|
|
val: function( value ) {
|
|
var hooks, ret, isFunction,
|
|
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;
|
|
}
|
|
|
|
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, i, max, option,
|
|
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
|
|
i = one ? index : 0;
|
|
max = one ? index + 1 : options.length;
|
|
for ( ; i < max; i++ ) {
|
|
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
|
|
},
|
|
|
|
attr: function( elem, name, value, pass ) {
|
|
var ret, hooks, notxml,
|
|
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 );
|
|
}
|
|
|
|
notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
|
|
|
|
// All attributes are lowercase
|
|
// Grab necessary hook if one is defined
|
|
if ( notxml ) {
|
|
name = name.toLowerCase();
|
|
hooks = jQuery.attrHooks[ name ] || (rboolean.test( name ) ? boolHook : nodeHook);
|
|
}
|
|
|
|
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, value ) {
|
|
var propName, attrNames, name, l,
|
|
i = 0;
|
|
|
|
if ( elem.nodeType === 1 ) {
|
|
attrNames = (value || "").split( rspace );
|
|
l = attrNames.length;
|
|
|
|
for ( ; i < l; i++ ) {
|
|
name = attrNames[ i ].toLowerCase();
|
|
propName = jQuery.propFix[ name ] || name;
|
|
|
|
// See #9699 for explanation of this approach (setting first, then removal)
|
|
jQuery.attr( elem, name, "" );
|
|
elem.removeAttribute( getSetAttribute ? name : propName );
|
|
|
|
// Set corresponding property to false for boolean attributes
|
|
if ( rboolean.test( name ) && propName 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;
|
|
}
|
|
}
|
|
},
|
|
// Use the value property for back compat
|
|
// Use the nodeHook for button elements in IE6/7 (#1954)
|
|
value: {
|
|
get: function( elem, name ) {
|
|
if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
|
|
return nodeHook.get( elem, name );
|
|
}
|
|
return name in elem ?
|
|
elem.value :
|
|
null;
|
|
},
|
|
set: function( elem, value, name ) {
|
|
if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
|
|
return nodeHook.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 ret, hooks, notxml,
|
|
nType = elem.nodeType;
|
|
|
|
// don't get/set properties on text, comment and attribute nodes
|
|
if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
|
|
return undefined;
|
|
}
|
|
|
|
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 )) !== null ) {
|
|
return ret;
|
|
|
|
} else {
|
|
return elem[ name ];
|
|
}
|
|
}
|
|
},
|
|
|
|
propHooks: {
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional)
|
|
jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex;
|
|
|
|
// 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 ?
|
|
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 ( !getSetAttribute ) {
|
|
|
|
fixSpecified = {
|
|
name: true,
|
|
id: true
|
|
};
|
|
|
|
// Use this for any attribute in IE6/7
|
|
// This fixes almost every IE6/7 issue
|
|
nodeHook = jQuery.valHooks.button = {
|
|
get: function( elem, name ) {
|
|
var ret;
|
|
ret = elem.getAttributeNode( name );
|
|
return ret && (fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified) ?
|
|
ret.nodeValue :
|
|
undefined;
|
|
},
|
|
set: function( elem, value, name ) {
|
|
// Set the existing or create a new attribute node
|
|
var ret = elem.getAttributeNode( name );
|
|
if ( !ret ) {
|
|
ret = document.createAttribute( name );
|
|
elem.setAttributeNode( ret );
|
|
}
|
|
return (ret.nodeValue = value + "");
|
|
}
|
|
};
|
|
|
|
// Apply the nodeHook to tabindex
|
|
jQuery.attrHooks.tabindex.set = nodeHook.set;
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Set contenteditable to false on removals(#10429)
|
|
// Setting to empty string throws an error as an invalid value
|
|
jQuery.attrHooks.contenteditable = {
|
|
get: nodeHook.get,
|
|
set: function( elem, value, name ) {
|
|
if ( value === "" ) {
|
|
value = "false";
|
|
}
|
|
nodeHook.set( elem, value, name );
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
});
|
|
}
|
|
|
|
// IE6/7 call enctype encoding
|
|
if ( !jQuery.support.enctype ) {
|
|
jQuery.propFix.enctype = "encoding";
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
})( jQuery );
|