1
|
define([
|
2
|
"../core",
|
3
|
"../var/rnotwhite",
|
4
|
"./accepts"
|
5
|
], function( jQuery, rnotwhite ) {
|
6
|
|
7
|
function Data() {
|
8
|
// Support: Android<4,
|
9
|
// Old WebKit does not have Object.preventExtensions/freeze method,
|
10
|
// return new empty object instead with no [[set]] accessor
|
11
|
Object.defineProperty( this.cache = {}, 0, {
|
12
|
get: function() {
|
13
|
return {};
|
14
|
}
|
15
|
});
|
16
|
|
17
|
this.expando = jQuery.expando + Data.uid++;
|
18
|
}
|
19
|
|
20
|
Data.uid = 1;
|
21
|
Data.accepts = jQuery.acceptData;
|
22
|
|
23
|
Data.prototype = {
|
24
|
key: function( owner ) {
|
25
|
// We can accept data for non-element nodes in modern browsers,
|
26
|
// but we should not, see #8335.
|
27
|
// Always return the key for a frozen object.
|
28
|
if ( !Data.accepts( owner ) ) {
|
29
|
return 0;
|
30
|
}
|
31
|
|
32
|
var descriptor = {},
|
33
|
// Check if the owner object already has a cache key
|
34
|
unlock = owner[ this.expando ];
|
35
|
|
36
|
// If not, create one
|
37
|
if ( !unlock ) {
|
38
|
unlock = Data.uid++;
|
39
|
|
40
|
// Secure it in a non-enumerable, non-writable property
|
41
|
try {
|
42
|
descriptor[ this.expando ] = { value: unlock };
|
43
|
Object.defineProperties( owner, descriptor );
|
44
|
|
45
|
// Support: Android<4
|
46
|
// Fallback to a less secure definition
|
47
|
} catch ( e ) {
|
48
|
descriptor[ this.expando ] = unlock;
|
49
|
jQuery.extend( owner, descriptor );
|
50
|
}
|
51
|
}
|
52
|
|
53
|
// Ensure the cache object
|
54
|
if ( !this.cache[ unlock ] ) {
|
55
|
this.cache[ unlock ] = {};
|
56
|
}
|
57
|
|
58
|
return unlock;
|
59
|
},
|
60
|
set: function( owner, data, value ) {
|
61
|
var prop,
|
62
|
// There may be an unlock assigned to this node,
|
63
|
// if there is no entry for this "owner", create one inline
|
64
|
// and set the unlock as though an owner entry had always existed
|
65
|
unlock = this.key( owner ),
|
66
|
cache = this.cache[ unlock ];
|
67
|
|
68
|
// Handle: [ owner, key, value ] args
|
69
|
if ( typeof data === "string" ) {
|
70
|
cache[ data ] = value;
|
71
|
|
72
|
// Handle: [ owner, { properties } ] args
|
73
|
} else {
|
74
|
// Fresh assignments by object are shallow copied
|
75
|
if ( jQuery.isEmptyObject( cache ) ) {
|
76
|
jQuery.extend( this.cache[ unlock ], data );
|
77
|
// Otherwise, copy the properties one-by-one to the cache object
|
78
|
} else {
|
79
|
for ( prop in data ) {
|
80
|
cache[ prop ] = data[ prop ];
|
81
|
}
|
82
|
}
|
83
|
}
|
84
|
return cache;
|
85
|
},
|
86
|
get: function( owner, key ) {
|
87
|
// Either a valid cache is found, or will be created.
|
88
|
// New caches will be created and the unlock returned,
|
89
|
// allowing direct access to the newly created
|
90
|
// empty data object. A valid owner object must be provided.
|
91
|
var cache = this.cache[ this.key( owner ) ];
|
92
|
|
93
|
return key === undefined ?
|
94
|
cache : cache[ key ];
|
95
|
},
|
96
|
access: function( owner, key, value ) {
|
97
|
var stored;
|
98
|
// In cases where either:
|
99
|
//
|
100
|
// 1. No key was specified
|
101
|
// 2. A string key was specified, but no value provided
|
102
|
//
|
103
|
// Take the "read" path and allow the get method to determine
|
104
|
// which value to return, respectively either:
|
105
|
//
|
106
|
// 1. The entire cache object
|
107
|
// 2. The data stored at the key
|
108
|
//
|
109
|
if ( key === undefined ||
|
110
|
((key && typeof key === "string") && value === undefined) ) {
|
111
|
|
112
|
stored = this.get( owner, key );
|
113
|
|
114
|
return stored !== undefined ?
|
115
|
stored : this.get( owner, jQuery.camelCase(key) );
|
116
|
}
|
117
|
|
118
|
// [*]When the key is not a string, or both a key and value
|
119
|
// are specified, set or extend (existing objects) with either:
|
120
|
//
|
121
|
// 1. An object of properties
|
122
|
// 2. A key and value
|
123
|
//
|
124
|
this.set( owner, key, value );
|
125
|
|
126
|
// Since the "set" path can have two possible entry points
|
127
|
// return the expected data based on which path was taken[*]
|
128
|
return value !== undefined ? value : key;
|
129
|
},
|
130
|
remove: function( owner, key ) {
|
131
|
var i, name, camel,
|
132
|
unlock = this.key( owner ),
|
133
|
cache = this.cache[ unlock ];
|
134
|
|
135
|
if ( key === undefined ) {
|
136
|
this.cache[ unlock ] = {};
|
137
|
|
138
|
} else {
|
139
|
// Support array or space separated string of keys
|
140
|
if ( jQuery.isArray( key ) ) {
|
141
|
// If "name" is an array of keys...
|
142
|
// When data is initially created, via ("key", "val") signature,
|
143
|
// keys will be converted to camelCase.
|
144
|
// Since there is no way to tell _how_ a key was added, remove
|
145
|
// both plain key and camelCase key. #12786
|
146
|
// This will only penalize the array argument path.
|
147
|
name = key.concat( key.map( jQuery.camelCase ) );
|
148
|
} else {
|
149
|
camel = jQuery.camelCase( key );
|
150
|
// Try the string as a key before any manipulation
|
151
|
if ( key in cache ) {
|
152
|
name = [ key, camel ];
|
153
|
} else {
|
154
|
// If a key with the spaces exists, use it.
|
155
|
// Otherwise, create an array by matching non-whitespace
|
156
|
name = camel;
|
157
|
name = name in cache ?
|
158
|
[ name ] : ( name.match( rnotwhite ) || [] );
|
159
|
}
|
160
|
}
|
161
|
|
162
|
i = name.length;
|
163
|
while ( i-- ) {
|
164
|
delete cache[ name[ i ] ];
|
165
|
}
|
166
|
}
|
167
|
},
|
168
|
hasData: function( owner ) {
|
169
|
return !jQuery.isEmptyObject(
|
170
|
this.cache[ owner[ this.expando ] ] || {}
|
171
|
);
|
172
|
},
|
173
|
discard: function( owner ) {
|
174
|
if ( owner[ this.expando ] ) {
|
175
|
delete this.cache[ owner[ this.expando ] ];
|
176
|
}
|
177
|
}
|
178
|
};
|
179
|
|
180
|
return Data;
|
181
|
});
|