Data.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. define( [
  2. "../core",
  3. "../var/rnotwhite",
  4. "./var/acceptData"
  5. ], function( jQuery, rnotwhite, acceptData ) {
  6. function Data() {
  7. this.expando = jQuery.expando + Data.uid++;
  8. }
  9. Data.uid = 1;
  10. Data.prototype = {
  11. register: function( owner, initial ) {
  12. var value = initial || {};
  13. // If it is a node unlikely to be stringify-ed or looped over
  14. // use plain assignment
  15. if ( owner.nodeType ) {
  16. owner[ this.expando ] = value;
  17. // Otherwise secure it in a non-enumerable, non-writable property
  18. // configurability must be true to allow the property to be
  19. // deleted with the delete operator
  20. } else {
  21. Object.defineProperty( owner, this.expando, {
  22. value: value,
  23. writable: true,
  24. configurable: true
  25. } );
  26. }
  27. return owner[ this.expando ];
  28. },
  29. cache: function( owner ) {
  30. // We can accept data for non-element nodes in modern browsers,
  31. // but we should not, see #8335.
  32. // Always return an empty object.
  33. if ( !acceptData( owner ) ) {
  34. return {};
  35. }
  36. // Check if the owner object already has a cache
  37. var value = owner[ this.expando ];
  38. // If not, create one
  39. if ( !value ) {
  40. value = {};
  41. // We can accept data for non-element nodes in modern browsers,
  42. // but we should not, see #8335.
  43. // Always return an empty object.
  44. if ( acceptData( owner ) ) {
  45. // If it is a node unlikely to be stringify-ed or looped over
  46. // use plain assignment
  47. if ( owner.nodeType ) {
  48. owner[ this.expando ] = value;
  49. // Otherwise secure it in a non-enumerable property
  50. // configurable must be true to allow the property to be
  51. // deleted when data is removed
  52. } else {
  53. Object.defineProperty( owner, this.expando, {
  54. value: value,
  55. configurable: true
  56. } );
  57. }
  58. }
  59. }
  60. return value;
  61. },
  62. set: function( owner, data, value ) {
  63. var prop,
  64. cache = this.cache( owner );
  65. // Handle: [ owner, key, value ] args
  66. if ( typeof data === "string" ) {
  67. cache[ data ] = value;
  68. // Handle: [ owner, { properties } ] args
  69. } else {
  70. // Copy the properties one-by-one to the cache object
  71. for ( prop in data ) {
  72. cache[ prop ] = data[ prop ];
  73. }
  74. }
  75. return cache;
  76. },
  77. get: function( owner, key ) {
  78. return key === undefined ?
  79. this.cache( owner ) :
  80. owner[ this.expando ] && owner[ this.expando ][ key ];
  81. },
  82. access: function( owner, key, value ) {
  83. var stored;
  84. // In cases where either:
  85. //
  86. // 1. No key was specified
  87. // 2. A string key was specified, but no value provided
  88. //
  89. // Take the "read" path and allow the get method to determine
  90. // which value to return, respectively either:
  91. //
  92. // 1. The entire cache object
  93. // 2. The data stored at the key
  94. //
  95. if ( key === undefined ||
  96. ( ( key && typeof key === "string" ) && value === undefined ) ) {
  97. stored = this.get( owner, key );
  98. return stored !== undefined ?
  99. stored : this.get( owner, jQuery.camelCase( key ) );
  100. }
  101. // When the key is not a string, or both a key and value
  102. // are specified, set or extend (existing objects) with either:
  103. //
  104. // 1. An object of properties
  105. // 2. A key and value
  106. //
  107. this.set( owner, key, value );
  108. // Since the "set" path can have two possible entry points
  109. // return the expected data based on which path was taken[*]
  110. return value !== undefined ? value : key;
  111. },
  112. remove: function( owner, key ) {
  113. var i, name, camel,
  114. cache = owner[ this.expando ];
  115. if ( cache === undefined ) {
  116. return;
  117. }
  118. if ( key === undefined ) {
  119. this.register( owner );
  120. } else {
  121. // Support array or space separated string of keys
  122. if ( jQuery.isArray( key ) ) {
  123. // If "name" is an array of keys...
  124. // When data is initially created, via ("key", "val") signature,
  125. // keys will be converted to camelCase.
  126. // Since there is no way to tell _how_ a key was added, remove
  127. // both plain key and camelCase key. #12786
  128. // This will only penalize the array argument path.
  129. name = key.concat( key.map( jQuery.camelCase ) );
  130. } else {
  131. camel = jQuery.camelCase( key );
  132. // Try the string as a key before any manipulation
  133. if ( key in cache ) {
  134. name = [ key, camel ];
  135. } else {
  136. // If a key with the spaces exists, use it.
  137. // Otherwise, create an array by matching non-whitespace
  138. name = camel;
  139. name = name in cache ?
  140. [ name ] : ( name.match( rnotwhite ) || [] );
  141. }
  142. }
  143. i = name.length;
  144. while ( i-- ) {
  145. delete cache[ name[ i ] ];
  146. }
  147. }
  148. // Remove the expando if there's no more data
  149. if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
  150. // Support: Chrome <= 35-45+
  151. // Webkit & Blink performance suffers when deleting properties
  152. // from DOM nodes, so set to undefined instead
  153. // https://code.google.com/p/chromium/issues/detail?id=378607
  154. if ( owner.nodeType ) {
  155. owner[ this.expando ] = undefined;
  156. } else {
  157. delete owner[ this.expando ];
  158. }
  159. }
  160. },
  161. hasData: function( owner ) {
  162. var cache = owner[ this.expando ];
  163. return cache !== undefined && !jQuery.isEmptyObject( cache );
  164. }
  165. };
  166. return Data;
  167. } );