| define([ |
| "../core", |
| "../var/rnotwhite", |
| "./accepts" |
| ], function( jQuery, rnotwhite ) { |
| |
| function Data() { |
| // Support: Android<4, |
| // Old WebKit does not have Object.preventExtensions/freeze method, |
| // return new empty object instead with no [[set]] accessor |
| Object.defineProperty( this.cache = {}, 0, { |
| get: function() { |
| return {}; |
| } |
| }); |
| |
| this.expando = jQuery.expando + Data.uid++; |
| } |
| |
| Data.uid = 1; |
| Data.accepts = jQuery.acceptData; |
| |
| Data.prototype = { |
| key: function( owner ) { |
| // We can accept data for non-element nodes in modern browsers, |
| // but we should not, see #8335. |
| // Always return the key for a frozen object. |
| if ( !Data.accepts( owner ) ) { |
| return 0; |
| } |
| |
| var descriptor = {}, |
| // Check if the owner object already has a cache key |
| unlock = owner[ this.expando ]; |
| |
| // If not, create one |
| if ( !unlock ) { |
| unlock = Data.uid++; |
| |
| // Secure it in a non-enumerable, non-writable property |
| try { |
| descriptor[ this.expando ] = { value: unlock }; |
| Object.defineProperties( owner, descriptor ); |
| |
| // Support: Android<4 |
| // Fallback to a less secure definition |
| } catch ( e ) { |
| descriptor[ this.expando ] = unlock; |
| jQuery.extend( owner, descriptor ); |
| } |
| } |
| |
| // Ensure the cache object |
| if ( !this.cache[ unlock ] ) { |
| this.cache[ unlock ] = {}; |
| } |
| |
| return unlock; |
| }, |
| set: function( owner, data, value ) { |
| var prop, |
| // There may be an unlock assigned to this node, |
| // if there is no entry for this "owner", create one inline |
| // and set the unlock as though an owner entry had always existed |
| unlock = this.key( owner ), |
| cache = this.cache[ unlock ]; |
| |
| // Handle: [ owner, key, value ] args |
| if ( typeof data === "string" ) { |
| cache[ data ] = value; |
| |
| // Handle: [ owner, { properties } ] args |
| } else { |
| // Fresh assignments by object are shallow copied |
| if ( jQuery.isEmptyObject( cache ) ) { |
| jQuery.extend( this.cache[ unlock ], data ); |
| // Otherwise, copy the properties one-by-one to the cache object |
| } else { |
| for ( prop in data ) { |
| cache[ prop ] = data[ prop ]; |
| } |
| } |
| } |
| return cache; |
| }, |
| get: function( owner, key ) { |
| // Either a valid cache is found, or will be created. |
| // New caches will be created and the unlock returned, |
| // allowing direct access to the newly created |
| // empty data object. A valid owner object must be provided. |
| var cache = this.cache[ this.key( owner ) ]; |
| |
| return key === undefined ? |
| cache : cache[ key ]; |
| }, |
| access: function( owner, key, value ) { |
| var stored; |
| // In cases where either: |
| // |
| // 1. No key was specified |
| // 2. A string key was specified, but no value provided |
| // |
| // Take the "read" path and allow the get method to determine |
| // which value to return, respectively either: |
| // |
| // 1. The entire cache object |
| // 2. The data stored at the key |
| // |
| if ( key === undefined || |
| ((key && typeof key === "string") && value === undefined) ) { |
| |
| stored = this.get( owner, key ); |
| |
| return stored !== undefined ? |
| stored : this.get( owner, jQuery.camelCase(key) ); |
| } |
| |
| // [*]When the key is not a string, or both a key and value |
| // are specified, set or extend (existing objects) with either: |
| // |
| // 1. An object of properties |
| // 2. A key and value |
| // |
| this.set( owner, key, value ); |
| |
| // Since the "set" path can have two possible entry points |
| // return the expected data based on which path was taken[*] |
| return value !== undefined ? value : key; |
| }, |
| remove: function( owner, key ) { |
| var i, name, camel, |
| unlock = this.key( owner ), |
| cache = this.cache[ unlock ]; |
| |
| if ( key === undefined ) { |
| this.cache[ unlock ] = {}; |
| |
| } else { |
| // Support array or space separated string of keys |
| if ( jQuery.isArray( key ) ) { |
| // If "name" is an array of keys... |
| // When data is initially created, via ("key", "val") signature, |
| // keys will be converted to camelCase. |
| // Since there is no way to tell _how_ a key was added, remove |
| // both plain key and camelCase key. #12786 |
| // This will only penalize the array argument path. |
| name = key.concat( key.map( jQuery.camelCase ) ); |
| } else { |
| camel = jQuery.camelCase( key ); |
| // Try the string as a key before any manipulation |
| if ( key in cache ) { |
| name = [ key, camel ]; |
| } else { |
| // If a key with the spaces exists, use it. |
| // Otherwise, create an array by matching non-whitespace |
| name = camel; |
| name = name in cache ? |
| [ name ] : ( name.match( rnotwhite ) || [] ); |
| } |
| } |
| |
| i = name.length; |
| while ( i-- ) { |
| delete cache[ name[ i ] ]; |
| } |
| } |
| }, |
| hasData: function( owner ) { |
| return !jQuery.isEmptyObject( |
| this.cache[ owner[ this.expando ] ] || {} |
| ); |
| }, |
| discard: function( owner ) { |
| if ( owner[ this.expando ] ) { |
| delete this.cache[ owner[ this.expando ] ]; |
| } |
| } |
| }; |
| |
| return Data; |
| }); |