Skip to content
Permalink
Browse files

Fix #13494: Fallback defineProperties to jQuery.extend. Close gh-1182.

Android<4 (ancient WebKit) doesn't have full ES5 support.
  • Loading branch information...
gibson042 authored and dmethvin committed Feb 23, 2013
1 parent b55bfb1 commit 85f1985f2444da01054800d6f41c3a6057da2e16
Showing with 28 additions and 36 deletions.
  1. +28 −36 src/data.js
@@ -14,44 +14,36 @@ var data_user, data_priv,
rmultiDash = /([A-Z])/g;

function Data() {
// Data objects. Keys correspond to the
// unlocker that is accessible via "locker" method
this.cache = {};
this.expando = jQuery.expando + Math.random();
}

Data.uid = 1;

Data.prototype = {
locker: function( owner ) {
var ovalueOf,
// Check if the owner object has already been outfitted with a valueOf
// "locker". They "key" is the "Data" constructor itself, which is scoped
// to the IIFE that wraps jQuery. This prevents outside tampering with the
// "valueOf" locker.
unlock = owner.valueOf( Data );

// If no "unlock" string exists, then create a valueOf "locker"
// for storing the unlocker key. Since valueOf normally does not accept any
// arguments, extant calls to valueOf will still behave as expected.
if ( typeof unlock !== "string" ) {
unlock = jQuery.expando + Data.uid++;
ovalueOf = owner.valueOf;

Object.defineProperty( owner, "valueOf", {
value: function( pick ) {
if ( pick === Data ) {
return unlock;
}
return ovalueOf.apply( owner );
}
// By omitting explicit [ enumerable, writable, configurable ]
// they will default to "false"
});
key: function( owner ) {
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++;
descriptor[ this.expando ] = { value: unlock };

// Secure it in a non-enumerable, non-writable property
try {
Object.defineProperties( owner, descriptor );

// Support: Android<4
// Fallback to a less secure definition
} catch ( e ) {
descriptor[ this.expando ] = unlock;
jQuery.extend( owner, descriptor );
}
}

// If private or user data already create a valueOf locker
// then we'll reuse the unlock key, but still need to create
// a cache object for this instance (could be private or user)
// Ensure the cache object
if ( !this.cache[ unlock ] ) {
this.cache[ unlock ] = {};
}
@@ -64,7 +56,7 @@ Data.prototype = {
// 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.locker( owner );
unlock = this.key( owner );
cache = this.cache[ unlock ];

// Handle: [ owner, key, value ] args
@@ -74,7 +66,7 @@ Data.prototype = {
// Handle: [ owner, { properties } ] args
} else {
// [*] In the case where there was actually no "owner" entry and
// this.locker( owner ) was called to create one, there will be
// this.key( owner ) was called to create one, there will be
// a corresponding empty plain object in the cache.
//
// Note, this will kill the reference between
@@ -102,7 +94,7 @@ Data.prototype = {
// New caches will be created and the unlock returned,
// allowing direct access to the newly created
// empty data object.
var cache = this.cache[ this.locker( owner ) ];
var cache = this.cache[ this.key( owner ) ];

return key === undefined ?
cache : cache[ key ];
@@ -138,7 +130,7 @@ Data.prototype = {
},
remove: function( owner, key ) {
var i, l, name,
unlock = this.locker( owner ),
unlock = this.key( owner ),
cache = this.cache[ unlock ];

if ( key === undefined ) {
@@ -178,11 +170,11 @@ Data.prototype = {
},
hasData: function( owner ) {
return !jQuery.isEmptyObject(
this.cache[ this.locker( owner ) ]
this.cache[ this.key( owner ) ]
);
},
discard: function( owner ) {
delete this.cache[ this.locker( owner ) ];
delete this.cache[ this.key( owner ) ];
}
};

0 comments on commit 85f1985

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.