| (function( jQuery ) { |
| |
| var rbrace = /^(?:\{.*\}|\[.*\])$/; |
| |
| jQuery.extend({ |
| cache: {}, |
| |
| // Please use with caution |
| uuid: 0, |
| |
| // Unique for each copy of jQuery on the page |
| // Non-digits removed to match rinlinejQuery |
| expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), |
| |
| // The following elements throw uncatchable exceptions if you |
| // attempt to add expando properties to them. |
| noData: { |
| "embed": true, |
| // Ban all objects except for Flash (which handle expandos) |
| "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", |
| "applet": true |
| }, |
| |
| hasData: function( elem ) { |
| elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; |
| |
| return !!elem && !isEmptyDataObject( elem ); |
| }, |
| |
| data: function( elem, name, data, pvt /* Internal Use Only */ ) { |
| if ( !jQuery.acceptData( elem ) ) { |
| return; |
| } |
| |
| var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache, |
| |
| // We have to handle DOM nodes and JS objects differently because IE6-7 |
| // can't GC object references properly across the DOM-JS boundary |
| isNode = elem.nodeType, |
| |
| // Only DOM nodes need the global jQuery cache; JS object data is |
| // attached directly to the object so GC can occur automatically |
| cache = isNode ? jQuery.cache : elem, |
| |
| // Only defining an ID for JS objects if its cache already exists allows |
| // the code to shortcut on the same path as a DOM node with no cache |
| id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando; |
| |
| // 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 ) { |
| return; |
| } |
| |
| if ( !id ) { |
| // Only DOM nodes need a new unique ID for each element since their data |
| // ends up in the global cache |
| if ( isNode ) { |
| elem[ jQuery.expando ] = id = ++jQuery.uuid; |
| } else { |
| id = jQuery.expando; |
| } |
| } |
| |
| 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 |
| if ( !isNode ) { |
| cache[ id ].toJSON = jQuery.noop; |
| } |
| } |
| |
| // An object can be passed to jQuery.data instead of a key/value pair; this gets |
| // 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); |
| } else { |
| cache[ id ] = jQuery.extend(cache[ id ], name); |
| } |
| } |
| |
| thisCache = cache[ id ]; |
| |
| // Internal jQuery data is stored in a separate object inside the object's data |
| // cache in order to avoid key collisions between internal data and user-defined |
| // data |
| if ( pvt ) { |
| if ( !thisCache[ internalKey ] ) { |
| thisCache[ internalKey ] = {}; |
| } |
| |
| thisCache = thisCache[ internalKey ]; |
| } |
| |
| if ( data !== undefined ) { |
| thisCache[ name ] = data; |
| } |
| |
| // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should |
| // not attempt to inspect the internal events object using jQuery.data, as this |
| // internal data object is undocumented and subject to change. |
| if ( name === "events" && !thisCache[name] ) { |
| return thisCache[ internalKey ] && thisCache[ internalKey ].events; |
| } |
| |
| return getByName ? thisCache[ name ] : thisCache; |
| }, |
| |
| removeData: function( elem, name, pvt /* Internal Use Only */ ) { |
| if ( !jQuery.acceptData( elem ) ) { |
| return; |
| } |
| |
| var internalKey = jQuery.expando, isNode = elem.nodeType, |
| |
| // See jQuery.data for more information |
| cache = isNode ? jQuery.cache : elem, |
| |
| // See jQuery.data for more information |
| id = isNode ? elem[ jQuery.expando ] : jQuery.expando; |
| |
| // If there is already no cache entry for this object, there is no |
| // purpose in continuing |
| if ( !cache[ id ] ) { |
| return; |
| } |
| |
| if ( name ) { |
| var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ]; |
| |
| if ( thisCache ) { |
| delete thisCache[ name ]; |
| |
| // If there is no data left in the cache, we want to continue |
| // and let the cache object itself get destroyed |
| if ( !isEmptyDataObject(thisCache) ) { |
| return; |
| } |
| } |
| } |
| |
| // See jQuery.data for more information |
| if ( pvt ) { |
| delete cache[ id ][ internalKey ]; |
| |
| // Don't destroy the parent cache unless the internal data object |
| // had been the only thing left in it |
| if ( !isEmptyDataObject(cache[ id ]) ) { |
| return; |
| } |
| } |
| |
| 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 ) { |
| 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 |
| // false lookups in the cache for entries that no longer exist |
| } else 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 |
| if ( jQuery.support.deleteExpando ) { |
| delete elem[ jQuery.expando ]; |
| } else if ( elem.removeAttribute ) { |
| elem.removeAttribute( jQuery.expando ); |
| } else { |
| elem[ jQuery.expando ] = null; |
| } |
| } |
| }, |
| |
| // For internal use only. |
| _data: function( elem, name, data ) { |
| return jQuery.data( elem, name, data, true ); |
| }, |
| |
| // A method for determining if a DOM node can handle the data expando |
| acceptData: function( elem ) { |
| if ( elem.nodeName ) { |
| var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; |
| |
| if ( match ) { |
| return !(match === true || elem.getAttribute("classid") !== match); |
| } |
| } |
| |
| return true; |
| } |
| }); |
| |
| jQuery.fn.extend({ |
| data: function( key, value ) { |
| var 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; |
| for ( var i = 0, l = attr.length; i < l; i++ ) { |
| name = attr[i].name; |
| |
| if ( name.indexOf( "data-" ) === 0 ) { |
| name = name.substr( 5 ); |
| dataAttr( this[0], name, data[ name ] ); |
| } |
| } |
| } |
| } |
| |
| return data; |
| |
| } else if ( typeof key === "object" ) { |
| return this.each(function() { |
| jQuery.data( this, key ); |
| }); |
| } |
| |
| var parts = key.split("."); |
| parts[1] = parts[1] ? "." + parts[1] : ""; |
| |
| if ( value === undefined ) { |
| data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); |
| |
| // Try to fetch any internally stored data first |
| if ( data === undefined && this.length ) { |
| data = jQuery.data( this[0], key ); |
| data = dataAttr( this[0], key, data ); |
| } |
| |
| return data === undefined && parts[1] ? |
| this.data( parts[0] ) : |
| data; |
| |
| } else { |
| return this.each(function() { |
| var $this = jQuery( this ), |
| args = [ parts[0], value ]; |
| |
| $this.triggerHandler( "setData" + parts[1] + "!", args ); |
| jQuery.data( this, key, value ); |
| $this.triggerHandler( "changeData" + parts[1] + "!", args ); |
| }); |
| } |
| }, |
| |
| removeData: function( key ) { |
| return this.each(function() { |
| jQuery.removeData( this, key ); |
| }); |
| } |
| }); |
| |
| 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 ) { |
| data = elem.getAttribute( "data-" + key ); |
| |
| if ( typeof data === "string" ) { |
| try { |
| data = data === "true" ? true : |
| data === "false" ? false : |
| data === "null" ? null : |
| !jQuery.isNaN( data ) ? parseFloat( data ) : |
| rbrace.test( data ) ? jQuery.parseJSON( data ) : |
| data; |
| } catch( e ) {} |
| |
| // Make sure we set the data so it isn't changed later |
| jQuery.data( elem, key, data ); |
| |
| } else { |
| data = undefined; |
| } |
| } |
| |
| 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 |
| function isEmptyDataObject( obj ) { |
| for ( var name in obj ) { |
| if ( name !== "toJSON" ) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| })( jQuery ); |