Tests: Add custom attribute getter tests to the selector module
[jquery.git] / src / data / Data.js
blob25c8c64aae0eab2cf3718afc91e060423e77dea9
1 import { jQuery } from "../core.js";
2 import { camelCase } from "../core/camelCase.js";
3 import { rnothtmlwhite } from "../var/rnothtmlwhite.js";
4 import { acceptData } from "./var/acceptData.js";
6 export function Data() {
7         this.expando = jQuery.expando + Data.uid++;
10 Data.uid = 1;
12 Data.prototype = {
14         cache: function( owner ) {
16                 // Check if the owner object already has a cache
17                 var value = owner[ this.expando ];
19                 // If not, create one
20                 if ( !value ) {
21                         value = Object.create( null );
23                         // We can accept data for non-element nodes in modern browsers,
24                         // but we should not, see trac-8335.
25                         // Always return an empty object.
26                         if ( acceptData( owner ) ) {
28                                 // If it is a node unlikely to be stringify-ed or looped over
29                                 // use plain assignment
30                                 if ( owner.nodeType ) {
31                                         owner[ this.expando ] = value;
33                                 // Otherwise secure it in a non-enumerable property
34                                 // configurable must be true to allow the property to be
35                                 // deleted when data is removed
36                                 } else {
37                                         Object.defineProperty( owner, this.expando, {
38                                                 value: value,
39                                                 configurable: true
40                                         } );
41                                 }
42                         }
43                 }
45                 return value;
46         },
47         set: function( owner, data, value ) {
48                 var prop,
49                         cache = this.cache( owner );
51                 // Handle: [ owner, key, value ] args
52                 // Always use camelCase key (gh-2257)
53                 if ( typeof data === "string" ) {
54                         cache[ camelCase( data ) ] = value;
56                 // Handle: [ owner, { properties } ] args
57                 } else {
59                         // Copy the properties one-by-one to the cache object
60                         for ( prop in data ) {
61                                 cache[ camelCase( prop ) ] = data[ prop ];
62                         }
63                 }
64                 return value;
65         },
66         get: function( owner, key ) {
67                 return key === undefined ?
68                         this.cache( owner ) :
70                         // Always use camelCase key (gh-2257)
71                         owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];
72         },
73         access: function( owner, key, value ) {
75                 // In cases where either:
76                 //
77                 //   1. No key was specified
78                 //   2. A string key was specified, but no value provided
79                 //
80                 // Take the "read" path and allow the get method to determine
81                 // which value to return, respectively either:
82                 //
83                 //   1. The entire cache object
84                 //   2. The data stored at the key
85                 //
86                 if ( key === undefined ||
87                                 ( ( key && typeof key === "string" ) && value === undefined ) ) {
89                         return this.get( owner, key );
90                 }
92                 // When the key is not a string, or both a key and value
93                 // are specified, set or extend (existing objects) with either:
94                 //
95                 //   1. An object of properties
96                 //   2. A key and value
97                 //
98                 this.set( owner, key, value );
100                 // Since the "set" path can have two possible entry points
101                 // return the expected data based on which path was taken[*]
102                 return value !== undefined ? value : key;
103         },
104         remove: function( owner, key ) {
105                 var i,
106                         cache = owner[ this.expando ];
108                 if ( cache === undefined ) {
109                         return;
110                 }
112                 if ( key !== undefined ) {
114                         // Support array or space separated string of keys
115                         if ( Array.isArray( key ) ) {
117                                 // If key is an array of keys...
118                                 // We always set camelCase keys, so remove that.
119                                 key = key.map( camelCase );
120                         } else {
121                                 key = camelCase( key );
123                                 // If a key with the spaces exists, use it.
124                                 // Otherwise, create an array by matching non-whitespace
125                                 key = key in cache ?
126                                         [ key ] :
127                                         ( key.match( rnothtmlwhite ) || [] );
128                         }
130                         i = key.length;
132                         while ( i-- ) {
133                                 delete cache[ key[ i ] ];
134                         }
135                 }
137                 // Remove the expando if there's no more data
138                 if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
140                         // Support: Chrome <=35 - 45+
141                         // Webkit & Blink performance suffers when deleting properties
142                         // from DOM nodes, so set to undefined instead
143                         // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
144                         if ( owner.nodeType ) {
145                                 owner[ this.expando ] = undefined;
146                         } else {
147                                 delete owner[ this.expando ];
148                         }
149                 }
150         },
151         hasData: function( owner ) {
152                 var cache = owner[ this.expando ];
153                 return cache !== undefined && !jQuery.isEmptyObject( cache );
154         }