jquery/src/data.js
John Resig 67d445a703 A follow-up to [6578] (which stopped adding expandos to elements that didn't have data). That broke jQuery.unique() (so we're now using the unique from Sizzle). Using Sizzle's unique (which also sorts in document order) changed how add, andSelf, parents, nextAll, prevAll, and siblings work. after and before were changed to not use .add() (in order to guarantee their position in the jQuery set). Also, jQuery.data(elem) was updated to return that element's data object (instead of its ID).
$("<div/>").after("<span/>")
=> [ div, span ]
(calling after on a disconnected DOM node adds the nodes to the end of the jQuery set)

$("<div/>").before("<span/>")
=> [ span, div ]
(calling before on a disconnected DOM node adds the nodes to the beginning of the jQuery set)

$("div").add("span")
=> [ div, span, span, div, span ]
(results now come out in document order)

$("div").find("code").andSelf();
=> [ div, code, code ]
(results now come out in document order)

Same goes for .parents(), .nextAll(), .prevAll(), and .siblings().

Exception: .parents() will still return the results in reverse document order.

jQuery.data(elem)
=> { object of data }
(no longer returns the unique ID assigned to the node)
2009-09-25 17:55:20 +00:00

171 lines
4 KiB
JavaScript

var expando = "jQuery" + now(), uuid = 0, windowData = {};
var emptyObject = {};
jQuery.extend({
cache: {},
expando:expando,
data: function( elem, name, data ) {
elem = elem == window ?
windowData :
elem;
var id = elem[ expando ], cache = jQuery.cache, thisCache;
// Handle the case where there's no name immediately
if ( !name && !id ) {
return null;
}
// Compute a unique ID for the element
if ( !id ) {
id = ++uuid;
}
// Avoid generating a new cache unless none exists and we
// want to manipulate it.
if ( cache[ id ] ) {
thisCache = cache[ id ];
} else if ( typeof data === "undefined" ) {
thisCache = emptyObject;
} else {
thisCache = cache[ id ] = {};
}
// Prevent overriding the named cache with undefined values
if ( data !== undefined ) {
elem[ expando ] = id;
thisCache[ name ] = data;
}
return name ? thisCache[ name ] : thisCache;
},
removeData: function( elem, name ) {
elem = elem == window ?
windowData :
elem;
var id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ];
// If we want to remove a specific section of the element's data
if ( name ) {
if ( thisCache ) {
// Remove the section of cache data
delete thisCache[ name ];
// If we've removed all the data, remove the element's cache
if ( jQuery.isEmptyObject(thisCache) ) {
jQuery.removeData( elem );
}
}
// Otherwise, we want to remove all of the element's data
} else {
// Clean up the element expando
try {
delete elem[ expando ];
} catch( e ) {
// IE has trouble directly removing the expando
// but it's ok with using removeAttribute
if ( elem.removeAttribute ) {
elem.removeAttribute( expando );
}
}
// Completely remove the data cache
delete cache[ id ];
}
},
queue: function( elem, type, data ) {
if( !elem ) return;
type = (type || "fx") + "queue";
var q = jQuery.data( elem, type );
// Speed up dequeue by getting out quickly if this is just a lookup
if( !data ) return q || [];
if ( !q || jQuery.isArray(data) )
q = jQuery.data( elem, type, jQuery.makeArray(data) );
else
q.push( data );
return q;
},
dequeue: function( elem, type ){
type = type || "fx";
var queue = jQuery.queue( elem, type ), fn = queue.shift();
// If the fx queue is dequeued, always remove the progress sentinel
if( fn === "inprogress" ) fn = queue.shift();
if( fn ) {
// Add a progress sentinel to prevent the fx queue from being
// automatically dequeued
if( type == "fx" ) queue.unshift("inprogress");
fn.call(elem, function() { jQuery.dequeue(elem, type); });
}
}
});
jQuery.fn.extend({
data: function( key, value ){
if ( typeof key === "undefined" && this.length ) {
return jQuery.data( this[0] );
}
var parts = key.split(".");
parts[1] = parts[1] ? "." + parts[1] : "";
if ( value === undefined ) {
var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
if ( data === undefined && this.length )
data = jQuery.data( this[0], key );
return data === undefined && parts[1] ?
this.data( parts[0] ) :
data;
} else
return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
jQuery.data( this, key, value );
});
},
removeData: function( key ){
return this.each(function(){
jQuery.removeData( this, key );
});
},
queue: function(type, data){
if ( typeof type !== "string" ) {
data = type;
type = "fx";
}
if ( data === undefined )
return jQuery.queue( this[0], type );
return this.each(function(i, elem){
var queue = jQuery.queue( this, type, data );
if( type == "fx" && queue[0] !== "inprogress" )
jQuery.dequeue( this, type )
});
},
dequeue: function(type){
return this.each(function(){
jQuery.dequeue( this, type );
});
},
clearQueue: function(type){
return this.queue( type || "fx", [] );
}
});