Skip to content

Commit 9d76c0b

Browse files
authored
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
1 parent 358b769 commit 9d76c0b

File tree

6 files changed

+69
-9
lines changed

6 files changed

+69
-9
lines changed

src/data/Data.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Data.prototype = {
1818

1919
// If not, create one
2020
if ( !value ) {
21-
value = {};
21+
value = Object.create( null );
2222

2323
// We can accept data for non-element nodes in modern browsers,
2424
// but we should not, see #8335.

src/event.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ jQuery.event = {
133133

134134
// Init the element's event structure and main handler, if this is the first
135135
if ( !( events = elemData.events ) ) {
136-
events = elemData.events = {};
136+
events = elemData.events = Object.create( null );
137137
}
138138
if ( !( eventHandle = elemData.handle ) ) {
139139
eventHandle = elemData.handle = function( e ) {
@@ -294,7 +294,9 @@ jQuery.event = {
294294
// Make a writable jQuery.Event from the native event object
295295
event = jQuery.event.fix( nativeEvent ),
296296

297-
handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [],
297+
handlers = (
298+
dataPriv.get( this, "events" ) || Object.create( null )
299+
)[ event.type ] || [],
298300
special = jQuery.event.special[ event.type ] || {};
299301

300302
// Use the fix-ed jQuery.Event rather than the (read-only) native event

src/event/trigger.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ jQuery.extend( jQuery.event, {
9999
special.bindType || type;
100100

101101
// jQuery handler
102-
handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] &&
102+
handle = (
103+
dataPriv.get( cur, "events" ) || Object.create( null )
104+
)[ event.type ] &&
103105
dataPriv.get( cur, "handle" );
104106
if ( handle ) {
105107
handle.apply( cur, data );

src/manipulation.js

+3-5
Original file line numberDiff line numberDiff line change
@@ -60,21 +60,19 @@ function restoreScript( elem ) {
6060
}
6161

6262
function cloneCopyEvent( src, dest ) {
63-
var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
63+
var i, l, type, pdataOld, udataOld, udataCur, events;
6464

6565
if ( dest.nodeType !== 1 ) {
6666
return;
6767
}
6868

6969
// 1. Copy private data: events, handlers, etc.
7070
if ( dataPriv.hasData( src ) ) {
71-
pdataOld = dataPriv.access( src );
72-
pdataCur = dataPriv.set( dest, pdataOld );
71+
pdataOld = dataPriv.get( src );
7372
events = pdataOld.events;
7473

7574
if ( events ) {
76-
delete pdataCur.handle;
77-
pdataCur.events = {};
75+
dataPriv.remove( dest, "handle events" );
7876

7977
for ( type in events ) {
8078
for ( i = 0, l = events[ type ].length; i < l; i++ ) {

test/unit/data.js

+15
Original file line numberDiff line numberDiff line change
@@ -998,3 +998,18 @@ QUnit.test( ".data(prop) does not create expando", function( assert ) {
998998
}
999999
}
10001000
} );
1001+
1002+
QUnit.test( "keys matching Object.prototype properties (gh-3256)", function( assert ) {
1003+
assert.expect( 2 );
1004+
1005+
var div = jQuery( "<div/>" );
1006+
1007+
assert.strictEqual( div.data( "hasOwnProperty" ), undefined,
1008+
"hasOwnProperty not matched (before forced data creation)" );
1009+
1010+
// Force the creation of a data object for this element.
1011+
div.data( { foo: "bar" } );
1012+
1013+
assert.strictEqual( div.data( "hasOwnProperty" ), undefined,
1014+
"hasOwnProperty not matched (after forced data creation)" );
1015+
} );

test/unit/event.js

+43
Original file line numberDiff line numberDiff line change
@@ -1796,6 +1796,49 @@ QUnit.test( "jQuery.off using dispatched jQuery.Event", function( assert ) {
17961796
.remove();
17971797
} );
17981798

1799+
QUnit.test( "events with type matching an Object.prototype property (gh-3256)", function( assert ) {
1800+
assert.expect( 1 );
1801+
1802+
var elem = jQuery( "<div/>" ),
1803+
eventFired = false;
1804+
1805+
elem.appendTo( "#qunit-fixture" );
1806+
1807+
try {
1808+
elem
1809+
.one( "hasOwnProperty", function() {
1810+
eventFired = true;
1811+
} )
1812+
.trigger( "hasOwnProperty" );
1813+
} finally {
1814+
assert.strictEqual( eventFired, true, "trigger fired without crashing" );
1815+
}
1816+
} );
1817+
1818+
QUnit.test( "events with type matching an Object.prototype property, cloned element (gh-3256)",
1819+
function( assert ) {
1820+
assert.expect( 1 );
1821+
1822+
var elem = jQuery( "<div/>" ),
1823+
eventFired = false;
1824+
1825+
elem.appendTo( "#qunit-fixture" );
1826+
1827+
try {
1828+
// Make sure the original element has some event data.
1829+
elem.on( "click", function() {} );
1830+
1831+
elem
1832+
.clone( true )
1833+
.one( "hasOwnProperty", function() {
1834+
eventFired = true;
1835+
} )
1836+
.trigger( "hasOwnProperty" );
1837+
} finally {
1838+
assert.strictEqual( eventFired, true, "trigger fired without crashing" );
1839+
}
1840+
} );
1841+
17991842
// selector-native does not support scope-fixing in delegation
18001843
QUnit[ QUnit.jQuerySelectors ? "test" : "skip" ]( "delegated event with delegateTarget-relative selector", function( assert ) {
18011844
assert.expect( 3 );

0 commit comments

Comments
 (0)