Skip to content
Permalink
Browse files

Hide metadata when serializing JS objects using JSON.stringify via a …

…toJSON hack. Fixes #8108.
  • Loading branch information
csnover committed Feb 14, 2011
1 parent 217a991 commit 2ed81708bdacfd4b97b77baef67ad8b75205dd20
Showing with 52 additions and 6 deletions.
  1. +23 −3 src/data.js
  2. +29 −3 test/unit/data.js
@@ -24,7 +24,7 @@ jQuery.extend({
hasData: function( elem ) {
elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];

return !!elem && !jQuery.isEmptyObject(elem);
return !!elem && !isEmptyDataObject( elem );
},

data: function( elem, name, data, pvt /* Internal Use Only */ ) {
@@ -64,6 +64,13 @@ jQuery.extend({

if ( !cache[ id ] ) {
cache[ id ] = {};

// TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
// metadata on plain JS objects when the object is serialized using
// JSON.stringify
cache[ id ].toJSON = function () {
return undefined;
};
}

// An object can be passed to jQuery.data instead of a key/value pair; this gets
@@ -130,7 +137,7 @@ jQuery.extend({

// If there is no data left in the cache, we want to continue
// and let the cache object itself get destroyed
if ( !jQuery.isEmptyObject(thisCache) ) {
if ( !isEmptyDataObject(thisCache) ) {
return;
}
}
@@ -142,7 +149,7 @@ jQuery.extend({

// Don't destroy the parent cache unless the internal data object
// had been the only thing left in it
if ( !jQuery.isEmptyObject(cache[ id ]) ) {
if ( !isEmptyDataObject(cache[ id ]) ) {
return;
}
}
@@ -291,4 +298,17 @@ function dataAttr( elem, key, data ) {
return data;
}

// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON
// property to be considered empty objects; this property always exists in
// order to make sure JSON.stringify does not expose internal metadata
function isEmptyDataObject( obj ) {
for ( var name in obj ) {
if ( name !== "toJSON" ) {
return false;
}
}

return true;
}

})( jQuery );
@@ -180,7 +180,13 @@ test(".data()", function() {
var div = jQuery("#foo");
strictEqual( div.data("foo"), undefined, "Make sure that missing result is undefined" );
div.data("test", "success");
same( div.data(), {test: "success"}, "data() get the entire data object" );

var dataObj = div.data();

// TODO: Remove this hack which was introduced in 1.5.1
delete dataObj.toJSON;

same( dataObj, {test: "success"}, "data() get the entire data object" );
strictEqual( div.data("foo"), undefined, "Make sure that missing result is still undefined" );

var nodiv = jQuery("#unfound");
@@ -189,7 +195,10 @@ test(".data()", function() {
var obj = { foo: "bar" };
jQuery(obj).data("foo", "baz");

var dataObj = jQuery.extend(true, {}, jQuery(obj).data());
dataObj = jQuery.extend(true, {}, jQuery(obj).data());

// TODO: Remove this hack which was introduced for 1.5.1
delete dataObj.toJSON;

deepEqual( dataObj, { foo: "baz" }, "Retrieve data object from a wrapped JS object (#7524)" );
});
@@ -329,12 +338,18 @@ test("data-* attributes", function() {
num++;
}

// TODO: Remove this hack which was introduced for 1.5.1
num--;

equals( num, check.length, "Make sure that the right number of properties came through." );

for ( var prop in obj2 ) {
num2++;
}

// TODO: Remove this hack which was introduced for 1.5.1
num2--;

equals( num2, check.length, "Make sure that the right number of properties came through." );

child.attr("data-other", "newvalue");
@@ -465,4 +480,15 @@ test(".removeData()", function() {

div.removeData("test.foo");
equals( div.data("test.foo"), undefined, "Make sure data is intact" );
});
});

if (window.JSON && window.JSON.stringify) {
test("JSON serialization (#8108)", function () {
expect(1);

var obj = { foo: "bar" };
jQuery.data(obj, "hidden", true);

equals( JSON.stringify(obj), '{"foo":"bar"}', "Expando is hidden from JSON.stringify" );
});
}

0 comments on commit 2ed8170

Please sign in to comment.
You can’t perform that action at this time.