aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Gaidarenko <markelog@gmail.com>2015-12-22 16:41:49 +0300
committerOleg Gaidarenko <markelog@gmail.com>2015-12-22 16:41:49 +0300
commit59fa7924c7b270f8a0983df6c9819cb1267e478a (patch)
tree111f2b5ca490d83698ca5484219c135793209511
parent4e0c67d6df9b5b909a3973633dfb725b3ba165cc (diff)
downloadjquery-59fa7924c7b270f8a0983df6c9819cb1267e478a.tar.gz
jquery-59fa7924c7b270f8a0983df6c9819cb1267e478a.zip
Revert "Data: always camelCase keys in .data()"
This reverts commit 0204c3089e7beee0306594605cc64d1e050ecd07.
-rw-r--r--src/data.js101
-rw-r--r--test/unit/data.js226
2 files changed, 112 insertions, 215 deletions
diff --git a/src/data.js b/src/data.js
index 223c2ccc7..d05def4bf 100644
--- a/src/data.js
+++ b/src/data.js
@@ -43,14 +43,14 @@ function dataAttr( elem, key, data ) {
// checks a cache object for emptiness
function isEmptyDataObject( obj ) {
- var key;
- for ( key in obj ) {
+ var name;
+ for ( name in obj ) {
// if the public data object is empty, the private is still empty
- if ( key === "data" && jQuery.isEmptyObject( obj[ key ] ) ) {
+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
continue;
}
- if ( key !== "toJSON" ) {
+ if ( name !== "toJSON" ) {
return false;
}
}
@@ -58,12 +58,12 @@ function isEmptyDataObject( obj ) {
return true;
}
-function internalData( elem, key, data, pvt /* Internal Use Only */ ) {
+function internalData( elem, name, data, pvt /* Internal Use Only */ ) {
if ( !acceptData( elem ) ) {
return;
}
- var thisCache, prop,
+ var ret, thisCache,
internalKey = jQuery.expando,
// We have to handle DOM nodes and JS objects differently because IE6-7
@@ -80,8 +80,8 @@ function internalData( elem, key, data, pvt /* Internal Use Only */ ) {
// Avoid doing any more work than we need to when trying to get data on an
// object that has no data at all
- if ( ( !id || !cache[ id ] || ( !pvt && !cache[ id ].data ) ) &&
- data === undefined && typeof key === "string" ) {
+ if ( (!id || !cache[id] || (!pvt && !cache[id].data)) &&
+ data === undefined && typeof name === "string" ) {
return;
}
@@ -103,6 +103,16 @@ function internalData( elem, key, data, pvt /* Internal Use Only */ ) {
cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
}
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
+ // shallow copied over onto the existing cache
+ if ( typeof name === "object" || typeof name === "function" ) {
+ if ( pvt ) {
+ cache[ id ] = jQuery.extend( cache[ id ], name );
+ } else {
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+ }
+ }
+
thisCache = cache[ id ];
// jQuery data() is stored in a separate object inside the object's internal data
@@ -116,30 +126,31 @@ function internalData( elem, key, data, pvt /* Internal Use Only */ ) {
thisCache = thisCache.data;
}
- // An object can be passed to jQuery.data instead of a key/value pair; this gets
- // shallow copied over onto the existing cache
- if ( typeof key === "object" || typeof key === "function" ) {
- for ( prop in key ) {
- thisCache[ jQuery.camelCase( prop ) ] = key[ prop ];
- }
-
- // Stop here, ignore other arguments
- return thisCache;
- }
-
if ( data !== undefined ) {
- return thisCache[ jQuery.camelCase( key ) ] = data;
+ thisCache[ jQuery.camelCase( name ) ] = data;
}
- // We always set camelCased properties (gh-2257)
- return typeof key === "string" ?
- thisCache[ jQuery.camelCase( key ) ] :
+ // Check for both converted-to-camel and non-converted data property names
+ // If a data property was specified
+ if ( typeof name === "string" ) {
+
+ // First Try to find as-is property data
+ ret = thisCache[ name ];
+
+ // Test for null|undefined property data
+ if ( ret == null ) {
- // Return the whole cache if no key was specified
- thisCache;
+ // Try to find the camelCased property
+ ret = thisCache[ jQuery.camelCase( name ) ];
+ }
+ } else {
+ ret = thisCache;
+ }
+
+ return ret;
}
-function internalRemoveData( elem, key, pvt ) {
+function internalRemoveData( elem, name, pvt ) {
if ( !acceptData( elem ) ) {
return;
}
@@ -157,29 +168,41 @@ function internalRemoveData( elem, key, pvt ) {
return;
}
- if ( key ) {
+ if ( name ) {
thisCache = pvt ? cache[ id ] : cache[ id ].data;
if ( thisCache ) {
- // Support array or space separated string keys for data keys
- if ( jQuery.isArray( key ) ) {
+ // Support array or space separated string names for data keys
+ if ( !jQuery.isArray( name ) ) {
- // If "key" is an array of keys...
- // We always use camelCased keys (gh-2257)
- key = jQuery.map( key, jQuery.camelCase );
- } else {
+ // try the string as a key before any manipulation
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
- // split the camel cased version by spaces
- // unless a key with the spaces exists
- key = jQuery.camelCase( key );
- key = key in thisCache ? [ key ] : key.split( " " );
+ // split the camel cased version by spaces unless a key with the spaces exists
+ name = jQuery.camelCase( name );
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+ name = name.split(" ");
+ }
+ }
+ } else {
+ // 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 = name.concat( jQuery.map( name, jQuery.camelCase ) );
}
- i = key.length;
+ i = name.length;
while ( i-- ) {
- delete thisCache[ key[ i ] ];
+ delete thisCache[ name[i] ];
}
// If there is no data left in the cache, we want to continue
diff --git a/test/unit/data.js b/test/unit/data.js
index b78b43090..91002b8a0 100644
--- a/test/unit/data.js
+++ b/test/unit/data.js
@@ -812,76 +812,6 @@ QUnit.test( "jQuery.data should not miss data with preset hyphenated property na
} );
} );
-QUnit.test( ".data should not miss attr() set data-* with hyphenated property names", function( assert ) {
- assert.expect( 2 );
-
- var a, b;
-
- a = jQuery( "<div/>" ).appendTo( "#qunit-fixture" );
-
- a.attr( "data-long-param", "test" );
- a.data( "long-param", { a: 2 } );
-
- assert.deepEqual(
- a.data( "long-param" ), { a: 2 }, "data with property long-param was found, 1"
- );
-
- b = jQuery( "<div/>" ).appendTo( "#qunit-fixture" );
-
- b.attr( "data-long-param", "test" );
- b.data( "long-param" );
- b.data( "long-param", { a: 2 } );
-
- assert.deepEqual(
- b.data( "long-param" ), { a: 2 }, "data with property long-param was found, 2"
- );
-} );
-
-QUnit.test( ".data always sets data with the camelCased key (gh-2257)", function( assert ) {
- assert.expect( 36 );
-
- var div = jQuery( "<div>" ).appendTo( "#qunit-fixture" ),
- datas = {
- "non-empty": "a string",
- "empty-string": "",
- "one-value": 1,
- "zero-value": 0,
- "an-array": [],
- "an-object": {},
- "bool-true": true,
- "bool-false": false,
-
- // JSHint enforces double quotes,
- // but JSON strings need double quotes to parse
- // so we need escaped double quotes here
- "some-json": "{ \"foo\": \"bar\" }"
- };
-
- jQuery.each( datas, function( key, val ) {
- div.data( key, val );
- var allData = div.data();
- assert.equal(
- allData[ key ], undefined, ".data(key, val) does not store with hyphenated keys"
- );
- assert.equal(
- allData[ jQuery.camelCase( key ) ], val, ".data(key, val) stores the camelCased key"
- );
- } );
-
- div.removeData();
-
- div.data( datas );
- jQuery.each( datas, function( key, val ) {
- var allData = div.data();
- assert.equal(
- allData[ key ], undefined, ".data(object) does not store with hyphenated keys"
- );
- assert.equal(
- allData[ jQuery.camelCase( key ) ], val, ".data(object) stores the camelCased key"
- );
- } );
-} );
-
QUnit.test(
".data supports interoperable hyphenated/camelCase get/set of" +
" properties with arbitrary non-null|NaN|undefined values",
@@ -921,125 +851,69 @@ QUnit.test(
}
);
-QUnit.test(
- "jQuery.data supports interoperable removal of hyphenated/camelCase properties",
- function( assert ) {
- var div = jQuery( "<div/>", { id: "hyphened" } ).appendTo( "#qunit-fixture" ),
- datas = {
- "non-empty": "a string",
- "empty-string": "",
- "one-value": 1,
- "zero-value": 0,
- "an-array": [],
- "an-object": {},
- "bool-true": true,
- "bool-false": false,
-
- // JSHint enforces double quotes,
- // but JSON strings need double quotes to parse
- // so we need escaped double quotes here
- "some-json": "{ \"foo\": \"bar\" }"
- };
-
- assert.expect( 27 );
-
- jQuery.each( datas, function( key, val ) {
- div.data( key, val );
-
- assert.deepEqual(
- div.data( key ), val, "get: " + key
- );
- assert.deepEqual(
- div.data( jQuery.camelCase( key ) ), val, "get: " + jQuery.camelCase( key )
- );
-
- div.removeData( key );
-
- assert.equal(
- div.data( key ), undefined, "get: " + key
- );
-
- } );
- }
-);
-
-QUnit.test(
- ".data supports interoperable removal of properties SET TWICE #13850",
- function( assert ) {
- var div = jQuery( "<div>" ).appendTo( "#qunit-fixture" ),
- datas = {
- "non-empty": "a string",
- "empty-string": "",
- "one-value": 1,
- "zero-value": 0,
- "an-array": [],
- "an-object": {},
- "bool-true": true,
- "bool-false": false,
-
- // JSHint enforces double quotes,
- // but JSON strings need double quotes to parse
- // so we need escaped double quotes here
- "some-json": "{ \"foo\": \"bar\" }"
- };
- assert.expect( 9 );
+test("jQuery.data supports interoperable hyphenated/camelCase get/set of properties with arbitrary non-null|NaN|undefined values", function() {
- jQuery.each( datas, function( key, val ) {
- div.data( key, val );
- div.data( key, val );
+ var div = jQuery("<div/>", { id: "hyphened" }).appendTo("#qunit-fixture"),
+ datas = {
+ "non-empty": "a string",
+ "empty-string": "",
+ "one-value": 1,
+ "zero-value": 0,
+ "an-array": [],
+ "an-object": {},
+ "bool-true": true,
+ "bool-false": false,
+ // JSHint enforces double quotes,
+ // but JSON strings need double quotes to parse
+ // so we need escaped double quotes here
+ "some-json": "{ \"foo\": \"bar\" }",
+ "num-1-middle": true,
+ "num-end-2": true,
+ "2-num-start": true
+ };
- div.removeData( key );
+ expect( 24 );
- assert.equal(
- div.data( key ), undefined, "removal: " + key
- );
- } );
- }
-);
-
-QUnit.test(
- ".removeData supports removal of hyphenated properties via array (#12786, gh-2257)",
- function( assert ) {
- assert.expect( 4 );
+ jQuery.each( datas, function( key, val ) {
+ div.data( key, val );
- var div, plain, compare;
+ deepEqual( div.data( key ), val, "get: " + key );
+ deepEqual( div.data( jQuery.camelCase( key ) ), val, "get: " + jQuery.camelCase( key ) );
+ });
+});
- div = jQuery( "<div>" ).appendTo( "#qunit-fixture" );
- plain = jQuery( {} );
+test( ".removeData supports removal of hyphenated properties via array (#12786)", function() {
+ expect( 4 );
- // Properties should always be camelCased
- compare = {
+ var div, plain, compare;
- // From batch assignment .data({ "a-a": 1 })
- "aA": 1,
+ div = jQuery("<div>").appendTo("#qunit-fixture");
+ plain = jQuery({});
- // From property, value assignment .data( "b-b", 1 )
- "bB": 1
- };
+ // When data is batch assigned (via plain object), the properties
+ // are not camel cased as they are with (property, value) calls
+ compare = {
+ // From batch assignment .data({ "a-a": 1 })
+ "a-a": 1,
+ // From property, value assignment .data( "b-b", 1 )
+ "bB": 1
+ };
- // Mixed assignment
- div.data( { "a-a": 1 } ).data( "b-b", 1 );
- plain.data( { "a-a": 1 } ).data( "b-b", 1 );
+ // Mixed assignment
+ div.data({ "a-a": 1 }).data( "b-b", 1 );
+ plain.data({ "a-a": 1 }).data( "b-b", 1 );
- assert.deepEqual(
- div.data(), compare, "Data appears as expected. (div)"
- );
- assert.deepEqual(
- plain.data(), compare, "Data appears as expected. (plain)"
- );
+ deepEqual( div.data(), compare, "Data appears as expected. (div)" );
+ deepEqual( plain.data(), compare, "Data appears as expected. (plain)" );
- div.removeData( [ "a-a", "b-b" ] );
- plain.removeData( [ "a-a", "b-b" ] );
+ div.removeData([ "a-a", "b-b" ]);
+ plain.removeData([ "a-a", "b-b" ]);
- assert.deepEqual(
- div.data(), {}, "Data is empty. (div)"
- );
- assert.deepEqual(
- plain.data(), {}, "Data is empty. (plain)"
- );
- }
-);
+ // NOTE: Timo's proposal for "propEqual" (or similar) would be nice here
+ deepEqual( div.data(), {}, "Data is empty. (div)" );
+ deepEqual( plain.data(), {}, "Data is empty. (plain)" );
+});
// Test originally by Moschel
QUnit.test( "Triggering the removeData should not throw exceptions. (#10080)", function( assert ) {