diff options
author | Oleg Gaidarenko <markelog@gmail.com> | 2015-12-22 16:41:49 +0300 |
---|---|---|
committer | Oleg Gaidarenko <markelog@gmail.com> | 2015-12-22 16:41:49 +0300 |
commit | 59fa7924c7b270f8a0983df6c9819cb1267e478a (patch) | |
tree | 111f2b5ca490d83698ca5484219c135793209511 | |
parent | 4e0c67d6df9b5b909a3973633dfb725b3ba165cc (diff) | |
download | jquery-59fa7924c7b270f8a0983df6c9819cb1267e478a.tar.gz jquery-59fa7924c7b270f8a0983df6c9819cb1267e478a.zip |
Revert "Data: always camelCase keys in .data()"
This reverts commit 0204c3089e7beee0306594605cc64d1e050ecd07.
-rw-r--r-- | src/data.js | 101 | ||||
-rw-r--r-- | test/unit/data.js | 226 |
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 ) { |