1 module("data", { teardown
: moduleTeardown
});
3 test("expando", function(){
6 equals("expando" in jQuery
, true, "jQuery is exposing the expando");
9 function dataTests (elem
) {
12 function getCacheLength() {
14 for (var i
in jQuery
.cache
) {
21 equals( jQuery
.data(elem
, "foo"), undefined, "No data exists initially" );
22 strictEqual( jQuery
.hasData(elem
), false, "jQuery.hasData agrees no data exists initially" );
24 var dataObj
= jQuery
.data(elem
);
25 equals( typeof dataObj
, "object", "Calling data with no args gives us a data object reference" );
26 strictEqual( jQuery
.data(elem
), dataObj
, "Calling jQuery.data returns the same data object when called multiple times" );
28 strictEqual( jQuery
.hasData(elem
), false, "jQuery.hasData agrees no data exists even when an empty data obj exists" );
31 equals( jQuery
.data(elem
, "foo"), "bar", "Data is readable by jQuery.data when set directly on a returned data object" );
33 strictEqual( jQuery
.hasData(elem
), true, "jQuery.hasData agrees data exists when data exists" );
35 jQuery
.data(elem
, "foo", "baz");
36 equals( jQuery
.data(elem
, "foo"), "baz", "Data can be changed by jQuery.data" );
37 equals( dataObj
.foo
, "baz", "Changes made through jQuery.data propagate to referenced data object" );
39 jQuery
.data(elem
, "foo", undefined);
40 equals( jQuery
.data(elem
, "foo"), "baz", "Data is not unset by passing undefined to jQuery.data" );
42 jQuery
.data(elem
, "foo", null);
43 strictEqual( jQuery
.data(elem
, "foo"), null, "Setting null using jQuery.data works OK" );
45 jQuery
.data(elem
, "foo", "foo1");
47 jQuery
.data(elem
, { "bar" : "baz", "boom" : "bloz" });
48 strictEqual( jQuery
.data(elem
, "foo"), "foo1", "Passing an object extends the data object instead of replacing it" );
49 equals( jQuery
.data(elem
, "boom"), "bloz", "Extending the data object works" );
51 jQuery
._data(elem
, "foo", "foo2");
52 equals( jQuery
._data(elem
, "foo"), "foo2", "Setting internal data works" );
53 equals( jQuery
.data(elem
, "foo"), "foo1", "Setting internal data does not override user data" );
55 var internalDataObj
= jQuery
.data(elem
, jQuery
.expando
);
56 strictEqual( jQuery
._data(elem
), internalDataObj
, "Internal data object is accessible via jQuery.expando property" );
57 notStrictEqual( dataObj
, internalDataObj
, "Internal data object is not the same as user data object" );
59 strictEqual( elem
.boom
, undefined, "Data is never stored directly on the object" );
61 jQuery
.removeData(elem
, "foo");
62 strictEqual( jQuery
.data(elem
, "foo"), undefined, "jQuery.removeData removes single properties" );
64 jQuery
.removeData(elem
);
65 strictEqual( jQuery
.data(elem
, jQuery
.expando
), internalDataObj
, "jQuery.removeData does not remove internal data if it exists" );
67 jQuery
.removeData(elem
, undefined, true);
69 strictEqual( jQuery
.data(elem
, jQuery
.expando
), undefined, "jQuery.removeData on internal data works" );
70 strictEqual( jQuery
.hasData(elem
), false, "jQuery.hasData agrees all data has been removed from object" );
72 jQuery
._data(elem
, "foo", "foo2");
73 strictEqual( jQuery
.hasData(elem
), true, "jQuery.hasData shows data exists even if it is only internal data" );
75 jQuery
.data(elem
, "foo", "foo1");
76 equals( jQuery
._data(elem
, "foo"), "foo2", "Setting user data does not override internal data" );
78 jQuery
.removeData(elem
, undefined, true);
79 equals( jQuery
.data(elem
, "foo"), "foo1", "jQuery.removeData for internal data does not remove user data" );
82 var oldCacheLength
= getCacheLength();
83 jQuery
.removeData(elem
, "foo");
85 equals( getCacheLength(), oldCacheLength
- 1, "Removing the last item in the data object destroys it" );
88 jQuery
.removeData(elem
, "foo");
91 if (jQuery
.support
.deleteExpando
) {
93 actual
= jQuery
.expando
in elem
;
97 actual
= elem
[ jQuery
.expando
];
100 equals( actual
, expected
, "Removing the last item in the data object destroys it" );
103 jQuery
.data(elem
, "foo", "foo1");
104 jQuery
._data(elem
, "foo", "foo2");
106 equals( jQuery
.data(elem
, "foo"), "foo1", "(sanity check) Ensure data is set in user data object" );
107 equals( jQuery
._data(elem
, "foo"), "foo2", "(sanity check) Ensure data is set in internal data object" );
109 jQuery
.removeData(elem
, "foo", true);
111 strictEqual( jQuery
.data(elem
, jQuery
.expando
), undefined, "Removing the last item in internal data destroys the internal data object" );
113 jQuery
._data(elem
, "foo", "foo2");
114 equals( jQuery
._data(elem
, "foo"), "foo2", "(sanity check) Ensure data is set in internal data object" );
116 jQuery
.removeData(elem
, "foo");
117 equals( jQuery
._data(elem
, "foo"), "foo2", "(sanity check) jQuery.removeData for user data does not remove internal data" );
120 oldCacheLength
= getCacheLength();
121 jQuery
.removeData(elem
, "foo", true);
122 equals( getCacheLength(), oldCacheLength
- 1, "Removing the last item in the internal data object also destroys the user data object when it is empty" );
125 jQuery
.removeData(elem
, "foo", true);
127 if (jQuery
.support
.deleteExpando
) {
129 actual
= jQuery
.expando
in elem
;
133 actual
= elem
[ jQuery
.expando
];
136 equals( actual
, expected
, "Removing the last item in the internal data object also destroys the user data object when it is empty" );
140 test("jQuery.data", function() {
143 var div
= document
.createElement("div");
148 // remove bound handlers from window object to stop potential false positives caused by fix for #5280 in
150 jQuery(window
).unbind("unload");
155 // clean up unattached element
156 jQuery(div
).remove();
159 test("jQuery.acceptData", function() {
162 ok( jQuery
.acceptData( document
), "document" );
163 ok( jQuery
.acceptData( document
.documentElement
), "documentElement" );
164 ok( jQuery
.acceptData( {} ), "object" );
165 ok( !jQuery
.acceptData( document
.createElement("embed") ), "embed" );
166 ok( !jQuery
.acceptData( document
.createElement("applet") ), "applet" );
168 var flash
= document
.createElement("object");
169 flash
.setAttribute("classid", "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000");
170 ok( jQuery
.acceptData( flash
), "flash" );
172 var applet
= document
.createElement("object");
173 applet
.setAttribute("classid", "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93");
174 ok( !jQuery
.acceptData( applet
), "applet" );
177 test(".data()", function() {
180 var div
= jQuery("#foo");
181 strictEqual( div
.data("foo"), undefined, "Make sure that missing result is undefined" );
182 div
.data("test", "success");
184 var dataObj
= div
.data();
186 // TODO: Remove this hack which was introduced in 1.5.1
187 delete dataObj
.toJSON
;
189 same( dataObj
, {test
: "success"}, "data() get the entire data object" );
190 strictEqual( div
.data("foo"), undefined, "Make sure that missing result is still undefined" );
192 var nodiv
= jQuery("#unfound");
193 equals( nodiv
.data(), null, "data() on empty set returns null" );
195 var obj
= { foo
: "bar" };
196 jQuery(obj
).data("foo", "baz");
198 dataObj
= jQuery
.extend(true, {}, jQuery(obj
).data());
200 // TODO: Remove this hack which was introduced for 1.5.1
201 delete dataObj
.toJSON
;
203 deepEqual( dataObj
, { foo
: "baz" }, "Retrieve data object from a wrapped JS object (#7524)" );
206 test(".data(String) and .data(String, Object)", function() {
208 var parent
= jQuery("<div><div></div></div>"),
209 div
= parent
.children();
212 .bind("getData", function(){ ok( false, "getData bubbled." ) })
213 .bind("setData", function(){ ok( false, "setData bubbled." ) })
214 .bind("changeData", function(){ ok( false, "changeData bubbled." ) });
216 ok( div
.data("test") === undefined, "Check for no data exists" );
218 div
.data("test", "success");
219 equals( div
.data("test"), "success", "Check for added data" );
221 div
.data("test", "overwritten");
222 equals( div
.data("test"), "overwritten", "Check for overwritten data" );
224 div
.data("test", undefined);
225 equals( div
.data("test"), "overwritten", "Check that data wasn't removed");
227 div
.data("test", null);
228 ok( div
.data("test") === null, "Check for null data");
230 ok( div
.data("notexist") === undefined, "Check for no data exists" );
232 div
.data("test", "overwritten");
233 var hits
= {test
:0}, gets
= {test
:0}, changes
= {test
:0, value
:null};
236 function logChangeData(e
,key
,value
) {
239 dataKey
= dataKey
+ "." + e
.namespace;
241 changes
[key
] += value
;
242 changes
.value
= jQuery
.data(e
.target
, dataKey
);
246 .bind("setData",function(e
,key
,value
){ hits
[key
] += value
; })
247 .bind("setData.foo",function(e
,key
,value
){ hits
[key
] += value
; })
248 .bind("changeData",logChangeData
)
249 .bind("changeData.foo",logChangeData
)
250 .bind("getData",function(e
,key
){ gets
[key
] += 1; })
251 .bind("getData.foo",function(e
,key
){ gets
[key
] += 3; });
253 div
.data("test.foo", 2);
254 equals( div
.data("test"), "overwritten", "Check for original data" );
255 equals( div
.data("test.foo"), 2, "Check for namespaced data" );
256 equals( div
.data("test.bar"), "overwritten", "Check for unmatched namespace" );
257 equals( hits
.test
, 2, "Check triggered setter functions" );
258 equals( gets
.test
, 5, "Check triggered getter functions" );
259 equals( changes
.test
, 2, "Check sets raise changeData");
260 equals( changes
.value
, 2, "Check changeData after data has been set" );
265 changes
.value
= null;
268 equals( div
.data("test"), 1, "Check for original data" );
269 equals( div
.data("test.foo"), 2, "Check for namespaced data" );
270 equals( div
.data("test.bar"), 1, "Check for unmatched namespace" );
271 equals( hits
.test
, 1, "Check triggered setter functions" );
272 equals( gets
.test
, 5, "Check triggered getter functions" );
273 equals( changes
.test
, 1, "Check sets raise changeData" );
274 equals( changes
.value
, 1, "Check changeData after data has been set" );
277 .bind("getData",function(e
,key
){ return key
+ "root"; })
278 .bind("getData.foo",function(e
,key
){ return key
+ "foo"; });
280 equals( div
.data("test"), "testroot", "Check for original data" );
281 equals( div
.data("test.foo"), "testfoo", "Check for namespaced data" );
282 equals( div
.data("test.bar"), "testroot", "Check for unmatched namespace" );
285 var $elem
= jQuery({exists
:true});
286 equals( $elem
.data('nothing'), undefined, "Non-existent data returns undefined");
287 equals( $elem
.data('null',null).data('null'), null, "null's are preserved");
288 equals( $elem
.data('emptyString','').data('emptyString'), '', "Empty strings are preserved");
289 equals( $elem
.data('false',false).data('false'), false, "false's are preserved");
290 equals( $elem
.data('exists'), undefined, "Existing data is not returned" );
294 deepEqual( $elem
[0], {exists
:true}, "removeData does not clear the object" );
296 // manually clean up detached elements
300 test("data-* attributes", function() {
302 var div
= jQuery("<div>"),
303 child
= jQuery("<div data-myobj='old data' data-ignored=\"DOM\" data-other='test'></div>"),
304 dummy
= jQuery("<div data-myobj='old data' data-ignored=\"DOM\" data-other='test'></div>");
306 equals( div
.data("attr"), undefined, "Check for non-existing data-attr attribute" );
308 div
.attr("data-attr", "exists");
309 equals( div
.data("attr"), "exists", "Check for existing data-attr attribute" );
311 div
.attr("data-attr", "exists2");
312 equals( div
.data("attr"), "exists", "Check that updates to data- don't update .data()" );
314 div
.data("attr", "internal").attr("data-attr", "external");
315 equals( div
.data("attr"), "internal", "Check for .data('attr') precedence (internal > external data-* attribute)" );
319 child
.appendTo('#main');
320 equals( child
.data("myobj"), "old data", "Value accessed from data-* attribute");
322 child
.data("myobj", "replaced");
323 equals( child
.data("myobj"), "replaced", "Original data overwritten");
325 child
.data("ignored", "cache");
326 equals( child
.data("ignored"), "cache", "Cached data used before DOM data-* fallback");
328 var obj
= child
.data(), obj2
= dummy
.data(), check
= [ "myobj", "ignored", "other" ], num
= 0, num2
= 0;
332 for ( var i
= 0, l
= check
.length
; i
< l
; i
++ ) {
333 ok( obj
[ check
[i
] ], "Make sure data- property exists when calling data-." );
334 ok( obj2
[ check
[i
] ], "Make sure data- property exists when calling data-." );
337 for ( var prop
in obj
) {
341 equals( num
, check
.length
, "Make sure that the right number of properties came through." );
343 for ( var prop
in obj2
) {
347 equals( num2
, check
.length
, "Make sure that the right number of properties came through." );
349 child
.attr("data-other", "newvalue");
351 equals( child
.data("other"), "test", "Make sure value was pulled in properly from a .data()." );
354 .attr("data-true", "true")
355 .attr("data-false", "false")
356 .attr("data-five", "5")
357 .attr("data-point", "5.5")
358 .attr("data-pointe", "5.5E3")
359 .attr("data-pointbad", "5..5")
360 .attr("data-pointbad2", "-.")
361 .attr("data-badjson", "{123}")
362 .attr("data-badjson2", "[abc]")
363 .attr("data-empty", "")
364 .attr("data-space", " ")
365 .attr("data-null", "null")
366 .attr("data-string", "test");
368 strictEqual( child
.data('true'), true, "Primitive true read from attribute");
369 strictEqual( child
.data('false'), false, "Primitive false read from attribute");
370 strictEqual( child
.data('five'), 5, "Primitive number read from attribute");
371 strictEqual( child
.data('point'), 5.5, "Primitive number read from attribute");
372 strictEqual( child
.data('pointe'), 5500, "Primitive number read from attribute");
373 strictEqual( child
.data('pointbad'), "5..5", "Bad number read from attribute");
374 strictEqual( child
.data('pointbad2'), "-.", "Bad number read from attribute");
375 strictEqual( child
.data('badjson'), "{123}", "Bad number read from attribute");
376 strictEqual( child
.data('badjson2'), "[abc]", "Bad number read from attribute");
377 strictEqual( child
.data('empty'), "", "Empty string read from attribute");
378 strictEqual( child
.data('space'), " ", "Empty string read from attribute");
379 strictEqual( child
.data('null'), null, "Primitive null read from attribute");
380 strictEqual( child
.data('string'), "test", "Typical string read from attribute");
384 // tests from metadata plugin
385 function testData(index
, elem
) {
388 equals(jQuery(elem
).data("foo"), "bar", "Check foo property");
389 equals(jQuery(elem
).data("bar"), "baz", "Check baz property");
392 equals(jQuery(elem
).data("test"), "bar", "Check test property");
393 equals(jQuery(elem
).data("bar"), "baz", "Check bar property");
396 equals(jQuery(elem
).data("zoooo"), "bar", "Check zoooo property");
397 same(jQuery(elem
).data("bar"), {"test":"baz"}, "Check bar property");
400 equals(jQuery(elem
).data("number"), true, "Check number property");
401 same(jQuery(elem
).data("stuff"), [2,8], "Check stuff property");
404 ok(false, ["Assertion failed on index ", index
, ", with data ", data
].join(''));
408 var metadata
= '<ol><li class="test test2" data-foo="bar" data-bar="baz" data-arr="[1,2]">Some stuff</li><li class="test test2" data-test="bar" data-bar="baz">Some stuff</li><li class="test test2" data-zoooo="bar" data-bar=\'{"test":"baz"}\'>Some stuff</li><li class="test test2" data-number=true data-stuff="[2,8]">Some stuff</li></ol>',
409 elem
= jQuery(metadata
).appendTo('#main');
411 elem
.find("li").each(testData
);
415 test(".data(Object)", function() {
418 var div
= jQuery("<div/>");
420 div
.data({ "test": "in", "test2": "in2" });
421 equals( div
.data("test"), "in", "Verify setting an object in data" );
422 equals( div
.data("test2"), "in2", "Verify setting an object in data" );
424 var obj
= {test
:"unset"},
426 jqobj
.data("test", "unset");
427 jqobj
.data({ "test": "in", "test2": "in2" });
428 equals( jQuery
.data(obj
).test
, "in", "Verify setting an object on an object extends the data object" );
429 equals( obj
.test2
, undefined, "Verify setting an object on an object does not extend the object" );
431 // manually clean up detached elements
435 test("jQuery.removeData", function() {
437 var div
= jQuery("#foo")[0];
438 jQuery
.data(div
, "test", "testing");
439 jQuery
.removeData(div
, "test");
440 equals( jQuery
.data(div
, "test"), undefined, "Check removal of data" );
442 jQuery
.data(div
, "test2", "testing");
443 jQuery
.removeData( div
);
444 ok( !jQuery
.data(div
, "test2"), "Make sure that the data property no longer exists." );
445 ok( !div
[ jQuery
.expando
], "Make sure the expando no longer exists, as well." );
448 jQuery
.data(obj
, "test", "testing");
449 equals( jQuery(obj
).data("test"), "testing", "verify data on plain object");
450 jQuery
.removeData(obj
, "test");
451 equals( jQuery
.data(obj
, "test"), undefined, "Check removal of data on plain object" );
453 jQuery
.data( window
, "BAD", true );
454 jQuery
.removeData( window
, "BAD" );
455 ok( !jQuery
.data( window
, "BAD" ), "Make sure that the value was not still set." );
458 test(".removeData()", function() {
460 var div
= jQuery("#foo");
461 div
.data("test", "testing");
462 div
.removeData("test");
463 equals( div
.data("test"), undefined, "Check removal of data" );
465 div
.data("test", "testing");
466 div
.data("test.foo", "testing2");
467 div
.removeData("test.bar");
468 equals( div
.data("test.foo"), "testing2", "Make sure data is intact" );
469 equals( div
.data("test"), "testing", "Make sure data is intact" );
471 div
.removeData("test");
472 equals( div
.data("test.foo"), "testing2", "Make sure data is intact" );
473 equals( div
.data("test"), undefined, "Make sure data is intact" );
475 div
.removeData("test.foo");
476 equals( div
.data("test.foo"), undefined, "Make sure data is intact" );
479 if (window
.JSON
&& window
.JSON
.stringify
) {
480 test("JSON serialization (#8108)", function () {
483 var obj
= { foo
: "bar" };
484 jQuery
.data(obj
, "hidden", true);
486 equals( JSON
.stringify(obj
), '{"foo":"bar"}', "Expando is hidden from JSON.stringify" );