Make .data(Object) extend the existing data object. Fixes #6692.
[jquery.git] / src / data.js
1 (function( jQuery ) {
2
3 var windowData = {},
4         rbrace = /^(?:\{.*\}|\[.*\])$/,
5         rdigit = /\d/;
6
7 jQuery.extend({
8         cache: {},
9
10         // Please use with caution
11         uuid: 0,
12
13         // Unique for each copy of jQuery on the page   
14         expando: "jQuery" + jQuery.now(),
15
16         // The following elements throw uncatchable exceptions if you
17         // attempt to add expando properties to them.
18         noData: {
19                 "embed": true,
20                 "object": true,
21                 "applet": true
22         },
23
24         data: function( elem, name, data ) {
25                 if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
26                         return;
27                 }
28
29                 elem = elem == window ?
30                         windowData :
31                         elem;
32
33                 var id = elem[ jQuery.expando ], cache = jQuery.cache, thisCache,
34                         isNode = elem.nodeType,
35                         store;
36
37                 if ( !id && typeof name === "string" && data === undefined ) {
38                         return;
39                 }
40
41                 // Get the data from the object directly
42                 if ( !isNode ) {
43                         cache = elem;
44                         id = jQuery.expando;
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                                 store = jQuery.extend(cache[ id ], name);
59                                 cache[ id ] = function() {
60                                         return store;
61                                 };
62                         }
63
64                 } else if ( !cache[ id ] ) {
65                         if ( isNode ) {
66                                 cache[ id ] = {};
67
68                         } else {
69                                 store = {};
70                                 cache[ id ] = function() {
71                                         return store;
72                                 };
73                         }
74                         
75                 }
76
77                 thisCache = isNode ? cache[ id ] : cache[ id ]();
78
79                 // Prevent overriding the named cache with undefined values
80                 if ( data !== undefined ) {
81                         thisCache[ name ] = data;
82                 }
83
84                 return typeof name === "string" ? thisCache[ name ] : thisCache;
85         },
86
87         removeData: function( elem, name ) {
88                 if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
89                         return;
90                 }
91
92                 elem = elem == window ?
93                         windowData :
94                         elem;
95
96                 var isNode = elem.nodeType,
97                         id = elem[ jQuery.expando ], cache = jQuery.cache;
98                 if ( id && !isNode ) {
99                         id = id();
100                 }
101                 var thisCache = cache[ id ];
102
103                 // If we want to remove a specific section of the element's data
104                 if ( name ) {
105                         if ( thisCache ) {
106                                 // Remove the section of cache data
107                                 delete thisCache[ name ];
108
109                                 // If we've removed all the data, remove the element's cache
110                                 if ( jQuery.isEmptyObject(thisCache) ) {
111                                         jQuery.removeData( elem );
112                                 }
113                         }
114
115                 // Otherwise, we want to remove all of the element's data
116                 } else {
117                         if ( jQuery.support.deleteExpando || !isNode ) {
118                                 delete elem[ jQuery.expando ];
119
120                         } else if ( elem.removeAttribute ) {
121                                 elem.removeAttribute( jQuery.expando );
122                         }
123
124                         // Completely remove the data cache
125                         if ( isNode ) {
126                                 delete cache[ id ];
127                         }
128                 }
129         }
130 });
131
132 jQuery.fn.extend({
133         data: function( key, value ) {
134                 if ( typeof key === "undefined" ) {
135                         return this.length ? jQuery.data( this[0] ) : null;
136
137                 } else if ( typeof key === "object" ) {
138                         return this.each(function() {
139                                 jQuery.data( this, key );
140                         });
141                 }
142
143                 var parts = key.split(".");
144                 parts[1] = parts[1] ? "." + parts[1] : "";
145
146                 if ( value === undefined ) {
147                         var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
148
149                         // Try to fetch any internally stored data first
150                         if ( data === undefined && this.length ) {
151                                 data = jQuery.data( this[0], key );
152
153                                 // If nothing was found internally, try to fetch any
154                                 // data from the HTML5 data-* attribute
155                                 if ( data === undefined && this[0].nodeType === 1 ) {
156                                         data = this[0].getAttribute( "data-" + key );
157
158                                         if ( typeof data === "string" ) {
159                                                 try {
160                                                         data = data === "true" ? true :
161                                                                 data === "false" ? false :
162                                                                 data === "null" ? null :
163                                                                 rdigit.test( data ) && !isNaN( data ) ? parseFloat( data ) :
164                                                                 rbrace.test( data ) ? jQuery.parseJSON( data ) :
165                                                                 data;
166                                                 } catch( e ) {}
167
168                                         } else {
169                                                 data = undefined;
170                                         }
171                                 }
172                         }
173
174                         return data === undefined && parts[1] ?
175                                 this.data( parts[0] ) :
176                                 data;
177
178                 } else {
179                         return this.each(function() {
180                                 var $this = jQuery( this ), args = [ parts[0], value ];
181
182                                 $this.triggerHandler( "setData" + parts[1] + "!", args );
183                                 jQuery.data( this, key, value );
184                                 $this.triggerHandler( "changeData" + parts[1] + "!", args );
185                         });
186                 }
187         },
188
189         removeData: function( key ) {
190                 return this.each(function() {
191                         jQuery.removeData( this, key );
192                 });
193         }
194 });
195
196 })( jQuery );