Handle some additional data- number edge cases.
[jquery.git] / src / data.js
1 (function( jQuery ) {
2
3 var windowData = {},
4         rnum = /^-?\d+(?:\.\d+)?(?:E\d+)?$/,
5         rbrace = /^(?:{.*}|\[.*\])$/;
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(true, {}, name);
56                         } else {
57                                 store = jQuery.extend(true, {}, name);
58                                 cache[ id ] = function() {
59                                         return store;
60                                 };
61                         }
62
63                 } else if ( !cache[ id ] ) {
64                         if ( isNode ) {
65                                 cache[ id ] = {};
66                         } else {
67                                 store = {};
68                                 cache[ id ] = function() {
69                                         return store;
70                                 };
71                         }
72                         
73                 }
74
75                 thisCache = isNode ? cache[ id ] : cache[ id ]();
76
77                 // Prevent overriding the named cache with undefined values
78                 if ( data !== undefined ) {
79                         thisCache[ name ] = data;
80                 }
81
82                 return typeof name === "string" ? thisCache[ name ] : thisCache;
83         },
84
85         removeData: function( elem, name ) {
86                 if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
87                         return;
88                 }
89
90                 elem = elem == window ?
91                         windowData :
92                         elem;
93
94                 var isNode = elem.nodeType,
95                         id = elem[ jQuery.expando ], cache = jQuery.cache;
96                 if ( id && !isNode ) {
97                         id = id();
98                 }
99                 var thisCache = cache[ id ];
100
101                 // If we want to remove a specific section of the element's data
102                 if ( name ) {
103                         if ( thisCache ) {
104                                 // Remove the section of cache data
105                                 delete thisCache[ name ];
106
107                                 // If we've removed all the data, remove the element's cache
108                                 if ( jQuery.isEmptyObject(thisCache) ) {
109                                         jQuery.removeData( elem );
110                                 }
111                         }
112
113                 // Otherwise, we want to remove all of the element's data
114                 } else {
115                         if ( jQuery.support.deleteExpando || !isNode ) {
116                                 delete elem[ jQuery.expando ];
117
118                         } else if ( elem.removeAttribute ) {
119                                 elem.removeAttribute( jQuery.expando );
120                         }
121
122                         // Completely remove the data cache
123                         if ( isNode ) {
124                                 delete cache[ id ];
125                         }
126                 }
127         }
128 });
129
130 jQuery.fn.extend({
131         data: function( key, value ) {
132                 if ( typeof key === "undefined" && this.length ) {
133                         return jQuery.data( this[0] );
134
135                 } else if ( typeof key === "object" ) {
136                         return this.each(function() {
137                                 jQuery.data( this, key );
138                         });
139                 }
140
141                 var parts = key.split(".");
142                 parts[1] = parts[1] ? "." + parts[1] : "";
143
144                 if ( value === undefined ) {
145                         var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
146
147                         // Try to fetch any internally stored data first
148                         if ( data === undefined && this.length ) {
149                                 data = jQuery.data( this[0], key );
150
151                                 // If nothing was found internally, try to fetch any
152                                 // data from the HTML5 data-* attribute
153                                 if ( data === undefined && this[0].nodeType === 1 ) {
154                                         data = this[0].getAttribute( "data-" + key );
155
156                                         if ( typeof data === "string" ) {
157                                                 try {
158                                                         data = data === "true" ? true :
159                                                                 data === "false" ? false :
160                                                                 data === "null" ? null :
161                                                                 rnum.test( data ) ? parseFloat( data ) :
162                                                                 rbrace.test( data ) ? jQuery.parseJSON( data ) :
163                                                                 data;
164                                                 } catch( e ) {}
165
166                                         } else {
167                                                 data = undefined;
168                                         }
169                                 }
170                         }
171
172                         return data === undefined && parts[1] ?
173                                 this.data( parts[0] ) :
174                                 data;
175
176                 } else {
177                         return this.each(function() {
178                                 var $this = jQuery( this ), args = [ parts[0], value ];
179
180                                 $this.triggerHandler( "setData" + parts[1] + "!", args );
181                                 jQuery.data( this, key, value );
182                                 $this.triggerHandler( "changeData" + parts[1] + "!", args );
183                         });
184                 }
185         },
186
187         removeData: function( key ) {
188                 return this.each(function() {
189                         jQuery.removeData( this, key );
190                 });
191         }
192 });
193
194 })( jQuery );