aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichał Gołębiowski-Owczarek <m.goleb@gmail.com>2020-03-02 23:02:42 +0100
committerMichał Gołębiowski-Owczarek <m.goleb@gmail.com>2020-03-02 23:05:58 +0100
commit413ff796ae16611777581e7657cb5ca76c3cfb1d (patch)
treebb0c33a5732a10bc2d62b69f32a150306d025af0
parent524bcf39da9d9aba67d9ec92433462cd936fcc89 (diff)
downloadjquery-413ff796ae16611777581e7657cb5ca76c3cfb1d.tar.gz
jquery-413ff796ae16611777581e7657cb5ca76c3cfb1d.zip
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 9d76c0b163675505d1a901e5fe5249a2c55609bc)
-rw-r--r--src/data/Data.js2
-rw-r--r--src/event.js6
-rw-r--r--src/event/trigger.js4
-rw-r--r--src/manipulation.js8
-rw-r--r--test/unit/data.js15
-rw-r--r--test/unit/event.js43
6 files changed, 69 insertions, 9 deletions
diff --git a/src/data/Data.js b/src/data/Data.js
index 31ff4318c..ce6d8fa9b 100644
--- a/src/data/Data.js
+++ b/src/data/Data.js
@@ -22,7 +22,7 @@ Data.prototype = {
// If not, create one
if ( !value ) {
- value = {};
+ value = Object.create( null );
// We can accept data for non-element nodes in modern browsers,
// but we should not, see #8335.
diff --git a/src/event.js b/src/event.js
index 734f6f020..6510d6a30 100644
--- a/src/event.js
+++ b/src/event.js
@@ -150,7 +150,7 @@ jQuery.event = {
// Init the element's event structure and main handler, if this is the first
if ( !( events = elemData.events ) ) {
- events = elemData.events = {};
+ events = elemData.events = Object.create( null );
}
if ( !( eventHandle = elemData.handle ) ) {
eventHandle = elemData.handle = function( e ) {
@@ -314,7 +314,9 @@ jQuery.event = {
// Make a writable jQuery.Event from the native event object
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 ] || {};
// Use the fix-ed jQuery.Event rather than the (read-only) native event
diff --git a/src/event/trigger.js b/src/event/trigger.js
index cf40b4faa..c3769e1f1 100644
--- a/src/event/trigger.js
+++ b/src/event/trigger.js
@@ -103,7 +103,9 @@ jQuery.extend( jQuery.event, {
special.bindType || type;
// jQuery handler
- handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] &&
+ handle = (
+ dataPriv.get( cur, "events" ) || Object.create( null )
+ )[ event.type ] &&
dataPriv.get( cur, "handle" );
if ( handle ) {
handle.apply( cur, data );
diff --git a/src/manipulation.js b/src/manipulation.js
index 892ab621c..017345afb 100644
--- a/src/manipulation.js
+++ b/src/manipulation.js
@@ -76,7 +76,7 @@ function restoreScript( elem ) {
}
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 ) {
return;
@@ -84,13 +84,11 @@ function cloneCopyEvent( src, dest ) {
// 1. Copy private data: events, handlers, etc.
if ( dataPriv.hasData( src ) ) {
- pdataOld = dataPriv.access( src );
- pdataCur = dataPriv.set( dest, pdataOld );
+ pdataOld = dataPriv.get( src );
events = pdataOld.events;
if ( events ) {
- delete pdataCur.handle;
- pdataCur.events = {};
+ dataPriv.remove( dest, "handle events" );
for ( type in events ) {
for ( i = 0, l = events[ type ].length; i < l; i++ ) {
diff --git a/test/unit/data.js b/test/unit/data.js
index bd0b4e882..138bb8399 100644
--- a/test/unit/data.js
+++ b/test/unit/data.js
@@ -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)" );
+} );
diff --git a/test/unit/event.js b/test/unit/event.js
index fdddb0ba6..5ad20e3fd 100644
--- a/test/unit/event.js
+++ b/test/unit/event.js
@@ -1796,6 +1796,49 @@ QUnit.test( "jQuery.off using dispatched jQuery.Event", function( assert ) {
.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
QUnit[ jQuery.find.compile ? "test" : "skip" ]( "delegated event with delegateTarget-relative selector", function( assert ) {
assert.expect( 3 );