a";
+
all = div.getElementsByTagName( "*" );
a = div.getElementsByTagName( "a" )[ 0 ];
@@ -1215,6 +1409,9 @@ jQuery.support = (function() {
// (IE uses styleFloat instead of cssFloat)
cssFloat: !!a.style.cssFloat,
+ // Make sure unknown elements (like HTML5 elems) are handled appropriately
+ unknownElems: !!div.getElementsByTagName( "nav" ).length,
+
// Make sure that if no value is specified for a checkbox
// that it defaults to "on".
// (WebKit defaults to "" instead)
@@ -1264,7 +1461,7 @@ jQuery.support = (function() {
div.cloneNode( true ).fireEvent( "onclick" );
}
- // Check if a radio maintains it's value
+ // Check if a radio maintains its value
// after being appended to the DOM
input = document.createElement("input");
input.value = "t";
@@ -1284,7 +1481,11 @@ jQuery.support = (function() {
// Figure out if the W3C box model works as expected
div.style.width = div.style.paddingLeft = "1px";
- body = document.getElementsByTagName( "body" )[ 0 ];
+ // We don't want to do body-related feature tests on frameset
+ // documents, which lack a body. So we use
+ // document.getElementsByTagName("body")[0], which is undefined in
+ // frameset documents, while document.body isn’t. (7398)
+ body = document.getElementsByTagName("body")[ 0 ];
// We use our own, invisible, body unless the body is already present
// in which case we use a div (#9239)
testElement = document.createElement( body ? "div" : "body" );
@@ -1293,13 +1494,14 @@ jQuery.support = (function() {
width: 0,
height: 0,
border: 0,
- margin: 0
+ margin: 0,
+ background: "none"
};
if ( body ) {
jQuery.extend( testElementStyle, {
position: "absolute",
- left: -1000,
- top: -1000
+ left: "-999px",
+ top: "-999px"
});
}
for ( i in testElementStyle ) {
@@ -1391,6 +1593,49 @@ jQuery.support = (function() {
}
}
+ // Determine fixed-position support early
+ offsetSupport = (function( body, container ) {
+
+ var outer, inner, table, td, supports,
+ bodyMarginTop = parseFloat( body.style.marginTop ) || 0,
+ ptlm = "position:absolute;top:0;left:0;width:1px;height:1px;",
+ style = "style='" + ptlm + "margin:0;border:5px solid #000;padding:0;'",
+ html = "
" +
+ "
" +
+ "
";
+
+ container.style.cssText = ptlm + "border:0;visibility:hidden";
+
+ container.innerHTML = html;
+ body.insertBefore( container, body.firstChild );
+ outer = container.firstChild;
+ inner = outer.firstChild;
+ td = outer.nextSibling.firstChild.firstChild;
+
+ supports = {
+ doesNotAddBorder: (inner.offsetTop !== 5),
+ doesAddBorderForTableAndCells: (td.offsetTop === 5)
+ };
+
+ inner.style.position = "fixed";
+ inner.style.top = "20px";
+
+ // safari subtracts parent border width here which is 5px
+ supports.supportsFixedPosition = (inner.offsetTop === 20 || inner.offsetTop === 15);
+ inner.style.position = inner.style.top = "";
+
+ outer.style.overflow = "hidden";
+ outer.style.position = "relative";
+
+ supports.subtractsBorderForOverflowNotVisible = (inner.offsetTop === -5);
+ supports.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);
+
+ return supports;
+
+ })( testElement, div );
+
+ jQuery.extend( support, offsetSupport );
+
// Null connected elements to avoid leaks in IE
testElement = fragment = select = opt = body = marginDiv = div = input = null;
@@ -1404,7 +1649,7 @@ jQuery.boxModel = jQuery.support.boxModel;
var rbrace = /^(?:\{.*\}|\[.*\])$/,
- rmultiDash = /([a-z])([A-Z])/g;
+ rmultiDash = /([A-Z])/g;
jQuery.extend({
cache: {},
@@ -1427,7 +1672,6 @@ jQuery.extend({
hasData: function( elem ) {
elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
-
return !!elem && !isEmptyDataObject( elem );
},
@@ -1436,7 +1680,9 @@ jQuery.extend({
return;
}
- var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache,
+ var thisCache, ret,
+ internalKey = jQuery.expando,
+ getByName = typeof name === "string",
// We have to handle DOM nodes and JS objects differently because IE6-7
// can't GC object references properly across the DOM-JS boundary
@@ -1452,7 +1698,7 @@ jQuery.extend({
// Avoid doing any more work than we need to when trying to get data on an
// object that has no data at all
- if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) {
+ if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {
return;
}
@@ -1469,9 +1715,8 @@ jQuery.extend({
if ( !cache[ id ] ) {
cache[ id ] = {};
- // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
- // metadata on plain JS objects when the object is serialized using
- // JSON.stringify
+ // Avoids exposing jQuery metadata on plain JS objects when the object
+ // is serialized using JSON.stringify
if ( !isNode ) {
cache[ id ].toJSON = jQuery.noop;
}
@@ -1481,23 +1726,23 @@ jQuery.extend({
// shallow copied over onto the existing cache
if ( typeof name === "object" || typeof name === "function" ) {
if ( pvt ) {
- cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name);
+ cache[ id ] = jQuery.extend( cache[ id ], name );
} else {
- cache[ id ] = jQuery.extend(cache[ id ], name);
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
}
}
thisCache = cache[ id ];
- // Internal jQuery data is stored in a separate object inside the object's data
+ // jQuery data() is stored in a separate object inside the object's internal data
// cache in order to avoid key collisions between internal data and user-defined
- // data
- if ( pvt ) {
- if ( !thisCache[ internalKey ] ) {
- thisCache[ internalKey ] = {};
+ // data.
+ if ( !pvt ) {
+ if ( !thisCache.data ) {
+ thisCache.data = {};
}
- thisCache = thisCache[ internalKey ];
+ thisCache = thisCache.data;
}
if ( data !== undefined ) {
@@ -1511,10 +1756,24 @@ jQuery.extend({
return thisCache[ internalKey ] && thisCache[ internalKey ].events;
}
- return getByName ?
- // Check for both converted-to-camel and non-converted data property names
- thisCache[ jQuery.camelCase( name ) ] || thisCache[ name ] :
- thisCache;
+ // Check for both converted-to-camel and non-converted data property names
+ // If a data property was specified
+ if ( getByName ) {
+
+ // First Try to find as-is property data
+ ret = thisCache[ name ];
+
+ // Test for null|undefined property data
+ if ( ret == null ) {
+
+ // Try to find the camelCased property
+ ret = thisCache[ jQuery.camelCase( name ) ];
+ }
+ } else {
+ ret = thisCache;
+ }
+
+ return ret;
},
removeData: function( elem, name, pvt /* Internal Use Only */ ) {
@@ -1522,7 +1781,12 @@ jQuery.extend({
return;
}
- var internalKey = jQuery.expando, isNode = elem.nodeType,
+ var thisCache, i, l,
+
+ // Reference to internal data cache key
+ internalKey = jQuery.expando,
+
+ isNode = elem.nodeType,
// See jQuery.data for more information
cache = isNode ? jQuery.cache : elem,
@@ -1537,22 +1801,42 @@ jQuery.extend({
}
if ( name ) {
- var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ];
+
+ thisCache = pvt ? cache[ id ] : cache[ id ].data;
if ( thisCache ) {
- delete thisCache[ name ];
+
+ // Support space separated names
+ if ( jQuery.isArray( name ) ) {
+ name = name;
+ } else if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+
+ // split the camel cased version by spaces
+ name = jQuery.camelCase( name );
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+ name = name.split( " " );
+ }
+ }
+
+ for ( i = 0, l = name.length; i < l; i++ ) {
+ delete thisCache[ name[i] ];
+ }
// If there is no data left in the cache, we want to continue
// and let the cache object itself get destroyed
- if ( !isEmptyDataObject(thisCache) ) {
+ if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
return;
}
}
}
// See jQuery.data for more information
- if ( pvt ) {
- delete cache[ id ][ internalKey ];
+ if ( !pvt ) {
+ delete cache[ id ].data;
// Don't destroy the parent cache unless the internal data object
// had been the only thing left in it
@@ -1561,34 +1845,19 @@ jQuery.extend({
}
}
- var internalCache = cache[ id ][ internalKey ];
-
// Browsers that fail expando deletion also refuse to delete expandos on
// the window, but it will allow it on all other JS objects; other browsers
// don't care
- if ( jQuery.support.deleteExpando || cache != window ) {
+ // Ensure that `cache` is not a window object #10080
+ if ( jQuery.support.deleteExpando || !cache.setInterval ) {
delete cache[ id ];
} else {
cache[ id ] = null;
}
- // We destroyed the entire user cache at once because it's faster than
- // iterating through each key, but we need to continue to persist internal
- // data if it existed
- if ( internalCache ) {
- cache[ id ] = {};
- // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
- // metadata on plain JS objects when the object is serialized using
- // JSON.stringify
- if ( !isNode ) {
- cache[ id ].toJSON = jQuery.noop;
- }
-
- cache[ id ][ internalKey ] = internalCache;
-
- // Otherwise, we need to eliminate the expando on the node to avoid
+ // We destroyed the cache and need to eliminate the expando on the node to avoid
// false lookups in the cache for entries that no longer exist
- } else if ( isNode ) {
+ if ( isNode ) {
// IE does not allow us to delete expando properties from nodes,
// nor does it have a removeAttribute function on Document nodes;
// we must handle all of these cases
@@ -1623,14 +1892,15 @@ jQuery.extend({
jQuery.fn.extend({
data: function( key, value ) {
- var data = null;
+ var parts, attr, name,
+ data = null;
if ( typeof key === "undefined" ) {
if ( this.length ) {
data = jQuery.data( this[0] );
- if ( this[0].nodeType === 1 ) {
- var attr = this[0].attributes, name;
+ if ( this[0].nodeType === 1 && !jQuery._data( this[0], "parsedAttrs" ) ) {
+ attr = this[0].attributes;
for ( var i = 0, l = attr.length; i < l; i++ ) {
name = attr[i].name;
@@ -1640,6 +1910,7 @@ jQuery.fn.extend({
dataAttr( this[0], name, data[ name ] );
}
}
+ jQuery._data( this[0], "parsedAttrs", true );
}
}
@@ -1651,7 +1922,7 @@ jQuery.fn.extend({
});
}
- var parts = key.split(".");
+ parts = key.split(".");
parts[1] = parts[1] ? "." + parts[1] : "";
if ( value === undefined ) {
@@ -1690,7 +1961,8 @@ function dataAttr( elem, key, data ) {
// If nothing was found internally, try to fetch any
// data from the HTML5 data-* attribute
if ( data === undefined && elem.nodeType === 1 ) {
- var name = "data-" + key.replace( rmultiDash, "$1-$2" ).toLowerCase();
+
+ var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
data = elem.getAttribute( name );
@@ -1715,11 +1987,14 @@ function dataAttr( elem, key, data ) {
return data;
}
-// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON
-// property to be considered empty objects; this property always exists in
-// order to make sure JSON.stringify does not expose internal metadata
+// checks a cache object for emptiness
function isEmptyDataObject( obj ) {
for ( var name in obj ) {
+
+ // if the public data object is empty, the private is still empty
+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+ continue;
+ }
if ( name !== "toJSON" ) {
return false;
}
@@ -1735,17 +2010,17 @@ function handleQueueMarkDefer( elem, type, src ) {
var deferDataKey = type + "defer",
queueDataKey = type + "queue",
markDataKey = type + "mark",
- defer = jQuery.data( elem, deferDataKey, undefined, true );
+ defer = jQuery._data( elem, deferDataKey );
if ( defer &&
- ( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) &&
- ( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) {
+ ( src === "queue" || !jQuery._data(elem, queueDataKey) ) &&
+ ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) {
// Give room for hard-coded callbacks to fire first
// and eventually mark/queue something else on the element
setTimeout( function() {
- if ( !jQuery.data( elem, queueDataKey, undefined, true ) &&
- !jQuery.data( elem, markDataKey, undefined, true ) ) {
+ if ( !jQuery._data( elem, queueDataKey ) &&
+ !jQuery._data( elem, markDataKey ) ) {
jQuery.removeData( elem, deferDataKey, true );
- defer.resolve();
+ defer.fire();
}
}, 0 );
}
@@ -1756,7 +2031,7 @@ jQuery.extend({
_mark: function( elem, type ) {
if ( elem ) {
type = (type || "fx") + "mark";
- jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true );
+ jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 );
}
},
@@ -1769,9 +2044,9 @@ jQuery.extend({
if ( elem ) {
type = type || "fx";
var key = type + "mark",
- count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 );
+ count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 );
if ( count ) {
- jQuery.data( elem, key, count, true );
+ jQuery._data( elem, key, count );
} else {
jQuery.removeData( elem, key, true );
handleQueueMarkDefer( elem, type, "mark" );
@@ -1780,13 +2055,15 @@ jQuery.extend({
},
queue: function( elem, type, data ) {
+ var q;
if ( elem ) {
type = (type || "fx") + "queue";
- var q = jQuery.data( elem, type, undefined, true );
+ q = jQuery._data( elem, type );
+
// Speed up dequeue by getting out quickly if this is just a lookup
if ( data ) {
if ( !q || jQuery.isArray(data) ) {
- q = jQuery.data( elem, type, jQuery.makeArray(data), true );
+ q = jQuery._data( elem, type, jQuery.makeArray(data) );
} else {
q.push( data );
}
@@ -1799,8 +2076,7 @@ jQuery.extend({
type = type || "fx";
var queue = jQuery.queue( elem, type ),
- fn = queue.shift(),
- defer;
+ fn = queue.shift();
// If the fx queue is dequeued, always remove the progress sentinel
if ( fn === "inprogress" ) {
@@ -1815,7 +2091,7 @@ jQuery.extend({
}
fn.call(elem, function() {
- jQuery.dequeue(elem, type);
+ jQuery.dequeue( elem, type );
});
}
@@ -1852,7 +2128,7 @@ jQuery.fn.extend({
// Based off of the plugin by Clint Helfers, with permission.
// http://blindsignals.com/index.php/2009/07/jquery-delay/
delay: function( time, type ) {
- time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
type = type || "fx";
return this.queue( type, function() {
@@ -1890,9 +2166,9 @@ jQuery.fn.extend({
if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
- jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) {
+ jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) {
count++;
- tmp.done( resolve );
+ tmp.add( resolve );
}
}
resolve();
@@ -1910,8 +2186,7 @@ var rclass = /[\n\t\r]/g,
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;
+ nodeHook, boolHook, fixSpecified;
jQuery.fn.extend({
attr: function( name, value ) {
@@ -1923,11 +2198,11 @@ jQuery.fn.extend({
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() {
@@ -2049,7 +2324,7 @@ jQuery.fn.extend({
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 ) {
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
return true;
}
}
@@ -2060,7 +2335,7 @@ jQuery.fn.extend({
val: function( value ) {
var hooks, ret,
elem = this[0];
-
+
if ( !arguments.length ) {
if ( elem ) {
hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ];
@@ -2071,9 +2346,9 @@ jQuery.fn.extend({
ret = elem.value;
- return typeof ret === "string" ?
+ return typeof ret === "string" ?
// handle most common string cases
- ret.replace(rreturn, "") :
+ ret.replace(rreturn, "") :
// handle cases where value is null/undef or number
ret == null ? "" : ret;
}
@@ -2194,15 +2469,15 @@ jQuery.extend({
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;
@@ -2229,14 +2504,11 @@ jQuery.extend({
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;
+ // Use nodeHook if available( IE6/7 )
+ } else if ( nodeHook ) {
+ hooks = nodeHook;
}
}
}
@@ -2269,22 +2541,26 @@ jQuery.extend({
}
},
- removeAttr: function( elem, name ) {
- var propName;
+ removeAttr: function( elem, value ) {
+ var propName, attrNames, name, l,
+ i = 0;
+
if ( elem.nodeType === 1 ) {
- name = jQuery.attrFix[ name ] || name;
-
- if ( jQuery.support.getSetAttribute ) {
- // Use removeAttribute in browsers that support it
- elem.removeAttribute( name );
- } else {
+ attrNames = (value || "").split( rspace );
+ l = attrNames.length;
+
+ for ( ; i < l; i++ ) {
+ name = attrNames[ i ];
+ name = jQuery.attrFix[ name ] || name;
+
+ // See #9699 for explanation of this approach (setting first, then removal)
jQuery.attr( elem, name, "" );
- elem.removeAttributeNode( elem.getAttributeNode( name ) );
- }
+ elem.removeAttribute( name );
- // Set corresponding property to false for boolean attributes
- if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) {
- elem[ propName ] = false;
+ // Set corresponding property to false for boolean attributes
+ if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) {
+ elem[ propName ] = false;
+ }
}
}
},
@@ -2308,33 +2584,20 @@ jQuery.extend({
}
}
},
- 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)
+ // Use the nodeHook for button elements in IE6/7 (#1954)
value: {
get: function( elem, name ) {
- if ( formHook && jQuery.nodeName( elem, "button" ) ) {
- return formHook.get( 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 ( formHook && jQuery.nodeName( elem, "button" ) ) {
- return formHook.set( 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;
@@ -2356,7 +2619,7 @@ jQuery.extend({
frameborder: "frameBorder",
contenteditable: "contentEditable"
},
-
+
prop: function( elem, name, value ) {
var nType = elem.nodeType;
@@ -2383,7 +2646,7 @@ jQuery.extend({
}
} else {
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== undefined ) {
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
return ret;
} else {
@@ -2391,15 +2654,35 @@ jQuery.extend({
}
}
},
-
- propHooks: {}
+
+ 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
+jQuery.attrHooks.tabIndex = jQuery.propHooks.tabIndex;
+
// Hook for boolean attributes
boolHook = {
get: function( elem, name ) {
// Align boolean attributes with corresponding properties
- return jQuery.prop( elem, name ) ?
+ // 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;
},
@@ -2426,27 +2709,29 @@ boolHook = {
// 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 = {
+ 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 undefined if nodeValue is empty string
- return ret && ret.nodeValue !== "" ?
+ return ret && (fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified) ?
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
+ // Set the existing or create a new attribute node
var ret = elem.getAttributeNode( name );
- if ( ret ) {
- ret.nodeValue = value;
- return value;
+ if ( !ret ) {
+ ret = document.createAttribute( name );
+ elem.setAttributeNode( ret );
}
+ return (ret.nodeValue = value + "");
}
};
@@ -2505,6 +2790,7 @@ if ( !jQuery.support.optSelected ) {
parent.parentNode.selectedIndex;
}
}
+ return null;
}
});
}
@@ -2538,59 +2824,72 @@ var rnamespaces = /\.(.*)$/,
rperiod = /\./g,
rspaces = / /g,
rescape = /[^\w\s.|`]/g,
- fcleanup = function( nm ) {
- return nm.replace(rescape, "\\$&");
+ rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/,
+ rhoverHack = /\bhover(\.\S+)?/,
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|contextmenu)|click/,
+ rquickIs = /^([\w\-]+)?(?:#([\w\-]+))?(?:\.([\w\-]+))?(?:\[([\w+\-]+)=["']?([\w\-]*)["']?\])?$/,
+ quickParse = function( selector ) {
+ var quick = rquickIs.exec( selector );
+ if ( quick ) {
+ // 0 1 2 3 4 5
+ // [ _, tag, id, class, attrName, attrValue ]
+ quick[1] = ( quick[1] || "" ).toLowerCase();
+ quick[3] = quick[3] && new RegExp( "\\b" + quick[3] + "\\b" );
+ }
+ return quick;
+ },
+ quickIs = function( elem, m ) {
+ return (
+ (!m[1] || elem.nodeName.toLowerCase() === m[1]) &&
+ (!m[2] || elem.id === m[2]) &&
+ (!m[3] || m[3].test( elem.className )) &&
+ (!m[4] || elem.getAttribute( m[4] ) == m[5])
+ );
+ },
+ useNativeMethod = function( event ) {
+ // IE throws error on focus/blur of a hidden element (#1486)
+ var type = event.type;
+ if ( !event.isDefaultPrevented() && this[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) ) {
+ this[ type ]();
+ return false;
+ }
};
/*
- * A number of helper functions used for managing events.
- * Many of the ideas behind this code originated from
- * Dean Edwards' addEvent library.
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
*/
jQuery.event = {
- // Bind an event to an element
- // Original by Dean Edwards
- add: function( elem, types, handler, data ) {
- if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
- return;
- }
+ add: function( elem, types, handler, data, selector ) {
+
+ var elemData, eventHandle, events,
+ t, tns, type, namespaces, handleObj,
+ handleObjIn, quick, handlers, special;
- if ( handler === false ) {
- handler = returnFalse;
- } else if ( !handler ) {
- // Fixes bug #7229. Fix recommended by jdalton
+ // Don't attach events to noData or text/comment nodes (allow plain objects tho)
+ if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
return;
}
- var handleObjIn, handleObj;
-
+ // Caller can pass in an object of custom data in lieu of the handler
if ( handler.handler ) {
handleObjIn = handler;
handler = handleObjIn.handler;
}
- // Make sure that the function being executed has a unique ID
+ // Make sure that the handler has a unique ID, used to find/remove it later
if ( !handler.guid ) {
handler.guid = jQuery.guid++;
}
- // Init the element's event structure
- var elemData = jQuery._data( elem );
-
- // If no elemData is found then we must be trying to bind to one of the
- // banned noData elements
- if ( !elemData ) {
- return;
- }
-
- var events = elemData.events,
- eventHandle = elemData.handle;
-
+ // Init the element's event structure and main handler, if this is the first
+ events = elemData.events;
if ( !events ) {
elemData.events = events = {};
}
-
+ eventHandle = elemData.handle;
if ( !eventHandle ) {
elemData.handle = eventHandle = function( e ) {
// Discard the second event of a jQuery.event.trigger() and
@@ -2599,50 +2898,50 @@ jQuery.event = {
jQuery.event.handle.apply( eventHandle.elem, arguments ) :
undefined;
};
+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+ eventHandle.elem = elem;
}
- // Add elem as a property of the handle function
- // This is to prevent a memory leak with non-native events in IE.
- eventHandle.elem = elem;
-
// Handle multiple events separated by a space
// jQuery(...).bind("mouseover mouseout", fn);
- types = types.split(" ");
-
- var type, i = 0, namespaces;
+ types = types.replace( rhoverHack, "mouseover$1 mouseout$1" ).split( " " );
+ for ( t = 0; t < types.length; t++ ) {
- while ( (type = types[ i++ ]) ) {
- handleObj = handleObjIn ?
- jQuery.extend({}, handleObjIn) :
- { handler: handler, data: data };
+ tns = rtypenamespace.exec( types[t] ) || [];
+ type = tns[1];
+ namespaces = (tns[2] || "").split( "." ).sort();
- // Namespaced event handlers
- if ( type.indexOf(".") > -1 ) {
- namespaces = type.split(".");
- type = namespaces.shift();
- handleObj.namespace = namespaces.slice(0).sort().join(".");
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+ type = (selector? special.delegateType : special.bindType ) || type;
+ special = jQuery.event.special[ type ] || {};
- } else {
- namespaces = [];
- handleObj.namespace = "";
- }
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend({
+ type: type,
+ origType: tns[1],
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ namespace: namespaces.join(".")
+ }, handleObjIn);
- handleObj.type = type;
- if ( !handleObj.guid ) {
- handleObj.guid = handler.guid;
+ // Delegated event; pre-analyze selector so it's processed quickly on event dispatch
+ if ( selector ) {
+ handleObj.quick = quickParse( selector );
+ if ( !handleObj.quick && jQuery.expr.match.POS.test( selector ) ) {
+ handleObj.isPositional = true;
+ }
}
- // Get the current list of functions bound to this event
- var handlers = events[ type ],
- special = jQuery.event.special[ type ] || {};
-
- // Init the event handler queue
+ // Init the event handler queue if we're the first
+ handlers = events[ type ];
if ( !handlers ) {
handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
- // Check for a special event handler
- // Only use addEventListener/attachEvent if the special
- // events handler returns false
+ // Only use addEventListener/attachEvent if the special events handler returns false
if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
// Bind the global event handler to the element
if ( elem.addEventListener ) {
@@ -2662,10 +2961,14 @@ jQuery.event = {
}
}
- // Add the function to the element's handler list
- handlers.push( handleObj );
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
- // Keep track of which events have been used, for event optimization
+ // Keep track of which events have ever been used, for event optimization
jQuery.event.global[ type ] = true;
}
@@ -2676,129 +2979,94 @@ jQuery.event = {
global: {},
// Detach an event or set of events from an element
- remove: function( elem, types, handler, pos ) {
- // don't do events on text and comment nodes
- if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
- return;
- }
-
- if ( handler === false ) {
- handler = returnFalse;
- }
+ remove: function( elem, types, handler, selector ) {
- var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
- elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
- events = elemData && elemData.events;
+ var elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
+ t, tns, type, namespaces, origCount,
+ j, events, special, handle, eventType, handleObj;
- if ( !elemData || !events ) {
+ if ( !elemData || !(events = elemData.events) ) {
return;
}
- // types is actually an event object here
- if ( types && types.type ) {
+ // For removal, types can be an Event object
+ if ( types && types.type && types.handler ) {
handler = types.handler;
types = types.type;
+ selector = types.selector;
}
- // Unbind all events for the element
- if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
- types = types || "";
-
- for ( type in events ) {
- jQuery.event.remove( elem, type + types );
- }
-
- return;
- }
-
- // Handle multiple events separated by a space
- // jQuery(...).unbind("mouseover mouseout", fn);
- types = types.split(" ");
-
- while ( (type = types[ i++ ]) ) {
- origType = type;
- handleObj = null;
- all = type.indexOf(".") < 0;
- namespaces = [];
-
- if ( !all ) {
- // Namespaced event handlers
- namespaces = type.split(".");
- type = namespaces.shift();
-
- namespace = new RegExp("(^|\\.)" +
- jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
- }
-
- eventType = events[ type ];
+ // Once for each type.namespace in types; type may be omitted
+ types = (types || "").replace( rhoverHack, "mouseover$1 mouseout$1" ).split(" ");
+ for ( t = 0; t < types.length; t++ ) {
+ tns = rtypenamespace.exec( types[t] ) || [];
+ type = tns[1];
+ namespaces = tns[2];
- if ( !eventType ) {
- continue;
- }
-
- if ( !handler ) {
- for ( j = 0; j < eventType.length; j++ ) {
- handleObj = eventType[ j ];
-
- if ( all || namespace.test( handleObj.namespace ) ) {
- jQuery.event.remove( elem, origType, handleObj.handler, j );
- eventType.splice( j--, 1 );
- }
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ namespaces = namespaces? "." + namespaces : "";
+ for ( j in events ) {
+ jQuery.event.remove( elem, j + namespaces, handler, selector );
}
-
- continue;
+ return;
}
special = jQuery.event.special[ type ] || {};
+ type = (selector? special.delegateType : special.bindType ) || type;
+ eventType = events[ type ] || [];
+ origCount = eventType.length;
+ namespaces = namespaces? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
- for ( j = pos || 0; j < eventType.length; j++ ) {
- handleObj = eventType[ j ];
+ // Only need to loop for special events or selective removal
+ if ( handler || namespaces || selector || special.remove ) {
+ for ( j = 0; j < eventType.length; j++ ) {
+ handleObj = eventType[ j ];
- if ( handler.guid === handleObj.guid ) {
- // remove the given handler for the given type
- if ( all || namespace.test( handleObj.namespace ) ) {
- if ( pos == null ) {
- eventType.splice( j--, 1 );
- }
+ if ( !handler || handler.guid === handleObj.guid ) {
+ if ( !namespaces || namespaces.test( handleObj.namespace ) ) {
+ if ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) {
+ eventType.splice( j--, 1 );
- if ( special.remove ) {
- special.remove.call( elem, handleObj );
+ if ( handleObj.selector ) {
+ eventType.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
}
}
-
- if ( pos != null ) {
- break;
- }
}
+ } else {
+ // Removing all events
+ eventType.length = 0;
}
- // remove generic event handler if no more handlers exist
- if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( eventType.length === 0 && origCount !== eventType.length ) {
if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
jQuery.removeEvent( elem, type, elemData.handle );
}
- ret = null;
delete events[ type ];
}
}
// Remove the expando if it's no longer used
if ( jQuery.isEmptyObject( events ) ) {
- var handle = elemData.handle;
+ handle = elemData.handle;
if ( handle ) {
handle.elem = null;
}
- delete elemData.events;
- delete elemData.handle;
-
- if ( jQuery.isEmptyObject( elemData ) ) {
- jQuery.removeData( elem, undefined, true );
- }
+ // removeData also checks for emptiness and clears the expando if empty
+ // so use it instead of delete
+ jQuery.removeData( elem, [ "events", "handle" ], true );
}
},
-
+
// Events that are safe to short-circuit if no handlers are attached.
// Native DOM events should not be added, they may have inline handlers.
customEvent: {
@@ -2808,18 +3076,33 @@ jQuery.event = {
},
trigger: function( event, data, elem, onlyHandlers ) {
+ // Don't do events on text and comment nodes
+ if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
+ return;
+ }
+
// Event object or event type
var type = event.type || event,
namespaces = [],
- exclusive;
+ exclusive, i, cur, old, ontype, special, doc, eventPath, bubbleType,
+ addHandlers = function( elem, type ) {
+ // Defer getting handler so we don't waste time in case propagation is stopped
+ if ( (jQuery._data( elem, "events" ) || {})[ type ] ) {
+ eventPath.push({ elem: elem, type: type /*, handler: jQuery._data( elem, "handle" ) */ });
+ }
+ // IE doesn't like method names with a colon (#3533, #8272)
+ if ( ontype && jQuery.acceptData( elem ) && elem[ ontype ] ) {
+ eventPath.push({ elem: elem, type: type, handler: elem[ ontype ] });
+ }
+ };
- if ( type.indexOf("!") >= 0 ) {
+ if ( type.indexOf( "!" ) >= 0 ) {
// Exclusive events trigger only for the exact event (no namespaces)
type = type.slice(0, -1);
exclusive = true;
}
- if ( type.indexOf(".") >= 0 ) {
+ if ( type.indexOf( "." ) >= 0 ) {
// Namespaced trigger; create a regexp to match event type in handle()
namespaces = type.split(".");
type = namespaces.shift();
@@ -2841,10 +3124,12 @@ jQuery.event = {
new jQuery.Event( type );
event.type = type;
+ event.isTrigger = true;
event.exclusive = exclusive;
- event.namespace = namespaces.join(".");
- event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)");
-
+ event.namespace = namespaces.join( "." );
+ event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
+ ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
+
// triggerHandler() and global events don't bubble or run the default action
if ( onlyHandlers || !elem ) {
event.preventDefault();
@@ -2853,193 +3138,236 @@ jQuery.event = {
// Handle a global trigger
if ( !elem ) {
+
// TODO: Stop taunting the data cache; remove global events and always attach to document
- jQuery.each( jQuery.cache, function() {
- // internalKey variable is just used to make it easier to find
- // and potentially change this stuff later; currently it just
- // points to jQuery.expando
- var internalKey = jQuery.expando,
- internalCache = this[ internalKey ];
- if ( internalCache && internalCache.events && internalCache.events[ type ] ) {
- jQuery.event.trigger( event, data, internalCache.handle.elem );
+ var cache = jQuery.cache;
+ for ( i in cache ) {
+ if ( cache[ i ].events && cache[ i ].events[ type ] ) {
+ jQuery.event.trigger( event, data, cache[ i ].handle.elem );
}
- });
- return;
- }
-
- // Don't do events on text and comment nodes
- if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ }
return;
}
// Clean up the event in case it is being reused
event.result = undefined;
- event.target = elem;
+ if ( !event.target ) {
+ event.target = elem;
+ }
// Clone any incoming data and prepend the event, creating the handler arg list
data = data != null ? jQuery.makeArray( data ) : [];
data.unshift( event );
- var cur = elem,
- // IE doesn't like method names with a colon (#3533, #8272)
- ontype = type.indexOf(":") < 0 ? "on" + type : "";
-
- // Fire event on the current element, then bubble up the DOM tree
- do {
- var handle = jQuery._data( cur, "handle" );
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
- event.currentTarget = cur;
- if ( handle ) {
- handle.apply( cur, data );
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ // Always fire handlers for the target, even if prop is stopped in advance
+ eventPath = [];
+ addHandlers( elem, special.bindType || type );
+ doc = elem.ownerDocument;
+ if ( doc && !jQuery.isWindow( elem ) & !event.isPropagationStopped() ) {
+ bubbleType = special.delegateType || type;
+ for ( cur = elem.parentNode; cur; cur = cur.parentNode ) {
+ addHandlers( cur, bubbleType );
}
+ addHandlers( doc.defaultView || doc.parentWindow || window, bubbleType );
+ }
- // Trigger an inline bound script
- if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) {
- event.result = false;
- event.preventDefault();
+ // Bubble up the DOM tree
+ for ( i = 0; i < eventPath.length; i++ ) {
+ cur = eventPath[ i ];
+ event.type = cur.type;
+ (cur.handler || jQuery._data( cur.elem, "handle" )).apply( cur.elem, data );
+ if ( event.isPropagationStopped() ) {
+ break;
}
-
- // Bubble up to document, then to window
- cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window;
- } while ( cur && !event.isPropagationStopped() );
+ }
+ event.type = type;
// If nobody prevented the default action, do it now
if ( !event.isDefaultPrevented() ) {
- var old,
- special = jQuery.event.special[ type ] || {};
- if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) &&
+ if ( (!special._default || special._default.call( elem.ownerDocument, event, data ) === false) &&
!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
// Call a native DOM method on the target with the same name name as the event.
- // Can't use an .isFunction)() check here because IE6/7 fails that test.
- // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch.
- try {
- if ( ontype && elem[ type ] ) {
- // Don't re-trigger an onFOO event when we call its FOO() method
- old = elem[ ontype ];
+ // Can't use an .isFunction() check here because IE6/7 fails that test.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ // IE<9 dies on focus/blur to hidden element (#1486)
+ if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ old = elem[ ontype ];
+
+ if ( old ) {
+ elem[ ontype ] = null;
+ }
- if ( old ) {
- elem[ ontype ] = null;
- }
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ elem[ type ]();
+ jQuery.event.triggered = undefined;
- jQuery.event.triggered = type;
- elem[ type ]();
+ if ( old ) {
+ elem[ ontype ] = old;
}
- } catch ( ieError ) {}
-
- if ( old ) {
- elem[ ontype ] = old;
}
-
- jQuery.event.triggered = undefined;
}
}
-
+
return event.result;
},
handle: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
event = jQuery.event.fix( event || window.event );
- // Snapshot the handlers list since a called handler may add/remove events.
- var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0),
- run_all = !event.exclusive && !event.namespace,
- args = Array.prototype.slice.call( arguments, 0 );
- // Use the fix-ed Event rather than the (read-only) native event
+ var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []),
+ delegateCount = handlers.delegateCount,
+ args = Array.prototype.slice.call( arguments, 0 ),
+ handlerQueue = [],
+ i, cur, selMatch, matches, handleObj, sel, hit, related;
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
args[0] = event;
- event.currentTarget = this;
-
- for ( var j = 0, l = handlers.length; j < l; j++ ) {
- var handleObj = handlers[ j ];
-
- // Triggered event must 1) be non-exclusive and have no namespace, or
- // 2) have namespace(s) a subset or equal to those in the bound event.
- if ( run_all || event.namespace_re.test( handleObj.namespace ) ) {
- // Pass in a reference to the handler function itself
- // So that we can later remove it
- event.handler = handleObj.handler;
- event.data = handleObj.data;
- event.handleObj = handleObj;
-
- var ret = handleObj.handler.apply( this, args );
-
- if ( ret !== undefined ) {
- event.result = ret;
- if ( ret === false ) {
- event.preventDefault();
- event.stopPropagation();
+
+ // Determine handlers that should run if there are delegated events
+ // Avoid disabled elements in IE (#6911) and non-left-click bubbling in Firefox (#3861)
+ if ( delegateCount && !event.target.disabled && !(event.button && event.type === "click") ) {
+
+ for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
+ selMatch = {};
+ matches = [];
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+ sel = handleObj.selector;
+ hit = selMatch[ sel ];
+
+ if ( handleObj.isPositional ) {
+ // Since .is() does not work for positionals; see http://jsfiddle.net/eJ4yd/3/
+ hit = (hit || (selMatch[ sel ] = jQuery( sel ))).index( cur ) >= 0;
+ } else if ( hit === undefined ) {
+ hit = selMatch[ sel ] = (handleObj.quick? quickIs( cur, handleObj.quick ) : jQuery( cur ).is( sel ));
+ }
+ if ( hit ) {
+ matches.push( handleObj );
}
}
-
- if ( event.isImmediatePropagationStopped() ) {
- break;
+ if ( matches.length ) {
+ handlerQueue.push({ elem: cur, matches: matches });
}
}
}
+
+ // Copy the remaining (bound) handlers in case they're changed
+ handlers = handlers.slice( delegateCount );
+
+ // Run delegates first; they may want to stop propagation beneath us
+ event.delegateTarget = this;
+ for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
+ matched = handlerQueue[ i ];
+ dispatch( matched.elem, event, matched.matches, args );
+ }
+ delete event.delegateTarget;
+
+ // Run non-delegated handlers for this level
+ if ( handlers.length ) {
+ dispatch( this, event, handlers, args );
+ }
+
return event.result;
},
- props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+ // Includes some event props shared by KeyEvent and MouseEvent
+ // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
+ props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp type view which".split(" "),
+
+ propHooks: {},
+
+ keyHooks: {
+ props: "char charCode key keyCode".split(" "),
+ filter: function( event, original ) {
+
+ // Add which for key events
+ if ( event.which == null ) {
+ event.which = original.charCode != null ? original.charCode : original.keyCode;
+ }
+
+ return event;
+ }
+ },
+
+ mouseHooks: {
+ props: "button buttons clientX clientY fromElement layerX layerY offsetX offsetY pageX pageY screenX screenY toElement wheelDelta".split(" "),
+ filter: function( event, original ) {
+ var eventDoc, doc, body,
+ button = original.button,
+ fromElement = original.fromElement;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && original.clientX != null ) {
+ eventDoc = event.target.ownerDocument || document;
+ doc = eventDoc.documentElement;
+ body = eventDoc.body;
+
+ event.pageX = original.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
+ event.pageY = original.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
+ }
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && fromElement ) {
+ event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && button !== undefined ) {
+ event.which = (button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ));
+ }
+
+ return event;
+ }
+ },
fix: function( event ) {
if ( event[ jQuery.expando ] ) {
return event;
}
- // store a copy of the original event object
- // and "clone" to set read-only properties
- var originalEvent = event;
+ // Create a writable copy of the event object and normalize some properties
+ var originalEvent = event,
+ propHook = jQuery.event.propHooks[ event.type ] || {},
+ copy = propHook.props ? this.props.concat( propHook.props ) : this.props;
+
event = jQuery.Event( originalEvent );
- for ( var i = this.props.length, prop; i; ) {
- prop = this.props[ --i ];
+ for ( var i = copy.length, prop; i; ) {
+ prop = copy[ --i ];
event[ prop ] = originalEvent[ prop ];
}
- // Fix target property, if necessary
+ // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
if ( !event.target ) {
- // Fixes #1925 where srcElement might not be defined either
- event.target = event.srcElement || document;
+ event.target = originalEvent.srcElement || document;
}
- // check if target is a textnode (safari)
+ // Target should not be a text node (#504, Safari)
if ( event.target.nodeType === 3 ) {
event.target = event.target.parentNode;
}
- // Add relatedTarget, if necessary
- if ( !event.relatedTarget && event.fromElement ) {
- event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
- }
-
- // Calculate pageX/Y if missing and clientX/Y available
- if ( event.pageX == null && event.clientX != null ) {
- var eventDocument = event.target.ownerDocument || document,
- doc = eventDocument.documentElement,
- body = eventDocument.body;
-
- event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
- event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
- }
-
- // Add which for key events
- if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
- event.which = event.charCode != null ? event.charCode : event.keyCode;
- }
-
- // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
- if ( !event.metaKey && event.ctrlKey ) {
+ // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8)
+ if ( event.metaKey === undefined ) {
event.metaKey = event.ctrlKey;
}
- // Add which for click: 1 === left; 2 === middle; 3 === right
- // Note: button is not normalized, so don't use it
- if ( !event.which && event.button !== undefined ) {
- event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
- }
-
- return event;
+ return propHook.filter? propHook.filter( event, originalEvent ) : event;
},
// Deprecated, use jQuery.guid instead
@@ -3051,20 +3379,16 @@ jQuery.event = {
special: {
ready: {
// Make sure the ready event is setup
- setup: jQuery.bindReady,
- teardown: jQuery.noop
+ setup: jQuery.bindReady
},
- live: {
- add: function( handleObj ) {
- jQuery.event.add( this,
- liveConvert( handleObj.origType, handleObj.selector ),
- jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
- },
-
- remove: function( handleObj ) {
- jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
- }
+ focus: {
+ delegateType: "focusin",
+ trigger: useNativeMethod
+ },
+ blur: {
+ delegateType: "focusout",
+ trigger: useNativeMethod
},
beforeunload: {
@@ -3084,6 +3408,39 @@ jQuery.event = {
}
};
+// Run jQuery handler functions; called from jQuery.event.handle
+function dispatch( target, event, handlers, args ) {
+ var run_all = !event.exclusive && !event.namespace,
+ specialHandle = (jQuery.event.special[event.type] || {}).handle,
+ j, handleObj, ret;
+
+ event.currentTarget = target;
+ for ( j = 0; j < handlers.length && !event.isImmediatePropagationStopped(); j++ ) {
+ handleObj = handlers[ j ];
+
+ // Triggered event must either 1) be non-exclusive and have no namespace, or
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+ if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
+
+ // Pass in a reference to the handler function itself
+ // So that we can later remove it
+ event.handler = handleObj.handler;
+ event.data = handleObj.data;
+ event.handleObj = handleObj;
+
+ ret = (specialHandle || handleObj.handler).apply( target, args );
+
+ if ( ret !== undefined ) {
+ event.result = ret;
+ if ( ret === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+}
+
jQuery.removeEvent = document.removeEventListener ?
function( elem, type, handle ) {
if ( elem.removeEventListener ) {
@@ -3098,7 +3455,7 @@ jQuery.removeEvent = document.removeEventListener ?
jQuery.Event = function( src, props ) {
// Allow instantiation without the 'new' keyword
- if ( !this.preventDefault ) {
+ if ( !(this instanceof jQuery.Event) ) {
return new jQuery.Event( src, props );
}
@@ -3122,9 +3479,8 @@ jQuery.Event = function( src, props ) {
jQuery.extend( this, props );
}
- // timeStamp is buggy for some events on Firefox(#3843)
- // So we won't rely on the native value
- this.timeStamp = jQuery.now();
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || jQuery.now();
// Mark it as fixed
this[ jQuery.expando ] = true;
@@ -3180,213 +3536,150 @@ jQuery.Event.prototype = {
isImmediatePropagationStopped: returnFalse
};
-// Checks if an event happened on an element within another element
-// Used in jQuery.event.special.mouseenter and mouseleave handlers
-var withinElement = function( event ) {
-
- // Check if mouse(over|out) are still within the same parent element
- var related = event.relatedTarget,
- inside = false,
- eventType = event.type;
-
- event.type = event.data;
-
- if ( related !== this ) {
-
- if ( related ) {
- inside = jQuery.contains( this, related );
- }
-
- if ( !inside ) {
-
- jQuery.event.handle.apply( this, arguments );
-
- event.type = eventType;
- }
- }
-},
-
-// In case of event delegation, we only need to rename the event.type,
-// liveHandler will take care of the rest.
-delegate = function( event ) {
- event.type = event.data;
- jQuery.event.handle.apply( this, arguments );
-};
-
-// Create mouseenter and mouseleave events
+// Create mouseenter/leave events using mouseover/out and event-time checks
jQuery.each({
mouseenter: "mouseover",
mouseleave: "mouseout"
}, function( orig, fix ) {
- jQuery.event.special[ orig ] = {
- setup: function( data ) {
- jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
- },
- teardown: function( data ) {
- jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
+ jQuery.event.special[ orig ] = jQuery.event.special[ fix ] = {
+ delegateType: fix,
+ bindType: fix,
+
+ handle: function( event ) {
+ var target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj,
+ selector = handleObj.selector,
+ oldType, ret;
+
+ // For a real mouseover/out, always call the handler; for
+ // mousenter/leave call the handler if related is outside the target.
+ // NB: No relatedTarget if the mouse left/entered the browser window
+ if ( !related || handleObj.origType === event.type || (related !== target && !jQuery.contains( target, related )) ) {
+ oldType = event.type;
+ event.type = handleObj.origType;
+ ret = handleObj.handler.apply( this, arguments );
+ event.type = oldType;
+ }
+ return ret;
}
};
});
-// submit delegation
+// IE submit delegation
if ( !jQuery.support.submitBubbles ) {
jQuery.event.special.submit = {
- setup: function( data, namespaces ) {
- if ( !jQuery.nodeName( this, "form" ) ) {
- jQuery.event.add(this, "click.specialSubmit", function( e ) {
- var elem = e.target,
- type = elem.type;
-
- if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
- trigger( "submit", this, arguments );
- }
- });
-
- jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
- var elem = e.target,
- type = elem.type;
+ setup: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
- if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
- trigger( "submit", this, arguments );
- }
- });
+ // Lazy-add a submit handler when a descendant form may potentially be submitted
+ jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
+ // Node name check avoids a VML-related crash in IE (#9807)
+ var elem = e.target,
+ form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
+ if ( form && !form._submit_attached ) {
+ jQuery.event.add( form, "submit._submit", function( event ) {
+ // Form was submitted, bubble the event up the tree
+ if ( this.parentNode ) {
+ simulate( "submit", this.parentNode, event, true );
+ }
+ });
+ form._submit_attached = true;
+ }
+ });
+ // return undefined since we don't need an event listener
+ },
- } else {
+ teardown: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
return false;
}
- },
- teardown: function( namespaces ) {
- jQuery.event.remove( this, ".specialSubmit" );
+ // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
+ jQuery.event.remove( this, "._submit" );
}
};
-
}
-// change delegation, happens here so we have bind.
+// IE change delegation and checkbox/radio fix
if ( !jQuery.support.changeBubbles ) {
- var changeFilters,
-
- getVal = function( elem ) {
- var type = elem.type, val = elem.value;
-
- if ( type === "radio" || type === "checkbox" ) {
- val = elem.checked;
-
- } else if ( type === "select-multiple" ) {
- val = elem.selectedIndex > -1 ?
- jQuery.map( elem.options, function( elem ) {
- return elem.selected;
- }).join("-") :
- "";
-
- } else if ( jQuery.nodeName( elem, "select" ) ) {
- val = elem.selectedIndex;
- }
-
- return val;
- },
-
- testChange = function testChange( e ) {
- var elem = e.target, data, val;
-
- if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
- return;
- }
-
- data = jQuery._data( elem, "_change_data" );
- val = getVal(elem);
-
- // the current data will be also retrieved by beforeactivate
- if ( e.type !== "focusout" || elem.type !== "radio" ) {
- jQuery._data( elem, "_change_data", val );
- }
-
- if ( data === undefined || val === data ) {
- return;
- }
-
- if ( data != null || val ) {
- e.type = "change";
- e.liveFired = undefined;
- jQuery.event.trigger( e, arguments[1], elem );
- }
- };
-
jQuery.event.special.change = {
- filters: {
- focusout: testChange,
-
- beforedeactivate: testChange,
-
- click: function( e ) {
- var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";
-
- if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) {
- testChange.call( this, e );
- }
- },
- // Change has to be called before submit
- // Keydown will be called before keypress, which is used in submit-event delegation
- keydown: function( e ) {
- var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";
+ setup: function() {
- if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) ||
- (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
- type === "select-multiple" ) {
- testChange.call( this, e );
+ if ( rformElems.test( this.nodeName ) ) {
+ // IE doesn't fire change on a check/radio until blur; trigger it on click
+ // after a propertychange. Eat the blur-change in special.change.handle.
+ // This still fires onchange a second time for check/radio after blur.
+ if ( this.type === "checkbox" || this.type === "radio" ) {
+ jQuery.event.add( this, "propertychange._change", function( event ) {
+ if ( event.originalEvent.propertyName === "checked" ) {
+ this._just_changed = true;
+ }
+ });
+ jQuery.event.add( this, "click._change", function( event ) {
+ if ( this._just_changed ) {
+ this._just_changed = false;
+ simulate( "change", this, event, true );
+ }
+ });
}
- },
-
- // Beforeactivate happens also before the previous element is blurred
- // with this event you can't trigger a change event, but you can store
- // information
- beforeactivate: function( e ) {
- var elem = e.target;
- jQuery._data( elem, "_change_data", getVal(elem) );
- }
- },
-
- setup: function( data, namespaces ) {
- if ( this.type === "file" ) {
return false;
}
+ // Delegated event; lazy-add a change handler on descendant inputs
+ jQuery.event.add( this, "beforeactivate._change", function( e ) {
+ var elem = e.target;
- for ( var type in changeFilters ) {
- jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
- }
+ if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) {
+ jQuery.event.add( elem, "change._change", function( event ) {
+ if ( this.parentNode && !event.isSimulated ) {
+ simulate( "change", this.parentNode, event, true );
+ }
+ });
+ elem._change_attached = true;
+ }
+ });
+ },
+
+ handle: function( event ) {
+ var elem = event.target;
- return rformElems.test( this.nodeName );
+ // Swallow native change events from checkbox/radio, we already triggered them above
+ if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
+ return event.handleObj.handler.apply( this, arguments );
+ }
},
- teardown: function( namespaces ) {
- jQuery.event.remove( this, ".specialChange" );
+ teardown: function() {
+ jQuery.event.remove( this, "._change" );
return rformElems.test( this.nodeName );
}
};
-
- changeFilters = jQuery.event.special.change.filters;
-
- // Handle when the input is .focus()'d
- changeFilters.focus = changeFilters.beforeactivate;
}
-function trigger( type, elem, args ) {
+function simulate( type, elem, event, bubble ) {
// Piggyback on a donor event to simulate a different one.
// Fake originalEvent to avoid donor's stopPropagation, but if the
// simulated event prevents default then we do the same on the donor.
- // Don't pass args or remember liveFired; they apply to the donor event.
- var event = jQuery.extend( {}, args[ 0 ] );
- event.type = type;
- event.originalEvent = {};
- event.liveFired = undefined;
- jQuery.event.handle.call( elem, event );
- if ( event.isDefaultPrevented() ) {
- args[ 0 ].preventDefault();
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ { type: type, isSimulated: true, originalEvent: {} }
+ );
+ if ( bubble ) {
+ jQuery.event.trigger( e, null, elem );
+ } else {
+ jQuery.event.handle.call( elem, e );
+ }
+ if ( e.isDefaultPrevented() ) {
+ event.preventDefault();
}
}
@@ -3395,7 +3688,10 @@ if ( !jQuery.support.focusinBubbles ) {
jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
// Attach a single capturing handler while someone wants focusin/focusout
- var attaches = 0;
+ var attaches = 0,
+ handler = function( event ) {
+ simulate( fix, event.target, jQuery.event.fix( event ), true );
+ };
jQuery.event.special[ fix ] = {
setup: function() {
@@ -3409,89 +3705,113 @@ if ( !jQuery.support.focusinBubbles ) {
}
}
};
-
- function handler( donor ) {
- // Donor event is always a native one; fix it and switch its type.
- // Let focusin/out handler cancel the donor focus/blur event.
- var e = jQuery.event.fix( donor );
- e.type = fix;
- e.originalEvent = {};
- jQuery.event.trigger( e, null, e.target );
- if ( e.isDefaultPrevented() ) {
- donor.preventDefault();
- }
- }
});
}
-jQuery.each(["bind", "one"], function( i, name ) {
- jQuery.fn[ name ] = function( type, data, fn ) {
- var handler;
+jQuery.fn.extend({
+
+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+ var origFn, type;
- // Handle object literals
- if ( typeof type === "object" ) {
- for ( var key in type ) {
- this[ name ](key, data, type[key], fn);
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) {
+ // ( types-Object, data )
+ data = selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ this.on( type, selector, data, types[ type ], one );
}
return this;
}
- if ( arguments.length === 2 || data === false ) {
- fn = data;
- data = undefined;
+ if ( data == null && fn == null ) {
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return this;
}
- if ( name === "one" ) {
- handler = function( event ) {
- jQuery( this ).unbind( event, handler );
- return fn.apply( this, arguments );
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+ jQuery.event.remove( event.delegateTarget || this, event );
+ return origFn.apply( this, arguments );
};
- handler.guid = fn.guid || jQuery.guid++;
- } else {
- handler = fn;
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
}
-
- if ( type === "unload" && name !== "one" ) {
- this.one( type, data, fn );
-
- } else {
- for ( var i = 0, l = this.length; i < l; i++ ) {
- jQuery.event.add( this[i], type, handler, data );
- }
+ return this.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ });
+ },
+ one: function( types, selector, data, fn ) {
+ return this.on.call( this, types, selector, data, fn, 1 );
+ },
+ off: function( types, selector, fn ) {
+ if ( types && types.preventDefault ) {
+ // ( event ) native or jQuery.Event
+ return this.off( types.type, types.handler, types.selector );
}
-
- return this;
- };
-});
-
-jQuery.fn.extend({
- unbind: function( type, fn ) {
- // Handle object literals
- if ( typeof type === "object" && !type.preventDefault ) {
- for ( var key in type ) {
- this.unbind(key, type[key]);
- }
-
- } else {
- for ( var i = 0, l = this.length; i < l; i++ ) {
- jQuery.event.remove( this[i], type, fn );
+ if ( typeof types === "object" ) {
+ // ( types-object [, selector] )
+ for ( var type in types ) {
+ this.off( type, selector, types[ type ] );
}
+ return this;
+ }
+ if ( typeof selector !== "string" ) {
+ // ( types [, fn] )
+ fn = selector;
+ selector = undefined;
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
}
+ return this.each(function() {
+ jQuery.event.remove( this, types, fn, selector );
+ });
+ },
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+ live: function( types, data, fn ) {
+ jQuery( this.context ).on( types, this.selector, data, fn );
+ return this;
+ },
+ die: function( types, fn ) {
+ jQuery( this.context ).off( types, this.selector || "**", fn );
return this;
},
delegate: function( selector, types, data, fn ) {
- return this.live( types, data, fn, selector );
+ return this.on( types, selector, data, fn );
},
-
undelegate: function( selector, types, fn ) {
- if ( arguments.length === 0 ) {
- return this.unbind( "live" );
-
- } else {
- return this.die( types, null, fn, selector );
- }
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn );
},
trigger: function( type, data ) {
@@ -3499,7 +3819,6 @@ jQuery.fn.extend({
jQuery.event.trigger( type, data, this );
});
},
-
triggerHandler: function( type, data ) {
if ( this[0] ) {
return jQuery.event.trigger( type, data, this[0], true );
@@ -3513,8 +3832,8 @@ jQuery.fn.extend({
i = 0,
toggler = function( event ) {
// Figure out which function to execute
- var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
- jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+ var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+ jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
// Make sure that clicks stop
event.preventDefault();
@@ -3537,178 +3856,9 @@ jQuery.fn.extend({
}
});
-var liveMap = {
- focus: "focusin",
- blur: "focusout",
- mouseenter: "mouseover",
- mouseleave: "mouseout"
-};
-
-jQuery.each(["live", "die"], function( i, name ) {
- jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
- var type, i = 0, match, namespaces, preType,
- selector = origSelector || this.selector,
- context = origSelector ? this : jQuery( this.context );
-
- if ( typeof types === "object" && !types.preventDefault ) {
- for ( var key in types ) {
- context[ name ]( key, data, types[key], selector );
- }
-
- return this;
- }
-
- if ( name === "die" && !types &&
- origSelector && origSelector.charAt(0) === "." ) {
-
- context.unbind( origSelector );
-
- return this;
- }
-
- if ( data === false || jQuery.isFunction( data ) ) {
- fn = data || returnFalse;
- data = undefined;
- }
-
- types = (types || "").split(" ");
-
- while ( (type = types[ i++ ]) != null ) {
- match = rnamespaces.exec( type );
- namespaces = "";
-
- if ( match ) {
- namespaces = match[0];
- type = type.replace( rnamespaces, "" );
- }
-
- if ( type === "hover" ) {
- types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
- continue;
- }
-
- preType = type;
-
- if ( liveMap[ type ] ) {
- types.push( liveMap[ type ] + namespaces );
- type = type + namespaces;
-
- } else {
- type = (liveMap[ type ] || type) + namespaces;
- }
-
- if ( name === "live" ) {
- // bind live handler
- for ( var j = 0, l = context.length; j < l; j++ ) {
- jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
- { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
- }
-
- } else {
- // unbind live handler
- context.unbind( "live." + liveConvert( type, selector ), fn );
- }
- }
-
- return this;
- };
-});
-
-function liveHandler( event ) {
- var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
- elems = [],
- selectors = [],
- events = jQuery._data( this, "events" );
-
- // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
- if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
- return;
- }
-
- if ( event.namespace ) {
- namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
- }
-
- event.liveFired = this;
-
- var live = events.live.slice(0);
-
- for ( j = 0; j < live.length; j++ ) {
- handleObj = live[j];
-
- if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
- selectors.push( handleObj.selector );
-
- } else {
- live.splice( j--, 1 );
- }
- }
-
- match = jQuery( event.target ).closest( selectors, event.currentTarget );
-
- for ( i = 0, l = match.length; i < l; i++ ) {
- close = match[i];
-
- for ( j = 0; j < live.length; j++ ) {
- handleObj = live[j];
-
- if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) {
- elem = close.elem;
- related = null;
-
- // Those two events require additional checking
- if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
- event.type = handleObj.preType;
- related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
-
- // Make sure not to accidentally match a child element with the same selector
- if ( related && jQuery.contains( elem, related ) ) {
- related = elem;
- }
- }
-
- if ( !related || related !== elem ) {
- elems.push({ elem: elem, handleObj: handleObj, level: close.level });
- }
- }
- }
- }
-
- for ( i = 0, l = elems.length; i < l; i++ ) {
- match = elems[i];
-
- if ( maxLevel && match.level > maxLevel ) {
- break;
- }
-
- event.currentTarget = match.elem;
- event.data = match.handleObj.data;
- event.handleObj = match.handleObj;
-
- ret = match.handleObj.origHandler.apply( match.elem, arguments );
-
- if ( ret === false || event.isPropagationStopped() ) {
- maxLevel = match.level;
-
- if ( ret === false ) {
- stop = false;
- }
- if ( event.isImmediatePropagationStopped() ) {
- break;
- }
- }
- }
-
- return stop;
-}
-
-function liveConvert( type, selector ) {
- return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&");
-}
-
jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
- "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
+ "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
// Handle event binding
jQuery.fn[ name ] = function( data, fn ) {
@@ -3725,6 +3875,14 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl
if ( jQuery.attrFn ) {
jQuery.attrFn[ name ] = true;
}
+
+ if ( rkeyEvent.test( name ) ) {
+ jQuery.event.propHooks[ name ] = jQuery.event.keyHooks;
+ }
+
+ if ( rmouseEvent.test( name ) ) {
+ jQuery.event.propHooks[ name ] = jQuery.event.mouseHooks;
+ }
});
@@ -3794,7 +3952,7 @@ var Sizzle = function( selector, context, results, seed ) {
if ( parts.length > 1 && origPOS.exec( selector ) ) {
if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
- set = posProcess( parts[0] + parts[1], context );
+ set = posProcess( parts[0] + parts[1], context, seed );
} else {
set = Expr.relative[ parts[0] ] ?
@@ -3808,7 +3966,7 @@ var Sizzle = function( selector, context, results, seed ) {
selector += parts.shift();
}
- set = posProcess( selector, set );
+ set = posProcess( selector, set, seed );
}
}
@@ -3927,18 +4085,17 @@ Sizzle.matchesSelector = function( node, expr ) {
};
Sizzle.find = function( expr, context, isXML ) {
- var set;
+ var set, i, len, match, type, left;
if ( !expr ) {
return [];
}
- for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
- var match,
- type = Expr.order[i];
+ for ( i = 0, len = Expr.order.length; i < len; i++ ) {
+ type = Expr.order[i];
if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
- var left = match[1];
+ left = match[1];
match.splice( 1, 1 );
if ( left.substr( left.length - 1 ) !== "\\" ) {
@@ -3964,17 +4121,18 @@ Sizzle.find = function( expr, context, isXML ) {
Sizzle.filter = function( expr, set, inplace, not ) {
var match, anyFound,
+ type, found, item, filter, left,
+ i, pass,
old = expr,
result = [],
curLoop = set,
isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
while ( expr && set.length ) {
- for ( var type in Expr.filter ) {
+ for ( type in Expr.filter ) {
if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
- var found, item,
- filter = Expr.filter[ type ],
- left = match[1];
+ filter = Expr.filter[ type ];
+ left = match[1];
anyFound = false;
@@ -4000,10 +4158,10 @@ Sizzle.filter = function( expr, set, inplace, not ) {
}
if ( match ) {
- for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
+ for ( i = 0; (item = curLoop[i]) != null; i++ ) {
if ( item ) {
found = filter( item, match, i, curLoop );
- var pass = not ^ !!found;
+ pass = not ^ found;
if ( inplace && found != null ) {
if ( pass ) {
@@ -4529,7 +4687,7 @@ var Expr = Sizzle.selectors = {
},
TAG: function( elem, match ) {
- return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
+ return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match;
},
CLASS: function( elem, match ) {
@@ -4539,7 +4697,9 @@ var Expr = Sizzle.selectors = {
ATTR: function( elem, match ) {
var name = match[1],
- result = Expr.attrHandle[ name ] ?
+ result = Sizzle.attr ?
+ Sizzle.attr( elem, name ) :
+ Expr.attrHandle[ name ] ?
Expr.attrHandle[ name ]( elem ) :
elem[ name ] != null ?
elem[ name ] :
@@ -4550,6 +4710,8 @@ var Expr = Sizzle.selectors = {
return result == null ?
type === "!=" :
+ !type && Sizzle.attr ?
+ result != null :
type === "=" ?
value === check :
type === "*=" ?
@@ -5115,7 +5277,7 @@ Sizzle.isXML = function( elem ) {
return documentElement ? documentElement.nodeName !== "HTML" : false;
};
-var posProcess = function( selector, context ) {
+var posProcess = function( selector, context, seed ) {
var match,
tmpSet = [],
later = "",
@@ -5131,13 +5293,16 @@ var posProcess = function( selector, context ) {
selector = Expr.relative[selector] ? selector + "*" : selector;
for ( var i = 0, l = root.length; i < l; i++ ) {
- Sizzle( selector, root[i], tmpSet );
+ Sizzle( selector, root[i], tmpSet, seed );
}
return Sizzle.filter( later, tmpSet );
};
// EXPOSE
+// Override sizzle attribute retrieval
+Sizzle.attr = jQuery.attr;
+Sizzle.selectors.attrMap = {};
jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.filters;
@@ -5223,43 +5388,33 @@ jQuery.fn.extend({
},
is: function( selector ) {
- return !!selector && ( typeof selector === "string" ?
- jQuery.filter( selector, this ).length > 0 :
- this.filter( selector ).length > 0 );
+ return !!selector && (
+ typeof selector === "string" ?
+ // If this is a positional selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ POS.test( selector ) ?
+ jQuery( selector, this.context ).index( this[0] ) >= 0 :
+ jQuery.filter( selector, this ).length > 0 :
+ this.filter( selector ).length > 0 );
},
closest: function( selectors, context ) {
var ret = [], i, l, cur = this[0];
- // Array
+ // Array (deprecated as of jQuery 1.7)
if ( jQuery.isArray( selectors ) ) {
- var match, selector,
- matches = {},
- level = 1;
-
- if ( cur && selectors.length ) {
- for ( i = 0, l = selectors.length; i < l; i++ ) {
- selector = selectors[i];
-
- if ( !matches[ selector ] ) {
- matches[ selector ] = POS.test( selector ) ?
- jQuery( selector, context || this.context ) :
- selector;
- }
- }
+ var level = 1;
- while ( cur && cur.ownerDocument && cur !== context ) {
- for ( selector in matches ) {
- match = matches[ selector ];
+ while ( cur && cur.ownerDocument && cur !== context ) {
+ for ( i = 0; i < selectors.length; i++ ) {
- if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) {
- ret.push({ selector: selector, elem: cur, level: level });
- }
+ if ( jQuery( cur ).is( selectors[ i ] ) ) {
+ ret.push({ selector: selectors[ i ], elem: cur, level: level });
}
-
- cur = cur.parentNode;
- level++;
}
+
+ cur = cur.parentNode;
+ level++;
}
return ret;
@@ -5295,12 +5450,17 @@ jQuery.fn.extend({
// Determine the position of an element within
// the matched set of elements
index: function( elem ) {
- if ( !elem || typeof elem === "string" ) {
- return jQuery.inArray( this[0],
- // If it receives a string, the selector is used
- // If it receives nothing, the siblings are used
- elem ? jQuery( elem ) : this.parent().children() );
+
+ // No argument, return index in parent
+ if ( !elem ) {
+ return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
}
+
+ // index in selector
+ if ( typeof elem === "string" ) {
+ return jQuery.inArray( this[0], jQuery( elem ) );
+ }
+
// Locate the position of the desired element
return jQuery.inArray(
// If it receives a jQuery object, the first element is used
@@ -5490,6 +5650,7 @@ var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
rtagName = /<([\w:]+)/,
rtbody = /
", "
" ],
area: [ 1, "" ],
_default: [ 0, "", "" ]
- };
+ },
+ safeFragment = (function() {
+ var nodeNames = (
+ "abbr article aside audio canvas datalist details figcaption figure footer " +
+ "header hgroup mark meter nav output progress section summary time video"
+ ).split( " " ),
+ safeFrag = document.createDocumentFragment();
+
+ if ( safeFrag.createElement ) {
+ while ( nodeNames.length ) {
+ safeFrag.createElement(
+ nodeNames.pop()
+ );
+ }
+ }
+ return safeFrag;
+ })();
wrapMap.optgroup = wrapMap.option;
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
@@ -5685,7 +5862,7 @@ jQuery.fn.extend({
null;
// See if we can take a shortcut and just use innerHTML
- } else if ( typeof value === "string" && !rnocache.test( value ) &&
+ } else if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
@@ -5840,27 +6017,26 @@ function cloneCopyEvent( src, dest ) {
return;
}
- var internalKey = jQuery.expando,
- oldData = jQuery.data( src ),
- curData = jQuery.data( dest, oldData );
-
- // Switch to use the internal data object, if it exists, for the next
- // stage of data copying
- if ( (oldData = oldData[ internalKey ]) ) {
- var events = oldData.events;
- curData = curData[ internalKey ] = jQuery.extend({}, oldData);
+ var type, i, l,
+ oldData = jQuery._data( src ),
+ curData = jQuery._data( dest, oldData ),
+ events = oldData.events;
- if ( events ) {
- delete curData.handle;
- curData.events = {};
+ if ( events ) {
+ delete curData.handle;
+ curData.events = {};
- for ( var type in events ) {
- for ( var i = 0, l = events[ type ].length; i < l; i++ ) {
- jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );
- }
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );
}
}
}
+
+ // make the cloned public data object a copy from the original
+ if ( curData.data ) {
+ curData.data = jQuery.extend( {}, curData.data );
+ }
}
function cloneFixAttributes( src, dest ) {
@@ -6048,7 +6224,10 @@ jQuery.extend({
// with an element if you are cloning the body and one of the
// elements on the page has a name or id of "length"
for ( i = 0; srcElements[i]; ++i ) {
- cloneFixAttributes( srcElements[i], destElements[i] );
+ // Ensure that the destination node is not null; Fixes #9587
+ if ( destElements[i] ) {
+ cloneFixAttributes( srcElements[i], destElements[i] );
+ }
}
}
@@ -6107,6 +6286,9 @@ jQuery.extend({
depth = wrap[0],
div = context.createElement("div");
+ // Append wrapper element to unknown element safe doc fragment
+ safeFragment.appendChild( div );
+
// Go to html and back, then peel off extra wrappers
div.innerHTML = wrap[1] + elem + wrap[2];
@@ -6187,7 +6369,9 @@ jQuery.extend({
},
cleanData: function( elems ) {
- var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special,
+ var data, id,
+ cache = jQuery.cache,
+ special = jQuery.event.special,
deleteExpando = jQuery.support.deleteExpando;
for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
@@ -6198,7 +6382,7 @@ jQuery.extend({
id = elem[ jQuery.expando ];
if ( id ) {
- data = cache[ id ] && cache[ id ][ internalKey ];
+ data = cache[ id ];
if ( data && data.events ) {
for ( var type in data.events ) {
@@ -6248,14 +6432,14 @@ function evalScript( i, elem ) {
+
var ralpha = /alpha\([^)]*\)/i,
ropacity = /opacity=([^)]*)/,
// fixed for IE9, see #8346
rupper = /([A-Z]|^ms)/g,
rnumpx = /^-?\d+(?:px)?$/i,
rnum = /^-?\d/,
- rrelNum = /^[+\-]=/,
- rrelNumFilter = /[^+\-\.\de]+/g,
+ rrelNum = /^([\-+])=([\-+.\de]+)/,
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
cssWidth = [ "Left", "Right" ],
@@ -6332,18 +6516,18 @@ jQuery.extend({
if ( value !== undefined ) {
type = typeof value;
- // Make sure that NaN and null values aren't set. See: #7116
- if ( type === "number" && isNaN( value ) || value == null ) {
- return;
- }
-
// convert relative number strings (+= or -=) to relative numbers. #7345
- if ( type === "string" && rrelNum.test( value ) ) {
- value = +value.replace( rrelNumFilter, "" ) + parseFloat( jQuery.css( elem, name ) );
+ if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+ value = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) );
// Fixes bug #9237
type = "number";
}
+ // Make sure that NaN and null values aren't set. See: #7116
+ if ( value == null || type === "number" && isNaN( value ) ) {
+ return;
+ }
+
// If a number was passed in, add 'px' to the (except for certain CSS properties)
if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
value += "px";
@@ -6459,18 +6643,29 @@ if ( !jQuery.support.opacity ) {
set: function( elem, value ) {
var style = elem.style,
- currentStyle = elem.currentStyle;
+ currentStyle = elem.currentStyle,
+ opacity = jQuery.isNaN( value ) ? "" : "alpha(opacity=" + value * 100 + ")",
+ filter = currentStyle && currentStyle.filter || style.filter || "";
// IE has trouble with opacity if it does not have layout
// Force it by setting the zoom level
style.zoom = 1;
- // Set the alpha filter to set the opacity
- var opacity = jQuery.isNaN( value ) ?
- "" :
- "alpha(opacity=" + value * 100 + ")",
- filter = currentStyle && currentStyle.filter || style.filter || "";
+ // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+ if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) {
+
+ // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+ // if "filter:" is present at all, clearType is disabled, we want to avoid this
+ // style.removeAttribute is IE Only, but so apparently is this code path...
+ style.removeAttribute( "filter" );
+
+ // if there there is no filter style applied in a css rule, we are done
+ if ( currentStyle && !currentStyle.filter ) {
+ return;
+ }
+ }
+ // otherwise, set new filter values
style.filter = ralpha.test( filter ) ?
filter.replace( ralpha, opacity ) :
filter + " " + opacity;
@@ -6609,7 +6804,7 @@ if ( jQuery.expr && jQuery.expr.filters ) {
var width = elem.offsetWidth,
height = elem.offsetHeight;
- return (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && (elem.style.display || jQuery.css( elem, "display" )) === "none");
+ return (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
};
jQuery.expr.filters.visible = function( elem ) {
@@ -6625,9 +6820,9 @@ var r20 = /%20/g,
rCRLF = /\r?\n/g,
rhash = /#.*$/,
rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
- rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
+ rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
// #7653, #8125, #8152: local protocol detection
- rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|widget):$/,
+ rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
rnoContent = /^(?:GET|HEAD)$/,
rprotocol = /^\/\//,
rquery = /\?/,
@@ -6662,7 +6857,10 @@ var r20 = /%20/g,
ajaxLocation,
// Document location segments
- ajaxLocParts;
+ ajaxLocParts,
+
+ // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+ allTypes = ["*/"] + ["*"];
// #8138, IE may throw an exception when accessing
// a field from window.location if document.domain has been set
@@ -6755,6 +6953,22 @@ function inspectPrefiltersOrTransports( structure, options, originalOptions, jqX
return selection;
}
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+ var key, deep,
+ flatOptions = jQuery.ajaxSettings.flatOptions || {};
+ for( key in src ) {
+ if ( src[ key ] !== undefined ) {
+ ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
+ }
+ }
+ if ( deep ) {
+ jQuery.extend( true, target, deep );
+ }
+}
+
jQuery.fn.extend({
load: function( url, params, callback ) {
if ( typeof url !== "string" && _load ) {
@@ -6898,23 +7112,16 @@ jQuery.extend({
// Creates a full fledged settings object into target
// with both ajaxSettings and settings fields.
// If target is omitted, writes into ajaxSettings.
- ajaxSetup: function ( target, settings ) {
- if ( !settings ) {
- // Only one parameter, we extend ajaxSettings
- settings = target;
- target = jQuery.extend( true, jQuery.ajaxSettings, settings );
+ ajaxSetup: function( target, settings ) {
+ if ( settings ) {
+ // Building a settings object
+ ajaxExtend( target, jQuery.ajaxSettings );
} else {
- // target was provided, we extend into it
- jQuery.extend( true, target, jQuery.ajaxSettings, settings );
- }
- // Flatten fields we don't want deep extended
- for( var field in { context: 1, url: 1 } ) {
- if ( field in settings ) {
- target[ field ] = settings[ field ];
- } else if( field in jQuery.ajaxSettings ) {
- target[ field ] = jQuery.ajaxSettings[ field ];
- }
+ // Extending ajaxSettings
+ settings = target;
+ target = jQuery.ajaxSettings;
}
+ ajaxExtend( target, settings );
return target;
},
@@ -6942,7 +7149,7 @@ jQuery.extend({
html: "text/html",
text: "text/plain",
json: "application/json, text/javascript",
- "*": "*/*"
+ "*": allTypes
},
contents: {
@@ -6972,6 +7179,15 @@ jQuery.extend({
// Parse text as xml
"text xml": jQuery.parseXML
+ },
+
+ // For options that shouldn't be deep extended:
+ // you can add your own custom options here if
+ // and when you create one that shouldn't be
+ // deep extended (see ajaxExtend)
+ flatOptions: {
+ context: true,
+ url: true
}
},
@@ -7002,7 +7218,7 @@ jQuery.extend({
jQuery( callbackContext ) : jQuery.event,
// Deferreds
deferred = jQuery.Deferred(),
- completeDeferred = jQuery._Deferred(),
+ completeDeferred = jQuery.Callbacks( "once memory" ),
// Status-dependent callbacks
statusCode = s.statusCode || {},
// ifModified key
@@ -7082,7 +7298,7 @@ jQuery.extend({
// Callback for when everything is done
// It is defined here because jslint complains if it is declared
// at the end of the function (which would be more logical and readable)
- function done( status, statusText, responses, headers ) {
+ function done( status, nativeStatusText, responses, headers ) {
// Called once
if ( state === 2 ) {
@@ -7105,11 +7321,12 @@ jQuery.extend({
responseHeadersString = headers || "";
// Set readyState
- jqXHR.readyState = status ? 4 : 0;
+ jqXHR.readyState = status > 0 ? 4 : 0;
var isSuccess,
success,
error,
+ statusText = nativeStatusText,
response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
lastModified,
etag;
@@ -7161,7 +7378,7 @@ jQuery.extend({
// Set data for the fake xhr object
jqXHR.status = status;
- jqXHR.statusText = statusText;
+ jqXHR.statusText = "" + ( nativeStatusText || statusText );
// Success/Error
if ( isSuccess ) {
@@ -7180,10 +7397,10 @@ jQuery.extend({
}
// Complete
- completeDeferred.resolveWith( callbackContext, [ jqXHR, statusText ] );
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
if ( fireGlobals ) {
- globalEventContext.trigger( "ajaxComplete", [ jqXHR, s] );
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
// Handle the global AJAX counter
if ( !( --jQuery.active ) ) {
jQuery.event.trigger( "ajaxStop" );
@@ -7195,7 +7412,7 @@ jQuery.extend({
deferred.promise( jqXHR );
jqXHR.success = jqXHR.done;
jqXHR.error = jqXHR.fail;
- jqXHR.complete = completeDeferred.done;
+ jqXHR.complete = completeDeferred.add;
// Status-dependent callbacks
jqXHR.statusCode = function( map ) {
@@ -7264,6 +7481,8 @@ jQuery.extend({
// If data is available, append data to url
if ( s.data ) {
s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
+ // #9682: remove data so that it's not used in an eventual retry
+ delete s.data;
}
// Get ifModifiedKey before adding the anti-cache parameter
@@ -7301,7 +7520,7 @@ jQuery.extend({
jqXHR.setRequestHeader(
"Accept",
s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
- s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) :
+ s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
s.accepts[ "*" ]
);
@@ -7347,7 +7566,7 @@ jQuery.extend({
transport.send( requestHeaders, done );
} catch (e) {
// Propagate exception as error if not done
- if ( status < 2 ) {
+ if ( state < 2 ) {
done( -1, e );
// Simply rethrow otherwise
} else {
@@ -7995,10 +8214,7 @@ var elemdisplay = {},
// opacity animations
[ "opacity" ]
],
- fxNow,
- requestAnimationFrame = window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- window.oRequestAnimationFrame;
+ fxNow;
jQuery.fn.extend({
show: function( speed, easing, callback ) {
@@ -8102,7 +8318,7 @@ jQuery.fn.extend({
},
animate: function( prop, speed, easing, callback ) {
- var optall = jQuery.speed(speed, easing, callback);
+ var optall = jQuery.speed( speed, easing, callback );
if ( jQuery.isEmptyObject( prop ) ) {
return this.each( optall.complete, [ false ] );
@@ -8111,7 +8327,7 @@ jQuery.fn.extend({
// Do not change referenced properties as per-property easing will be lost
prop = jQuery.extend( {}, prop );
- return this[ optall.queue === false ? "each" : "queue" ](function() {
+ function doAnimation() {
// XXX 'this' does not always have a nodeName when running the
// test suite
@@ -8122,9 +8338,9 @@ jQuery.fn.extend({
var opt = jQuery.extend( {}, optall ),
isElement = this.nodeType === 1,
hidden = isElement && jQuery(this).is(":hidden"),
- name, val, p,
- display, e,
- parts, start, end, unit;
+ name, val, p, e,
+ parts, start, end, unit,
+ method;
// will store per property easing and be used to determine when an animation is complete
opt.animatedProperties = {};
@@ -8160,25 +8376,17 @@ jQuery.fn.extend({
opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
// Set display property to inline-block for height/width
- // animations on inline elements that are having width/height
- // animated
+ // animations on inline elements that are having width/height animated
if ( jQuery.css( this, "display" ) === "inline" &&
jQuery.css( this, "float" ) === "none" ) {
- if ( !jQuery.support.inlineBlockNeedsLayout ) {
+
+ // inline-level elements accept inline-block;
+ // block-level elements need to be inline with layout
+ if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( this.nodeName ) === "inline" ) {
this.style.display = "inline-block";
} else {
- display = defaultDisplay( this.nodeName );
-
- // inline-level elements accept inline-block;
- // block-level elements need to be inline with layout
- if ( display === "inline" ) {
- this.style.display = "inline-block";
-
- } else {
- this.style.display = "inline";
- this.style.zoom = 1;
- }
+ this.style.zoom = 1;
}
}
}
@@ -8192,8 +8400,16 @@ jQuery.fn.extend({
e = new jQuery.fx( this, opt, p );
val = prop[ p ];
- if ( rfxtypes.test(val) ) {
- e[ val === "toggle" ? hidden ? "show" : "hide" : val ]();
+ if ( rfxtypes.test( val ) ) {
+ // Tracks whether to show or hide based on private
+ // data attached to the element
+ method = jQuery._data( this, "toggle" + p ) || (val === "toggle" ? hidden ? "show" : "hide" : 0);
+ if ( method ) {
+ jQuery._data( this, "toggle" + p, method === "show" ? "hide" : "show" );
+ e[ method ]();
+ } else {
+ e[ val ]();
+ }
} else {
parts = rfxnum.exec( val );
@@ -8225,7 +8441,11 @@ jQuery.fn.extend({
// For JS strict compliance
return true;
- });
+ }
+
+ return optall.queue === false ?
+ this.each( doAnimation ) :
+ this.queue( optall.queue || "fx", doAnimation );
},
stop: function( clearQueue, gotoEnd ) {
@@ -8236,18 +8456,21 @@ jQuery.fn.extend({
this.each(function() {
var timers = jQuery.timers,
i = timers.length;
+
// clear marker counters if we know they won't be
if ( !gotoEnd ) {
jQuery._unmark( true, this );
}
while ( i-- ) {
- if ( timers[i].elem === this ) {
- if (gotoEnd) {
+ if ( timers[ i ].elem === this ) {
+ if ( gotoEnd ) {
// force the next step to be the last
- timers[i](true);
+ timers[ i ]( true );
+ } else {
+ timers[ i ].saveState();
}
- timers.splice(i, 1);
+ timers.splice( i, 1 );
}
}
});
@@ -8276,7 +8499,7 @@ function clearFxNow() {
function genFx( type, num ) {
var obj = {};
- jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {
+ jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() {
obj[ this ] = type;
});
@@ -8285,9 +8508,9 @@ function genFx( type, num ) {
// Generate shortcuts for custom animations
jQuery.each({
- slideDown: genFx("show", 1),
- slideUp: genFx("hide", 1),
- slideToggle: genFx("toggle", 1),
+ slideDown: genFx( "show", 1 ),
+ slideUp: genFx( "hide", 1 ),
+ slideToggle: genFx( "toggle", 1 ),
fadeIn: { opacity: "show" },
fadeOut: { opacity: "hide" },
fadeToggle: { opacity: "toggle" }
@@ -8299,15 +8522,15 @@ jQuery.each({
jQuery.extend({
speed: function( speed, easing, fn ) {
- var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : {
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
complete: fn || !fn && easing ||
jQuery.isFunction( speed ) && speed,
duration: speed,
- easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
+ easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
};
opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
- opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[opt.duration] : jQuery.fx.speeds._default;
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
// Queueing
opt.old = opt.complete;
@@ -8317,7 +8540,7 @@ jQuery.extend({
}
if ( opt.queue !== false ) {
- jQuery.dequeue( this );
+ jQuery.dequeue( this, opt.queue || "fx" );
} else if ( noUnmark !== false ) {
jQuery._unmark( this );
}
@@ -8354,12 +8577,12 @@ jQuery.fx.prototype = {
this.options.step.call( this.elem, this.now, this );
}
- (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
+ (jQuery.fx.step[ this.prop ] || jQuery.fx.step._default)( this );
},
// Get the current size
cur: function() {
- if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {
+ if ( this.elem[ this.prop ] != null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) {
return this.elem[ this.prop ];
}
@@ -8374,50 +8597,46 @@ jQuery.fx.prototype = {
// Start an animation from one number to another
custom: function( from, to, unit ) {
var self = this,
- fx = jQuery.fx,
- raf;
+ fx = jQuery.fx;
this.startTime = fxNow || createFxNow();
- this.start = from;
this.end = to;
- this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
- this.now = this.start;
+ this.now = this.start = from;
this.pos = this.state = 0;
+ this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
function t( gotoEnd ) {
- return self.step(gotoEnd);
+ return self.step( gotoEnd );
}
t.elem = this.elem;
+ t.saveState = function() {
+ if ( self.options.hide && jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
+ jQuery._data( self.elem, "fxshow" + self.prop, self.start );
+ }
+ };
if ( t() && jQuery.timers.push(t) && !timerId ) {
- // Use requestAnimationFrame instead of setInterval if available
- if ( requestAnimationFrame ) {
- timerId = true;
- raf = function() {
- // When timerId gets set to null at any point, this stops
- if ( timerId ) {
- requestAnimationFrame( raf );
- fx.tick();
- }
- };
- requestAnimationFrame( raf );
- } else {
- timerId = setInterval( fx.tick, fx.interval );
- }
+ timerId = setInterval( fx.tick, fx.interval );
}
},
// Simple 'show' function
show: function() {
+ var dataShow = jQuery._data( this.elem, "fxshow" + this.prop );
+
// Remember where we started, so that we can go back to it later
- this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
+ this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop );
this.options.show = true;
// Begin the animation
- // Make sure that we start at a small width/height to avoid any
- // flash of content
- this.custom(this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur());
+ // Make sure that we start at a small width/height to avoid any flash of content
+ if ( dataShow !== undefined ) {
+ // This show is picking up where a previous hide or show left off
+ this.custom( this.cur(), dataShow );
+ } else {
+ this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() );
+ }
// Start by showing the element
jQuery( this.elem ).show();
@@ -8426,11 +8645,11 @@ jQuery.fx.prototype = {
// Simple 'hide' function
hide: function() {
// Remember where we started, so that we can go back to it later
- this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
+ this.options.orig[ this.prop ] = jQuery._data( this.elem, "fxshow" + this.prop ) || jQuery.style( this.elem, this.prop );
this.options.hide = true;
// Begin the animation
- this.custom(this.cur(), 0);
+ this.custom( this.cur(), 0 );
},
// Each step of an animation
@@ -8439,7 +8658,7 @@ jQuery.fx.prototype = {
done = true,
elem = this.elem,
options = this.options,
- i, n;
+ p, n;
if ( gotoEnd || t >= options.duration + this.startTime ) {
this.now = this.end;
@@ -8448,8 +8667,8 @@ jQuery.fx.prototype = {
options.animatedProperties[ this.prop ] = true;
- for ( i in options.animatedProperties ) {
- if ( options.animatedProperties[i] !== true ) {
+ for ( p in options.animatedProperties ) {
+ if ( options.animatedProperties[ p ] !== true ) {
done = false;
}
}
@@ -8458,20 +8677,23 @@ jQuery.fx.prototype = {
// Reset the overflow
if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
- jQuery.each( [ "", "X", "Y" ], function (index, value) {
- elem.style[ "overflow" + value ] = options.overflow[index];
+ jQuery.each( [ "", "X", "Y" ], function( index, value ) {
+ elem.style[ "overflow" + value ] = options.overflow[ index ];
});
}
// Hide the element if the "hide" operation was done
if ( options.hide ) {
- jQuery(elem).hide();
+ jQuery( elem ).hide();
}
// Reset the properties, if the item has been hidden or shown
if ( options.hide || options.show ) {
- for ( var p in options.animatedProperties ) {
- jQuery.style( elem, p, options.orig[p] );
+ for ( p in options.animatedProperties ) {
+ jQuery.style( elem, p, options.orig[ p ] );
+ jQuery.removeData( elem, "fxshow" + p, true );
+ // Toggle data is no longer needed
+ jQuery.removeData( elem, "toggle" + p, true );
}
}
@@ -8490,8 +8712,8 @@ jQuery.fx.prototype = {
this.state = n / options.duration;
// Perform the easing function, defaults to swing
- this.pos = jQuery.easing[ options.animatedProperties[ this.prop ] ]( this.state, n, 0, 1, options.duration );
- this.now = this.start + ((this.end - this.start) * this.pos);
+ this.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration );
+ this.now = this.start + ( (this.end - this.start) * this.pos );
}
// Perform the next step of the animation
this.update();
@@ -8503,9 +8725,15 @@ jQuery.fx.prototype = {
jQuery.extend( jQuery.fx, {
tick: function() {
- for ( var timers = jQuery.timers, i = 0 ; i < timers.length ; ++i ) {
- if ( !timers[i]() ) {
- timers.splice(i--, 1);
+ var timer,
+ timers = jQuery.timers,
+ i = 0;
+
+ for ( ; i < timers.length; i++ ) {
+ timer = timers[ i ];
+ // Checks the timer has not already been removed
+ if ( !timer() && timers[ i ] === timer ) {
+ timers.splice( i--, 1 );
}
}
@@ -8535,7 +8763,7 @@ jQuery.extend( jQuery.fx, {
_default: function( fx ) {
if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
- fx.elem.style[ fx.prop ] = (fx.prop === "width" || fx.prop === "height" ? Math.max(0, fx.now) : fx.now) + fx.unit;
+ fx.elem.style[ fx.prop ] = fx.now + fx.unit;
} else {
fx.elem[ fx.prop ] = fx.now;
}
@@ -8543,6 +8771,14 @@ jQuery.extend( jQuery.fx, {
}
});
+// Adds width/height step functions
+// Do not set anything below 0
+jQuery.each([ "width", "height" ], function( i, prop ) {
+ jQuery.fx.step[ prop ] = function( fx ) {
+ jQuery.style( fx.elem, prop, Math.max(0, fx.now) );
+ };
+});
+
if ( jQuery.expr && jQuery.expr.filters ) {
jQuery.expr.filters.animated = function( elem ) {
return jQuery.grep(jQuery.timers, function( fn ) {
@@ -8664,8 +8900,6 @@ if ( "getBoundingClientRect" in document.documentElement ) {
return jQuery.offset.bodyOffset( elem );
}
- jQuery.offset.initialize();
-
var computedStyle,
offsetParent = elem.offsetParent,
prevOffsetParent = elem,
@@ -8721,46 +8955,22 @@ if ( "getBoundingClientRect" in document.documentElement ) {
};
}
-jQuery.offset = {
- initialize: function() {
- var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.css(body, "marginTop") ) || 0,
- html = "
";
-
- jQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } );
-
- container.innerHTML = html;
- body.insertBefore( container, body.firstChild );
- innerDiv = container.firstChild;
- checkDiv = innerDiv.firstChild;
- td = innerDiv.nextSibling.firstChild.firstChild;
-
- this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
- this.doesAddBorderForTableAndCells = (td.offsetTop === 5);
-
- checkDiv.style.position = "fixed";
- checkDiv.style.top = "20px";
-
- // safari subtracts parent border width here which is 5px
- this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);
- checkDiv.style.position = checkDiv.style.top = "";
-
- innerDiv.style.overflow = "hidden";
- innerDiv.style.position = "relative";
+jQuery.offset = {};
- this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
+jQuery.each(
+ ( "doesAddBorderForTableAndCells doesNotAddBorder " +
+ "doesNotIncludeMarginInBodyOffset subtractsBorderForOverflowNotVisible " +
+ "supportsFixedPosition" ).split(" "), function( i, prop ) {
- this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);
+ jQuery.offset[ prop ] = jQuery.support[ prop ];
+});
- body.removeChild( container );
- jQuery.offset.initialize = jQuery.noop;
- },
+jQuery.extend( jQuery.offset, {
bodyOffset: function( body ) {
var top = body.offsetTop,
left = body.offsetLeft;
- jQuery.offset.initialize();
-
if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
top += parseFloat( jQuery.css(body, "marginTop") ) || 0;
left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
@@ -8811,10 +9021,11 @@ jQuery.offset = {
curElem.css( props );
}
}
-};
+});
jQuery.fn.extend({
+
position: function() {
if ( !this[0] ) {
return null;
@@ -8947,9 +9158,10 @@ jQuery.each([ "Height", "Width" ], function( i, name ) {
if ( jQuery.isWindow( elem ) ) {
// Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
// 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
- var docElemProp = elem.document.documentElement[ "client" + name ];
+ var docElemProp = elem.document.documentElement[ "client" + name ],
+ body = elem.document.body;
return elem.document.compatMode === "CSS1Compat" && docElemProp ||
- elem.document.body[ "client" + name ] || docElemProp;
+ body && body[ "client" + name ] || docElemProp;
// Get document width or height
} else if ( elem.nodeType === 9 ) {