Changed the expando string to use a random number instead of the time, so collisions...
[jquery.git] / src / data.js
1 (function( jQuery ) {
2
3 var windowData = {},
4         rbrace = /^(?:\{.*\}|\[.*\])$/;
5
6 jQuery.extend({
7         cache: {},
8
9         // Please use with caution
10         uuid: 0,
11
12         // Unique for each copy of jQuery on the page
13         // Non-digits removed to match rinlinejQuery
14         expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
15
16         // The following elements throw uncatchable exceptions if you
17         // attempt to add expando properties to them.
18         noData: {
19                 "embed": true,
20                 // Ban all objects except for Flash (which handle expandos)
21                 "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
22                 "applet": true
23         },
24
25         data: function( elem, name, data ) {
26                 if ( !jQuery.acceptData( elem ) ) {
27                         return;
28                 }
29
30                 elem = elem == window ?
31                         windowData :
32                         elem;
33
34                 var isNode = elem.nodeType,
35                         id = isNode ? elem[ jQuery.expando ] : null,
36                         cache = jQuery.cache, thisCache;
37
38                 if ( isNode && !id && typeof name === "string" && data === undefined ) {
39                         return;
40                 }
41
42                 // Get the data from the object directly
43                 if ( !isNode ) {
44                         cache = elem;
45
46                 // Compute a unique ID for the element
47                 } else if ( !id ) {
48                         elem[ jQuery.expando ] = id = ++jQuery.uuid;
49                 }
50
51                 // Avoid generating a new cache unless none exists and we
52                 // want to manipulate it.
53                 if ( typeof name === "object" ) {
54                         if ( isNode ) {
55                                 cache[ id ] = jQuery.extend(cache[ id ], name);
56
57                         } else {
58                                 jQuery.extend( cache, name );
59                         }
60
61                 } else if ( isNode && !cache[ id ] ) {
62                         cache[ id ] = {};
63                 }
64
65                 thisCache = isNode ? cache[ id ] : cache;
66
67                 // Prevent overriding the named cache with undefined values
68                 if ( data !== undefined ) {
69                         thisCache[ name ] = data;
70                 }
71
72                 return typeof name === "string" ? thisCache[ name ] : thisCache;
73         },
74
75         removeData: function( elem, name ) {
76                 if ( !jQuery.acceptData( elem ) ) {
77                         return;
78                 }
79
80                 elem = elem == window ?
81                         windowData :
82                         elem;
83
84                 var isNode = elem.nodeType,
85                         id = isNode ? elem[ jQuery.expando ] : elem,
86                         cache = jQuery.cache,
87                         thisCache = isNode ? cache[ id ] : id;
88
89                 // If we want to remove a specific section of the element's data
90                 if ( name ) {
91                         if ( thisCache ) {
92                                 // Remove the section of cache data
93                                 delete thisCache[ name ];
94
95                                 // If we've removed all the data, remove the element's cache
96                                 if ( isNode && jQuery.isEmptyObject(thisCache) ) {
97                                         jQuery.removeData( elem );
98                                 }
99                         }
100
101                 // Otherwise, we want to remove all of the element's data
102                 } else {
103                         if ( isNode && jQuery.support.deleteExpando ) {
104                                 delete elem[ jQuery.expando ];
105
106                         } else if ( elem.removeAttribute ) {
107                                 elem.removeAttribute( jQuery.expando );
108
109                         // Completely remove the data cache
110                         } else if ( isNode ) {
111                                 delete cache[ id ];
112
113                         // Remove all fields from the object
114                         } else {
115                                 for ( var n in elem ) {
116                                         delete elem[ n ];
117                                 }
118                         }
119                 }
120         },
121
122         // A method for determining if a DOM node can handle the data expando
123         acceptData: function( elem ) {
124                 if ( elem.nodeName ) {
125                         var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
126
127                         if ( match ) {
128                                 return !(match === true || elem.getAttribute("classid") !== match);
129                         }
130                 }
131
132                 return true;
133         }
134 });
135
136 jQuery.fn.extend({
137         data: function( key, value ) {
138                 if ( typeof key === "undefined" ) {
139                         return this.length ? jQuery.data( this[0] ) : null;
140
141                 } else if ( typeof key === "object" ) {
142                         return this.each(function() {
143                                 jQuery.data( this, key );
144                         });
145                 }
146
147                 var parts = key.split(".");
148                 parts[1] = parts[1] ? "." + parts[1] : "";
149
150                 if ( value === undefined ) {
151                         var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
152
153                         // Try to fetch any internally stored data first
154                         if ( data === undefined && this.length ) {
155                                 data = jQuery.data( this[0], key );
156
157                                 // If nothing was found internally, try to fetch any
158                                 // data from the HTML5 data-* attribute
159                                 if ( data === undefined && this[0].nodeType === 1 ) {
160                                         data = this[0].getAttribute( "data-" + key );
161
162                                         if ( typeof data === "string" ) {
163                                                 try {
164                                                         data = data === "true" ? true :
165                                                                 data === "false" ? false :
166                                                                 data === "null" ? null :
167                                                                 !jQuery.isNaN( data ) ? parseFloat( data ) :
168                                                                 rbrace.test( data ) ? jQuery.parseJSON( data ) :
169                                                                 data;
170                                                 } catch( e ) {}
171
172                                         } else {
173                                                 data = undefined;
174                                         }
175                                 }
176                         }
177
178                         return data === undefined && parts[1] ?
179                                 this.data( parts[0] ) :
180                                 data;
181
182                 } else {
183                         return this.each(function() {
184                                 var $this = jQuery( this ), args = [ parts[0], value ];
185
186                                 $this.triggerHandler( "setData" + parts[1] + "!", args );
187                                 jQuery.data( this, key, value );
188                                 $this.triggerHandler( "changeData" + parts[1] + "!", args );
189                         });
190                 }
191         },
192
193         removeData: function( key ) {
194                 return this.each(function() {
195                         jQuery.removeData( this, key );
196                 });
197         }
198 });
199
200 })( jQuery );