mirror of
https://github.com/jquery/jquery.git
synced 2024-11-23 02:54:22 +00:00
Create private methods for processing data/removeData requests. Fixes #12519, Closes gh-976
This commit is contained in:
parent
2e3ca6ca46
commit
08e134548f
354
src/data.js
354
src/data.js
@ -1,5 +1,179 @@
|
||||
var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
|
||||
rmultiDash = /([A-Z])/g;
|
||||
|
||||
function internalData( elem, name, data, pvt /* Internal Use Only */ ){
|
||||
if ( !jQuery.acceptData( elem ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
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[ internalKey ] : elem[ internalKey ] && internalKey;
|
||||
|
||||
// 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 || !cache[id] || (!pvt && !cache[id].data)) && 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[ internalKey ] = id = jQuery.deletedIds.pop() || jQuery.guid++;
|
||||
} else {
|
||||
id = internalKey;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !cache[ id ] ) {
|
||||
cache[ id ] = {};
|
||||
|
||||
// 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 ] = jQuery.extend( cache[ id ], name );
|
||||
} else {
|
||||
cache[ id ].data = jQuery.extend( cache[ id ].data, name );
|
||||
}
|
||||
}
|
||||
|
||||
thisCache = cache[ id ];
|
||||
|
||||
// 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.data ) {
|
||||
thisCache.data = {};
|
||||
}
|
||||
|
||||
thisCache = thisCache.data;
|
||||
}
|
||||
|
||||
if ( data !== undefined ) {
|
||||
thisCache[ jQuery.camelCase( name ) ] = data;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
function internalRemoveData( elem, name, pvt /* For internal use only */ ){
|
||||
if ( !jQuery.acceptData( elem ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var thisCache, i, l,
|
||||
|
||||
isNode = elem.nodeType,
|
||||
|
||||
// See jQuery.data for more information
|
||||
cache = isNode ? jQuery.cache : elem,
|
||||
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 ) {
|
||||
|
||||
thisCache = pvt ? cache[ id ] : cache[ id ].data;
|
||||
|
||||
if ( thisCache ) {
|
||||
|
||||
// Support array or space separated string names for data keys
|
||||
if ( !jQuery.isArray( name ) ) {
|
||||
|
||||
// try the string as a key before any manipulation
|
||||
if ( name in thisCache ) {
|
||||
name = [ name ];
|
||||
} else {
|
||||
|
||||
// split the camel cased version by spaces unless a key with the spaces exists
|
||||
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 ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// See jQuery.data for more information
|
||||
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
|
||||
if ( !isEmptyDataObject( cache[ id ] ) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy the cache
|
||||
if ( isNode ) {
|
||||
jQuery.cleanData( [ elem ], true );
|
||||
|
||||
// Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
|
||||
} else if ( jQuery.support.deleteExpando || cache != cache.window ) {
|
||||
delete cache[ id ];
|
||||
|
||||
// When all else fails, null
|
||||
} else {
|
||||
cache[ id ] = null;
|
||||
}
|
||||
}
|
||||
|
||||
jQuery.extend({
|
||||
cache: {},
|
||||
@ -27,183 +201,21 @@ jQuery.extend({
|
||||
return !!elem && !isEmptyDataObject( elem );
|
||||
},
|
||||
|
||||
data: function( elem, name, data, pvt /* Internal Use Only */ ) {
|
||||
if ( !jQuery.acceptData( elem ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
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[ internalKey ] : elem[ internalKey ] && internalKey;
|
||||
|
||||
// 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 || !cache[id] || (!pvt && !cache[id].data)) && 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[ internalKey ] = id = jQuery.deletedIds.pop() || jQuery.guid++;
|
||||
} else {
|
||||
id = internalKey;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !cache[ id ] ) {
|
||||
cache[ id ] = {};
|
||||
|
||||
// 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 ] = jQuery.extend( cache[ id ], name );
|
||||
} else {
|
||||
cache[ id ].data = jQuery.extend( cache[ id ].data, name );
|
||||
}
|
||||
}
|
||||
|
||||
thisCache = cache[ id ];
|
||||
|
||||
// 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.data ) {
|
||||
thisCache.data = {};
|
||||
}
|
||||
|
||||
thisCache = thisCache.data;
|
||||
}
|
||||
|
||||
if ( data !== undefined ) {
|
||||
thisCache[ jQuery.camelCase( name ) ] = data;
|
||||
}
|
||||
|
||||
// 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;
|
||||
data: function( elem, name, data ) {
|
||||
return internalData( elem, name, data, false );
|
||||
},
|
||||
|
||||
removeData: function( elem, name, pvt /* Internal Use Only */ ) {
|
||||
if ( !jQuery.acceptData( elem ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var thisCache, i, l,
|
||||
|
||||
isNode = elem.nodeType,
|
||||
|
||||
// See jQuery.data for more information
|
||||
cache = isNode ? jQuery.cache : elem,
|
||||
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 ) {
|
||||
|
||||
thisCache = pvt ? cache[ id ] : cache[ id ].data;
|
||||
|
||||
if ( thisCache ) {
|
||||
|
||||
// Support array or space separated string names for data keys
|
||||
if ( !jQuery.isArray( name ) ) {
|
||||
|
||||
// try the string as a key before any manipulation
|
||||
if ( name in thisCache ) {
|
||||
name = [ name ];
|
||||
} else {
|
||||
|
||||
// split the camel cased version by spaces unless a key with the spaces exists
|
||||
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 ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// See jQuery.data for more information
|
||||
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
|
||||
if ( !isEmptyDataObject( cache[ id ] ) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy the cache
|
||||
if ( isNode ) {
|
||||
jQuery.cleanData( [ elem ], true );
|
||||
|
||||
// Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
|
||||
} else if ( jQuery.support.deleteExpando || cache != cache.window ) {
|
||||
delete cache[ id ];
|
||||
|
||||
// When all else fails, null
|
||||
} else {
|
||||
cache[ id ] = null;
|
||||
}
|
||||
removeData: function( elem, name ) {
|
||||
return internalRemoveData( elem, name, false );
|
||||
},
|
||||
|
||||
// For internal use only.
|
||||
_data: function( elem, name, data ) {
|
||||
return jQuery.data( elem, name, data, true );
|
||||
return internalData( elem, name, data, true );
|
||||
},
|
||||
|
||||
_removeData: function( elem, name ) {
|
||||
return internalRemoveData( elem, name, true );
|
||||
},
|
||||
|
||||
// A method for determining if a DOM node can handle the data expando
|
||||
|
2
src/effects.js
vendored
2
src/effects.js
vendored
@ -327,7 +327,7 @@ function defaultPrefilter( elem, props, opts ) {
|
||||
}
|
||||
anim.done(function() {
|
||||
var prop;
|
||||
jQuery.removeData( elem, "fxshow", true );
|
||||
jQuery._removeData( elem, "fxshow" );
|
||||
for ( prop in orig ) {
|
||||
jQuery.style( elem, prop, orig[ prop ] );
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ var rformElems = /^(?:textarea|input|select)$/i,
|
||||
jQuery.event = {
|
||||
|
||||
add: function( elem, types, handler, data, selector ) {
|
||||
|
||||
var elemData, eventHandle, events,
|
||||
t, tns, type, namespaces, handleObj,
|
||||
handleObjIn, handlers, special;
|
||||
@ -196,7 +195,7 @@ jQuery.event = {
|
||||
|
||||
// removeData also checks for emptiness and clears the expando if empty
|
||||
// so use it instead of delete
|
||||
jQuery.removeData( elem, "events", true );
|
||||
jQuery._removeData( elem, "events" );
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -58,8 +58,8 @@ jQuery.extend({
|
||||
var key = type + "queueHooks";
|
||||
return jQuery._data( elem, key ) || jQuery._data( elem, key, {
|
||||
empty: jQuery.Callbacks("once memory").add(function() {
|
||||
jQuery.removeData( elem, type + "queue", true );
|
||||
jQuery.removeData( elem, key, true );
|
||||
jQuery._removeData( elem, type + "queue" );
|
||||
jQuery._removeData( elem, key );
|
||||
})
|
||||
});
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ function dataTests (elem) {
|
||||
}
|
||||
|
||||
var oldCacheLength, dataObj, internalDataObj, expected, actual;
|
||||
|
||||
|
||||
equal( jQuery.data(elem, "foo"), undefined, "No data exists initially" );
|
||||
strictEqual( jQuery.hasData(elem), false, "jQuery.hasData agrees no data exists initially" );
|
||||
|
||||
@ -50,7 +50,7 @@ function dataTests (elem) {
|
||||
strictEqual( jQuery.data(elem, "foo"), "foo1", "Passing an object extends the data object instead of replacing it" );
|
||||
equal( jQuery.data(elem, "boom"), "bloz", "Extending the data object works" );
|
||||
|
||||
jQuery._data(elem, "foo", "foo2");
|
||||
jQuery._data(elem, "foo", "foo2", true);
|
||||
equal( jQuery._data(elem, "foo"), "foo2", "Setting internal data works" );
|
||||
equal( jQuery.data(elem, "foo"), "foo1", "Setting internal data does not override user data" );
|
||||
|
||||
@ -66,9 +66,9 @@ function dataTests (elem) {
|
||||
jQuery.removeData(elem);
|
||||
strictEqual( jQuery._data(elem), internalDataObj, "jQuery.removeData does not remove internal data if it exists" );
|
||||
|
||||
jQuery.removeData(elem, undefined, true);
|
||||
jQuery._removeData(elem);
|
||||
|
||||
strictEqual( jQuery.data(elem, jQuery.expando), undefined, "jQuery.removeData on internal data works" );
|
||||
strictEqual( jQuery._data(elem, jQuery.expando), undefined, "jQuery.removeData on internal data works" );
|
||||
strictEqual( jQuery.hasData(elem), false, "jQuery.hasData agrees all data has been removed from object" );
|
||||
|
||||
jQuery._data(elem, "foo", "foo2");
|
||||
@ -79,7 +79,7 @@ function dataTests (elem) {
|
||||
|
||||
// delete the last private data key so we can test removing public data
|
||||
// will destroy the cache
|
||||
jQuery.removeData( elem, "foo", true );
|
||||
jQuery._removeData( elem, "foo" );
|
||||
|
||||
if (elem.nodeType) {
|
||||
oldCacheLength = getCacheLength();
|
||||
@ -109,9 +109,9 @@ function dataTests (elem) {
|
||||
equal( jQuery.data(elem, "foo"), "foo1", "(sanity check) Ensure data is set in user data object" );
|
||||
equal( jQuery._data(elem, "foo"), "foo2", "(sanity check) Ensure data is set in internal data object" );
|
||||
|
||||
jQuery.removeData(elem, "foo", true);
|
||||
jQuery._removeData(elem, "foo");
|
||||
|
||||
strictEqual( jQuery.data(elem, jQuery.expando), undefined, "Removing the last item in internal data destroys the internal data object" );
|
||||
strictEqual( jQuery._data(elem, jQuery.expando), undefined, "Removing the last item in internal data destroys the internal data object" );
|
||||
|
||||
jQuery._data(elem, "foo", "foo2");
|
||||
equal( jQuery._data(elem, "foo"), "foo2", "(sanity check) Ensure data is set in internal data object" );
|
||||
@ -121,11 +121,11 @@ function dataTests (elem) {
|
||||
|
||||
if ( elem.nodeType ) {
|
||||
oldCacheLength = getCacheLength();
|
||||
jQuery.removeData(elem, "foo", true);
|
||||
jQuery._removeData(elem, "foo");
|
||||
equal( getCacheLength(), oldCacheLength - 1, "Removing the last item in the internal data object also destroys the user data object when it is empty" );
|
||||
}
|
||||
else {
|
||||
jQuery.removeData(elem, "foo", true);
|
||||
jQuery._removeData(elem, "foo");
|
||||
|
||||
if (jQuery.support.deleteExpando) {
|
||||
expected = false;
|
||||
|
Loading…
Reference in New Issue
Block a user