Commit 7f94a5cc authored by Rick Waldron's avatar Rick Waldron

2.0: Rewrite data.js (Incl. event, manipulation, tests)

parent ed0e2d1e
This diff is collapsed.
......@@ -24,7 +24,7 @@ jQuery.event = {
var handleObjIn, eventHandle, tmp,
events, t, handleObj,
special, handlers, type, namespaces, origType,
elemData = jQuery._data( elem );
elemData = data_priv.get( elem );
// Don't attach events to noData or text/comment nodes (but allow plain objects)
if ( !elemData ) {
......@@ -130,7 +130,7 @@ jQuery.event = {
var j, origCount, tmp,
events, t, handleObj,
special, handlers, type, namespaces, origType,
elemData = jQuery.hasData( elem ) && jQuery._data( elem );
elemData = data_priv.hasData( elem ) && data_priv.get( elem );
if ( !elemData || !(events = elemData.events) ) {
return;
......
......@@ -328,7 +328,7 @@ jQuery.fn.extend({
for ( i = 0; i < hasScripts; i++ ) {
node = scripts[ i ];
if ( rscriptType.test( node.type || "" ) &&
!jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
!data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
if ( node.src ) {
// Hope ajax is available...
......@@ -511,11 +511,9 @@ jQuery.extend({
},
cleanData: function( elems, /* internal */ acceptData ) {
var id, data, elem, type,
var data, elem, type,
l = elems.length,
i = 0,
internalKey = jQuery.expando,
cache = jQuery.cache,
special = jQuery.event.special;
for ( ; i < l; i++ ) {
......@@ -523,8 +521,7 @@ jQuery.extend({
if ( acceptData || jQuery.acceptData( elem ) ) {
id = elem[ internalKey ];
data = id && cache[ id ];
data = data_priv.access( elem );
if ( data ) {
for ( type in data.events ) {
......@@ -536,14 +533,10 @@ jQuery.extend({
jQuery.removeEvent( elem, type, data.handle );
}
}
// Remove cache only if it was not already removed by jQuery.event.remove
if ( cache[ id ] ) {
delete cache[ id ];
delete elem[ internalKey ];
}
}
}
// Discard any remaining `private` and `user` data
data_discard( elem );
}
}
});
......@@ -576,38 +569,49 @@ function setGlobalEval( elems, refElements ) {
i = 0;
for ( ; i < l; i++ ) {
jQuery._data( elems[ i ], "globalEval", !refElements || jQuery._data( refElements[ i ], "globalEval" ) );
data_priv.set(
elems[ i ], "globalEval", !refElements || data_priv.get( refElements[ i ], "globalEval" )
);
}
}
function cloneCopyEvent( src, dest ) {
var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
if ( dest.nodeType !== 1 ) {
return;
}
var i, l, type,
oldData = jQuery._data( src ),
curData = jQuery._data( dest, oldData ),
events = oldData.events;
// 1. Copy private data: events, handlers, etc.
if ( data_priv.hasData( src ) ) {
pdataOld = data_priv.access( src );
pdataCur = jQuery.extend( {}, pdataOld );
events = pdataOld.events;
data_priv.set( dest, pdataCur );
if ( events ) {
delete curData.handle;
curData.events = {};
if ( events ) {
delete pdataCur.handle;
pdataCur.events = {};
for ( type in events ) {
for ( i = 0, l = events[ type ].length; i < l; i++ ) {
jQuery.event.add( dest, type, events[ type ][ i ] );
for ( type in events ) {
for ( i = 0, l = events[ type ].length; i < l; i++ ) {
jQuery.event.add( dest, type, events[ type ][ i ] );
}
}
}
}
// make the cloned public data object a copy from the original
if ( curData.data ) {
curData.data = jQuery.extend( {}, curData.data );
// 2. Copy user data
if ( data_user.hasData( src ) ) {
udataOld = data_user.access( src );
udataCur = jQuery.extend( {}, udataOld );
data_user.set( dest, udataCur );
}
}
function getAll( context, tag ) {
var ret = context.getElementsByTagName ? context.getElementsByTagName( tag || "*" ) :
context.querySelectorAll ? context.querySelectorAll( tag || "*" ) :
......
<!doctype html>
<html>
<script src="/dist/jquery.js"></script>
<script>
function report( event ) {
var payload = {
event: event.type
};
return top.postMessage( JSON.stringify(payload), "*" );
}
jQuery( window ).on( "beforeunload", function( event ) {
report( event );
}).on( "load", function( event ) {
setTimeout(function() {
window.location.reload();
}, 50);
});
</script>
</html>
......@@ -200,47 +200,53 @@ var Globals = (function() {
*/
QUnit.expectJqData = function( elems, key ) {
var i, elem, expando;
QUnit.current_testEnvironment.checkJqData = true;
if ( elems.jquery && elems.toArray ) {
elems = elems.toArray();
}
if ( !jQuery.isArray( elems ) ) {
elems = [ elems ];
}
// As of jQuery 2.0, there will be no "cache"-data is
// stored and managed completely below the API surface
if ( jQuery.cache ) {
QUnit.current_testEnvironment.checkJqData = true;
for ( i = 0; i < elems.length; i++ ) {
elem = elems[i];
// jQuery.data only stores data for nodes in jQuery.cache,
// for other data targets the data is stored in the object itself,
// in that case we can't test that target for memory leaks.
// But we don't have to since in that case the data will/must will
// be available as long as the object is not garbage collected by
// the js engine, and when it is, the data will be removed with it.
if ( !elem.nodeType ) {
// Fixes false positives for dataTests(window), dataTests({}).
continue;
if ( elems.jquery && elems.toArray ) {
elems = elems.toArray();
}
if ( !jQuery.isArray( elems ) ) {
elems = [ elems ];
}
expando = elem[ jQuery.expando ];
if ( expando === undefined ) {
// In this case the element exists fine, but
// jQuery.data (or internal data) was never (in)directly
// called.
// Since this method was called it means some data was
// expected to be found, but since there is nothing, fail early
// (instead of in teardown).
notStrictEqual( expando, undefined, "Target for expectJqData must have an expando, for else there can be no data to expect." );
} else {
if ( expectedDataKeys[expando] ) {
expectedDataKeys[expando].push( key );
for ( i = 0; i < elems.length; i++ ) {
elem = elems[i];
// jQuery.data only stores data for nodes in jQuery.cache,
// for other data targets the data is stored in the object itself,
// in that case we can't test that target for memory leaks.
// But we don't have to since in that case the data will/must will
// be available as long as the object is not garbage collected by
// the js engine, and when it is, the data will be removed with it.
if ( !elem.nodeType ) {
// Fixes false positives for dataTests(window), dataTests({}).
continue;
}
expando = elem[ jQuery.expando ];
if ( expando === undefined ) {
// In this case the element exists fine, but
// jQuery.data (or internal data) was never (in)directly
// called.
// Since this method was called it means some data was
// expected to be found, but since there is nothing, fail early
// (instead of in teardown).
notStrictEqual( expando, undefined, "Target for expectJqData must have an expando, for else there can be no data to expect." );
} else {
expectedDataKeys[expando] = [ key ];
if ( expectedDataKeys[expando] ) {
expectedDataKeys[expando].push( key );
} else {
expectedDataKeys[expando] = [ key ];
}
}
}
}
};
QUnit.config.urlConfig.push( {
id: "jqdata",
......@@ -334,7 +340,7 @@ var Globals = (function() {
} else {
delete jQuery.ajaxSettings;
}
// Cleanup globals
Globals.cleanup();
......
......@@ -6,6 +6,33 @@ test("expando", function(){
equal(jQuery.expando !== undefined, true, "jQuery is exposing the expando");
});
test( "jQuery.data & removeData, expected returns", function() {
expect(2);
equal(
jQuery.data( document.body, "hello", "world" ), "world",
"jQuery.data( elem, key, value ) returns value"
);
equal(
jQuery.removeData( document.body, "hello" ), undefined,
"jQuery.removeData( elem, key, value ) returns undefined"
);
});
test( "jQuery._data & _removeData, expected returns", function() {
expect(2);
equal(
jQuery._data( document.body, "hello", "world" ), "world",
"jQuery.data( elem, key, value ) returns value"
);
equal(
jQuery._removeData( document.body, "hello" ), undefined,
"jQuery.removeData( elem, key, value ) returns undefined"
);
});
function dataTests (elem) {
var oldCacheLength, dataObj, internalDataObj, expected, actual;
......@@ -106,6 +133,10 @@ test("Data is not being set on comment and text nodes", function() {
ok( !jQuery.hasData( jQuery("<span>text</span>").contents().data("foo", 0) ) );
});
/*
// Since the new data system does not rely on exandos, limiting the type of
// nodes that can have data is no longer necessary. jQuery.acceptData is now irrelevant
// and should be removed from the library.
test("jQuery.acceptData", function() {
expect(9);
......@@ -127,7 +158,7 @@ test("jQuery.acceptData", function() {
ok( !jQuery.acceptData( document.createComment("") ), "comment" );
ok( !jQuery.acceptData( document.createTextNode("") ), "text" );
});
*/
test(".data()", function() {
expect(5);
......@@ -424,7 +455,7 @@ if (window.JSON && window.JSON.stringify) {
}
test("jQuery.data should follow html5 specification regarding camel casing", function() {
expect(10);
expect(12);
var div = jQuery("<div id='myObject' data-w-t-f='ftw' data-big-a-little-a='bouncing-b' data-foo='a' data-foo-bar='b' data-foo-bar-baz='c'></div>")
.prependTo("body");
......@@ -445,6 +476,9 @@ test("jQuery.data should follow html5 specification regarding camel casing", fun
equal( div.data("fooBar"), "d", "Verify updated data-* key" );
equal( div.data("foo-bar"), "d", "Verify updated data-* key" );
equal( div.data("fooBar"), "d", "Verify updated data-* key (fooBar)" );
equal( div.data("foo-bar"), "d", "Verify updated data-* key (foo-bar)" );
div.remove();
});
......
......@@ -1371,75 +1371,20 @@ test("Submit event can be stopped (#11049)", function() {
// Test beforeunload event only if it supported (i.e. not Opera)
if ( window.onbeforeunload === null ) {
asyncTest("on(beforeunload)", 4, function() {
var win,
forIE6 = 0,
fired = false,
iframe = jQuery("<iframe src='data/iframe.html' />");
iframe.appendTo("#qunit-fixture").one( "load", function() {
win = this.contentWindow || this.contentDocument;
jQuery( win ).on( "beforeunload", function() {
fired = true;
ok( true, "beforeunload event is fired" );
});
strictEqual( win.onbeforeunload, null, "onbeforeunload property on window object still equals null" );
// In old Safari beforeunload event will not fire on iframes
jQuery( win ).on( "unload", function() {
if ( !fired ) {
ok( true, "This is suppose to be true only in old Safari" );
checker();
}
});
jQuery( win ).on( "beforeunload", function() {
// On iframe in IE6 beforeunload event will not fire if event is binded through window object,
// nevertheless, test should continue
window.setTimeout(function() {
if ( !forIE6 ) {
checker();
}
});
});
win.onbeforeunload = function() {
if ( !forIE6 ) {
forIE6++;
checker();
}
};
asyncTest("on(beforeunload)", 1, function() {
var iframe = jQuery(jQuery.parseHTML("<iframe src='data/onbeforeunload.html'><iframe>"));
function checker() {
ok( true, "window.onbeforeunload handler is called" );
iframe = jQuery("<iframe src='data/iframe.html' />");
window.onmessage = function( event ) {
var payload = JSON.parse( event.data );
iframe.appendTo("#qunit-fixture").one( "load", function() {
win = iframe[ 0 ].contentWindow || iframe[ 0 ].contentDocument;
ok( payload.event, "beforeunload", "beforeunload event" );
jQuery( win ).on( "beforeunload", function() {
strictEqual( win.onbeforeunload, null, "Event handler is fired, even when onbeforeunload property on window is nulled" );
start();
});
jQuery( win ).on( "unload", function() {
if ( !fired ) {
jQuery( win ).trigger("beforeunload");
}
});
win.onbeforeunload = null;
win.location.reload();
});
}
iframe.remove();
window.onmessage = null;
start();
};
win.location.reload();
});
iframe.appendTo("#qunit-fixture");
});
}
......@@ -2567,7 +2512,7 @@ test( "Namespace preserved when passed an Event (#12739)", function() {
e.handled = true;
equal( e.namespace, "bar", "namespace is bar" );
jQuery( e.target ).find("div").each(function() {
jQuery( this ).triggerHandler( e );
jQuery( this ).triggerHandler( e );
});
}
})
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment