diff options
author | Michał Gołębiowski-Owczarek <m.goleb@gmail.com> | 2020-03-02 23:02:42 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-02 23:02:42 +0100 |
commit | 9d76c0b163675505d1a901e5fe5249a2c55609bc (patch) | |
tree | 33c4b3ec7a4d312b7db7f9ff1ef5ed21f15992c0 | |
parent | 358b769a00c3a09a8ec621b8dcb2d5e31b7da69a (diff) | |
download | jquery-9d76c0b163675505d1a901e5fe5249a2c55609bc.tar.gz jquery-9d76c0b163675505d1a901e5fe5249a2c55609bc.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
-rw-r--r-- | src/data/Data.js | 2 | ||||
-rw-r--r-- | src/event.js | 6 | ||||
-rw-r--r-- | src/event/trigger.js | 4 | ||||
-rw-r--r-- | src/manipulation.js | 8 | ||||
-rw-r--r-- | test/unit/data.js | 15 | ||||
-rw-r--r-- | test/unit/event.js | 43 |
6 files changed, 69 insertions, 9 deletions
diff --git a/src/data/Data.js b/src/data/Data.js index 556f4e39c..a5eb09089 100644 --- a/src/data/Data.js +++ b/src/data/Data.js @@ -18,7 +18,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 f6dd709dc..c7812508b 100644 --- a/src/event.js +++ b/src/event.js @@ -133,7 +133,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 ) { @@ -294,7 +294,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 aba4c7edd..0d1cd4c56 100644 --- a/src/event/trigger.js +++ b/src/event/trigger.js @@ -99,7 +99,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 08b17a5bb..9ad36a20a 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -60,7 +60,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; @@ -68,13 +68,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 154ea5eeb..cba519e9e 100644 --- a/test/unit/data.js +++ b/test/unit/data.js @@ -998,3 +998,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 cecad3f34..938c66876 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[ QUnit.jQuerySelectors ? "test" : "skip" ]( "delegated event with delegateTarget-relative selector", function( assert ) { assert.expect( 3 ); |