]> source.dussan.org Git - jquery.git/commitdiff
Data:Event:Manipulation: Prevent collisions with Object.prototype
authorMichał Gołębiowski-Owczarek <m.goleb@gmail.com>
Mon, 2 Mar 2020 22:02:42 +0000 (23:02 +0100)
committerMichał Gołębiowski-Owczarek <m.goleb@gmail.com>
Mon, 2 Mar 2020 22:05:58 +0000 (23:05 +0100)
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)

src/data/Data.js
src/event.js
src/event/trigger.js
src/manipulation.js
test/unit/data.js
test/unit/event.js

index 31ff4318c1770ec43655e17d02a4373675e5c4bd..ce6d8fa9bab48c7e3bdf5a47cf614f2ff08272fa 100644 (file)
@@ -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.
index 734f6f020a9302197e55862736978796c3211299..6510d6a300e3b6197b6dd01efed493921c9b79e0 100644 (file)
@@ -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
index cf40b4faabfd1400b6dc3304622d7f39b6d6e22c..c3769e1f1690863222a1094a883a04d4dd353de9 100644 (file)
@@ -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 );
index 892ab621c86d665b1443570a1ac222c8588466d4..017345afb4fe1ff8b8b25bbba8aa3516463c4ec4 100644 (file)
@@ -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++ ) {
index bd0b4e8829537a256b1fc6c17a6b6fa1388698af..138bb8399eb0e44d52098cbf028ab90addab28ff 100644 (file)
@@ -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)" );
+} );
index fdddb0ba6e4e4f9286d88a3e216bf13d963bfca9..5ad20e3fdc4b35d78b54339d0c91a690925c1925 100644 (file)
@@ -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 );