mirror of
https://github.com/jquery/jquery.git
synced 2025-01-10 18:24:24 +00:00
Data:Event:Manipulation: Prevent collisions with Object.prototype
Make sure events & data keys matching Object.prototype properties work.
A separate fix for such events on cloned elements was added as well.
Fixes gh-3256
Closes gh-4603
(cherry picked from commit 9d76c0b163
)
This commit is contained in:
parent
524bcf39da
commit
413ff796ae
@ -22,7 +22,7 @@ Data.prototype = {
|
|||||||
|
|
||||||
// If not, create one
|
// If not, create one
|
||||||
if ( !value ) {
|
if ( !value ) {
|
||||||
value = {};
|
value = Object.create( null );
|
||||||
|
|
||||||
// We can accept data for non-element nodes in modern browsers,
|
// We can accept data for non-element nodes in modern browsers,
|
||||||
// but we should not, see #8335.
|
// but we should not, see #8335.
|
||||||
|
@ -150,7 +150,7 @@ jQuery.event = {
|
|||||||
|
|
||||||
// Init the element's event structure and main handler, if this is the first
|
// Init the element's event structure and main handler, if this is the first
|
||||||
if ( !( events = elemData.events ) ) {
|
if ( !( events = elemData.events ) ) {
|
||||||
events = elemData.events = {};
|
events = elemData.events = Object.create( null );
|
||||||
}
|
}
|
||||||
if ( !( eventHandle = elemData.handle ) ) {
|
if ( !( eventHandle = elemData.handle ) ) {
|
||||||
eventHandle = elemData.handle = function( e ) {
|
eventHandle = elemData.handle = function( e ) {
|
||||||
@ -314,7 +314,9 @@ jQuery.event = {
|
|||||||
// Make a writable jQuery.Event from the native event object
|
// Make a writable jQuery.Event from the native event object
|
||||||
event = jQuery.event.fix( nativeEvent ),
|
event = jQuery.event.fix( nativeEvent ),
|
||||||
|
|
||||||
handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [],
|
handlers = (
|
||||||
|
dataPriv.get( this, "events" ) || Object.create( null )
|
||||||
|
)[ event.type ] || [],
|
||||||
special = jQuery.event.special[ event.type ] || {};
|
special = jQuery.event.special[ event.type ] || {};
|
||||||
|
|
||||||
// Use the fix-ed jQuery.Event rather than the (read-only) native event
|
// Use the fix-ed jQuery.Event rather than the (read-only) native event
|
||||||
|
@ -103,7 +103,9 @@ jQuery.extend( jQuery.event, {
|
|||||||
special.bindType || type;
|
special.bindType || type;
|
||||||
|
|
||||||
// jQuery handler
|
// jQuery handler
|
||||||
handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] &&
|
handle = (
|
||||||
|
dataPriv.get( cur, "events" ) || Object.create( null )
|
||||||
|
)[ event.type ] &&
|
||||||
dataPriv.get( cur, "handle" );
|
dataPriv.get( cur, "handle" );
|
||||||
if ( handle ) {
|
if ( handle ) {
|
||||||
handle.apply( cur, data );
|
handle.apply( cur, data );
|
||||||
|
@ -76,7 +76,7 @@ function restoreScript( elem ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function cloneCopyEvent( src, dest ) {
|
function cloneCopyEvent( src, dest ) {
|
||||||
var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
|
var i, l, type, pdataOld, udataOld, udataCur, events;
|
||||||
|
|
||||||
if ( dest.nodeType !== 1 ) {
|
if ( dest.nodeType !== 1 ) {
|
||||||
return;
|
return;
|
||||||
@ -84,13 +84,11 @@ function cloneCopyEvent( src, dest ) {
|
|||||||
|
|
||||||
// 1. Copy private data: events, handlers, etc.
|
// 1. Copy private data: events, handlers, etc.
|
||||||
if ( dataPriv.hasData( src ) ) {
|
if ( dataPriv.hasData( src ) ) {
|
||||||
pdataOld = dataPriv.access( src );
|
pdataOld = dataPriv.get( src );
|
||||||
pdataCur = dataPriv.set( dest, pdataOld );
|
|
||||||
events = pdataOld.events;
|
events = pdataOld.events;
|
||||||
|
|
||||||
if ( events ) {
|
if ( events ) {
|
||||||
delete pdataCur.handle;
|
dataPriv.remove( dest, "handle events" );
|
||||||
pdataCur.events = {};
|
|
||||||
|
|
||||||
for ( type in events ) {
|
for ( type in events ) {
|
||||||
for ( i = 0, l = events[ type ].length; i < l; i++ ) {
|
for ( i = 0, l = events[ type ].length; i < l; i++ ) {
|
||||||
|
@ -989,3 +989,18 @@ QUnit.test( ".data(prop) does not create expando", function( assert ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
QUnit.test( "keys matching Object.prototype properties (gh-3256)", function( assert ) {
|
||||||
|
assert.expect( 2 );
|
||||||
|
|
||||||
|
var div = jQuery( "<div/>" );
|
||||||
|
|
||||||
|
assert.strictEqual( div.data( "hasOwnProperty" ), undefined,
|
||||||
|
"hasOwnProperty not matched (before forced data creation)" );
|
||||||
|
|
||||||
|
// Force the creation of a data object for this element.
|
||||||
|
div.data( { foo: "bar" } );
|
||||||
|
|
||||||
|
assert.strictEqual( div.data( "hasOwnProperty" ), undefined,
|
||||||
|
"hasOwnProperty not matched (after forced data creation)" );
|
||||||
|
} );
|
||||||
|
@ -1796,6 +1796,49 @@ QUnit.test( "jQuery.off using dispatched jQuery.Event", function( assert ) {
|
|||||||
.remove();
|
.remove();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
QUnit.test( "events with type matching an Object.prototype property (gh-3256)", function( assert ) {
|
||||||
|
assert.expect( 1 );
|
||||||
|
|
||||||
|
var elem = jQuery( "<div/>" ),
|
||||||
|
eventFired = false;
|
||||||
|
|
||||||
|
elem.appendTo( "#qunit-fixture" );
|
||||||
|
|
||||||
|
try {
|
||||||
|
elem
|
||||||
|
.one( "hasOwnProperty", function() {
|
||||||
|
eventFired = true;
|
||||||
|
} )
|
||||||
|
.trigger( "hasOwnProperty" );
|
||||||
|
} finally {
|
||||||
|
assert.strictEqual( eventFired, true, "trigger fired without crashing" );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
QUnit.test( "events with type matching an Object.prototype property, cloned element (gh-3256)",
|
||||||
|
function( assert ) {
|
||||||
|
assert.expect( 1 );
|
||||||
|
|
||||||
|
var elem = jQuery( "<div/>" ),
|
||||||
|
eventFired = false;
|
||||||
|
|
||||||
|
elem.appendTo( "#qunit-fixture" );
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Make sure the original element has some event data.
|
||||||
|
elem.on( "click", function() {} );
|
||||||
|
|
||||||
|
elem
|
||||||
|
.clone( true )
|
||||||
|
.one( "hasOwnProperty", function() {
|
||||||
|
eventFired = true;
|
||||||
|
} )
|
||||||
|
.trigger( "hasOwnProperty" );
|
||||||
|
} finally {
|
||||||
|
assert.strictEqual( eventFired, true, "trigger fired without crashing" );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
// selector-native does not support scope-fixing in delegation
|
// selector-native does not support scope-fixing in delegation
|
||||||
QUnit[ jQuery.find.compile ? "test" : "skip" ]( "delegated event with delegateTarget-relative selector", function( assert ) {
|
QUnit[ jQuery.find.compile ? "test" : "skip" ]( "delegated event with delegateTarget-relative selector", function( assert ) {
|
||||||
assert.expect( 3 );
|
assert.expect( 3 );
|
||||||
|
Loading…
Reference in New Issue
Block a user