From 4a465fbd9a99815e9a0eb8b14af0c0423d9e8552 Mon Sep 17 00:00:00 2001 From: Jim Date: Tue, 16 Jun 2015 14:15:12 -0700 Subject: [PATCH] Make events propagate through shadow DOMs. --- .../dom/client/ReactEventListener.js | 51 ++++++++++++++++++- .../eventPlugins/EnterLeaveEventPlugin.js | 9 ++-- .../client/eventPlugins/SelectEventPlugin.js | 13 ++--- .../client/eventPlugins/SimpleEventPlugin.js | 6 ++- .../dom/client/eventPlugins/TapEventPlugin.js | 6 ++- .../__tests__/EnterLeaveEventPlugin-test.js | 3 +- .../__tests__/SelectEventPlugin-test.js | 3 +- .../SyntheticClipboardEvent.js | 4 +- .../SyntheticCompositionEvent.js | 5 +- .../syntheticEvents/SyntheticDragEvent.js | 4 +- .../client/syntheticEvents/SyntheticEvent.js | 11 ++-- .../syntheticEvents/SyntheticFocusEvent.js | 4 +- .../syntheticEvents/SyntheticInputEvent.js | 5 +- .../syntheticEvents/SyntheticKeyboardEvent.js | 4 +- .../syntheticEvents/SyntheticMouseEvent.js | 4 +- .../syntheticEvents/SyntheticTouchEvent.js | 4 +- .../syntheticEvents/SyntheticUIEvent.js | 4 +- .../syntheticEvents/SyntheticWheelEvent.js | 4 +- .../__tests__/SyntheticEvent-test.js | 3 +- .../__tests__/SyntheticWheelEvent-test.js | 3 +- src/renderers/shared/event/EventPluginHub.js | 6 ++- .../eventPlugins/ResponderEventPlugin.js | 39 +++++++++----- .../eventPlugins/ResponderSyntheticEvent.js | 4 +- .../__tests__/ResponderEventPlugin-test.js | 14 +++-- .../reconciler/ReactEventEmitterMixin.js | 7 +-- src/shared/utils/PooledClass.js | 12 +++++ src/test/ReactTestUtils.js | 3 +- 27 files changed, 167 insertions(+), 68 deletions(-) diff --git a/src/renderers/dom/client/ReactEventListener.js b/src/renderers/dom/client/ReactEventListener.js index b7577c8619efb..e30bd77d47465 100644 --- a/src/renderers/dom/client/ReactEventListener.js +++ b/src/renderers/dom/client/ReactEventListener.js @@ -23,6 +23,8 @@ var assign = require('Object.assign'); var getEventTarget = require('getEventTarget'); var getUnboundedScrollPosition = require('getUnboundedScrollPosition'); +var DOCUMENT_FRAGMENT_NODE_TYPE = 11; + /** * Finds the parent React component of `node`. * @@ -60,6 +62,17 @@ PooledClass.addPoolingTo( ); function handleTopLevelImpl(bookKeeping) { + if (bookKeeping.nativeEvent.path) { + // New browsers have a path attribute on native events + handleTopLevelWithPath(bookKeeping); + } else { + // Legacy browsers don't have a path attribute on native events + handleTopLevelWithoutPath(bookKeeping); + } +} + +// Legacy browsers don't have a path attribute on native events +function handleTopLevelWithoutPath(bookKeeping) { var topLevelTarget = ReactMount.getFirstReactDOM( getEventTarget(bookKeeping.nativeEvent) ) || window; @@ -81,11 +94,47 @@ function handleTopLevelImpl(bookKeeping) { bookKeeping.topLevelType, topLevelTarget, topLevelTargetID, - bookKeeping.nativeEvent + bookKeeping.nativeEvent, + getEventTarget(bookKeeping.nativeEvent) ); } } +// New browsers have a path attribute on native events +function handleTopLevelWithPath(bookKeeping) { + var path = bookKeeping.nativeEvent.path; + var currentNativeTarget = path[0]; + for (var i = 0; i < path.length; i++) { + var currentPathElement = path[i]; + var currentPathElemenId = ReactMount.getID(currentPathElement); + if (currentPathElement.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE) { + currentNativeTarget = path[i + 1]; + } + if (ReactMount.isRenderedByReact(currentPathElement)) { + var newRootId = ReactInstanceHandles.getReactRootIDFromNodeID( + currentPathElemenId + ); + bookKeeping.ancestors.push(currentPathElement); + + var topLevelTargetID = ReactMount.getID(currentPathElement) || ''; + ReactEventListener._handleTopLevel( + bookKeeping.topLevelType, + currentPathElement, + topLevelTargetID, + bookKeeping.nativeEvent, + currentNativeTarget + ); + + // Jump to the root of this React render tree + while (currentPathElemenId !== newRootId) { + i++; + currentPathElement = path[i]; + currentPathElemenId = ReactMount.getID(currentPathElement); + } + } + } +} + function scrollValueMonitor(cb) { var scrollPosition = getUnboundedScrollPosition(window); cb(scrollPosition); diff --git a/src/renderers/dom/client/eventPlugins/EnterLeaveEventPlugin.js b/src/renderers/dom/client/eventPlugins/EnterLeaveEventPlugin.js index dcc9bd68e04a5..142b00eaf183d 100644 --- a/src/renderers/dom/client/eventPlugins/EnterLeaveEventPlugin.js +++ b/src/renderers/dom/client/eventPlugins/EnterLeaveEventPlugin.js @@ -63,7 +63,8 @@ var EnterLeaveEventPlugin = { topLevelType, topLevelTarget, topLevelTargetID, - nativeEvent) { + nativeEvent, + nativeEventTarget) { if (topLevelType === topLevelTypes.topMouseOver && (nativeEvent.relatedTarget || nativeEvent.fromElement)) { return null; @@ -110,7 +111,8 @@ var EnterLeaveEventPlugin = { var leave = SyntheticMouseEvent.getPooled( eventTypes.mouseLeave, fromID, - nativeEvent + nativeEvent, + nativeEventTarget ); leave.type = 'mouseleave'; leave.target = from; @@ -119,7 +121,8 @@ var EnterLeaveEventPlugin = { var enter = SyntheticMouseEvent.getPooled( eventTypes.mouseEnter, toID, - nativeEvent + nativeEvent, + nativeEventTarget ); enter.type = 'mouseenter'; enter.target = to; diff --git a/src/renderers/dom/client/eventPlugins/SelectEventPlugin.js b/src/renderers/dom/client/eventPlugins/SelectEventPlugin.js index 6ba98bce68432..92938f9648496 100644 --- a/src/renderers/dom/client/eventPlugins/SelectEventPlugin.js +++ b/src/renderers/dom/client/eventPlugins/SelectEventPlugin.js @@ -92,7 +92,7 @@ function getSelection(node) { * @param {object} nativeEvent * @return {?SyntheticEvent} */ -function constructSelectEvent(nativeEvent) { +function constructSelectEvent(nativeEvent, nativeEventTarget) { // Ensure we have the right element, and that the user is not dragging a // selection (this matches native `select` event behavior). In HTML5, select // fires only on input and textarea thus if there's no focused element we @@ -111,7 +111,8 @@ function constructSelectEvent(nativeEvent) { var syntheticEvent = SyntheticEvent.getPooled( eventTypes.select, activeElementID, - nativeEvent + nativeEvent, + nativeEventTarget ); syntheticEvent.type = 'select'; @@ -155,8 +156,8 @@ var SelectEventPlugin = { topLevelType, topLevelTarget, topLevelTargetID, - nativeEvent) { - + nativeEvent, + nativeEventTarget) { if (!hasListener) { return null; } @@ -185,7 +186,7 @@ var SelectEventPlugin = { case topLevelTypes.topContextMenu: case topLevelTypes.topMouseUp: mouseDown = false; - return constructSelectEvent(nativeEvent); + return constructSelectEvent(nativeEvent, nativeEventTarget); // Chrome and IE fire non-standard event when selection is changed (and // sometimes when it hasn't). @@ -196,7 +197,7 @@ var SelectEventPlugin = { case topLevelTypes.topSelectionChange: case topLevelTypes.topKeyDown: case topLevelTypes.topKeyUp: - return constructSelectEvent(nativeEvent); + return constructSelectEvent(nativeEvent, nativeEventTarget); } return null; diff --git a/src/renderers/dom/client/eventPlugins/SimpleEventPlugin.js b/src/renderers/dom/client/eventPlugins/SimpleEventPlugin.js index aa136662d6c0e..53d36144f6c1f 100644 --- a/src/renderers/dom/client/eventPlugins/SimpleEventPlugin.js +++ b/src/renderers/dom/client/eventPlugins/SimpleEventPlugin.js @@ -334,7 +334,8 @@ var SimpleEventPlugin = { topLevelType, topLevelTarget, topLevelTargetID, - nativeEvent) { + nativeEvent, + nativeEventTarget) { var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType]; if (!dispatchConfig) { return null; @@ -418,7 +419,8 @@ var SimpleEventPlugin = { var event = EventConstructor.getPooled( dispatchConfig, topLevelTargetID, - nativeEvent + nativeEvent, + nativeEventTarget ); EventPropagators.accumulateTwoPhaseDispatches(event); return event; diff --git a/src/renderers/dom/client/eventPlugins/TapEventPlugin.js b/src/renderers/dom/client/eventPlugins/TapEventPlugin.js index 8e3ad4a5aa5e7..794d5ee8ba7c6 100644 --- a/src/renderers/dom/client/eventPlugins/TapEventPlugin.js +++ b/src/renderers/dom/client/eventPlugins/TapEventPlugin.js @@ -101,7 +101,8 @@ var TapEventPlugin = { topLevelType, topLevelTarget, topLevelTargetID, - nativeEvent) { + nativeEvent, + nativeEventTarget) { if (!isStartish(topLevelType) && !isEndish(topLevelType)) { return null; } @@ -122,7 +123,8 @@ var TapEventPlugin = { event = SyntheticUIEvent.getPooled( eventTypes.touchTap, topLevelTargetID, - nativeEvent + nativeEvent, + nativeEventTarget ); } if (isStartish(topLevelType)) { diff --git a/src/renderers/dom/client/eventPlugins/__tests__/EnterLeaveEventPlugin-test.js b/src/renderers/dom/client/eventPlugins/__tests__/EnterLeaveEventPlugin-test.js index 23a3da0ce3ccc..bae68b94f0cf5 100644 --- a/src/renderers/dom/client/eventPlugins/__tests__/EnterLeaveEventPlugin-test.js +++ b/src/renderers/dom/client/eventPlugins/__tests__/EnterLeaveEventPlugin-test.js @@ -48,7 +48,8 @@ describe('EnterLeaveEventPlugin', function() { topLevelTypes.topMouseOver, div, ReactMount.getID(div), - {target: div} + {target: div}, + div ); expect(extracted.length).toBe(2); diff --git a/src/renderers/dom/client/eventPlugins/__tests__/SelectEventPlugin-test.js b/src/renderers/dom/client/eventPlugins/__tests__/SelectEventPlugin-test.js index 7a9a049405b62..ce201525b6dbb 100644 --- a/src/renderers/dom/client/eventPlugins/__tests__/SelectEventPlugin-test.js +++ b/src/renderers/dom/client/eventPlugins/__tests__/SelectEventPlugin-test.js @@ -30,7 +30,8 @@ describe('SelectEventPlugin', function() { topLevelEvent, node, ReactMount.getID(node), - {target: node} + {target: node}, + node ); } diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticClipboardEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticClipboardEvent.js index d606534e17c53..fe80b72f30120 100644 --- a/src/renderers/dom/client/syntheticEvents/SyntheticClipboardEvent.js +++ b/src/renderers/dom/client/syntheticEvents/SyntheticClipboardEvent.js @@ -34,8 +34,8 @@ var ClipboardEventInterface = { * @param {object} nativeEvent Native browser event. * @extends {SyntheticUIEvent} */ -function SyntheticClipboardEvent(dispatchConfig, dispatchMarker, nativeEvent) { - SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); +function SyntheticClipboardEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); } SyntheticEvent.augmentClass(SyntheticClipboardEvent, ClipboardEventInterface); diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticCompositionEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticCompositionEvent.js index d1ecb7c6daacf..159c723f27154 100644 --- a/src/renderers/dom/client/syntheticEvents/SyntheticCompositionEvent.js +++ b/src/renderers/dom/client/syntheticEvents/SyntheticCompositionEvent.js @@ -31,8 +31,9 @@ var CompositionEventInterface = { function SyntheticCompositionEvent( dispatchConfig, dispatchMarker, - nativeEvent) { - SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); + nativeEvent, + nativeEventTarget) { + SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); } SyntheticEvent.augmentClass( diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticDragEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticDragEvent.js index d3bf1af162fef..7ab5e247c4a50 100644 --- a/src/renderers/dom/client/syntheticEvents/SyntheticDragEvent.js +++ b/src/renderers/dom/client/syntheticEvents/SyntheticDragEvent.js @@ -28,8 +28,8 @@ var DragEventInterface = { * @param {object} nativeEvent Native browser event. * @extends {SyntheticUIEvent} */ -function SyntheticDragEvent(dispatchConfig, dispatchMarker, nativeEvent) { - SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); +function SyntheticDragEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); } SyntheticMouseEvent.augmentClass(SyntheticDragEvent, DragEventInterface); diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticEvent.js index 088326ccf8e3f..b9fd7a678e292 100644 --- a/src/renderers/dom/client/syntheticEvents/SyntheticEvent.js +++ b/src/renderers/dom/client/syntheticEvents/SyntheticEvent.js @@ -16,15 +16,14 @@ var PooledClass = require('PooledClass'); var assign = require('Object.assign'); var emptyFunction = require('emptyFunction'); -var getEventTarget = require('getEventTarget'); /** * @interface Event * @see http://www.w3.org/TR/DOM-Level-3-Events/ */ var EventInterface = { + path: null, type: null, - target: getEventTarget, // currentTarget is set when dispatching; no use in copying it here currentTarget: emptyFunction.thatReturnsNull, eventPhase: null, @@ -54,10 +53,12 @@ var EventInterface = { * @param {string} dispatchMarker Marker identifying the event target. * @param {object} nativeEvent Native browser event. */ -function SyntheticEvent(dispatchConfig, dispatchMarker, nativeEvent) { +function SyntheticEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { this.dispatchConfig = dispatchConfig; this.dispatchMarker = dispatchMarker; this.nativeEvent = nativeEvent; + this.target = nativeEventTarget; + this.currentTarget = nativeEventTarget; var Interface = this.constructor.Interface; for (var propName in Interface) { @@ -156,9 +157,9 @@ SyntheticEvent.augmentClass = function(Class, Interface) { Class.Interface = assign({}, Super.Interface, Interface); Class.augmentClass = Super.augmentClass; - PooledClass.addPoolingTo(Class, PooledClass.threeArgumentPooler); + PooledClass.addPoolingTo(Class, PooledClass.fourArgumentPooler); }; -PooledClass.addPoolingTo(SyntheticEvent, PooledClass.threeArgumentPooler); +PooledClass.addPoolingTo(SyntheticEvent, PooledClass.fourArgumentPooler); module.exports = SyntheticEvent; diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticFocusEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticFocusEvent.js index 72b449b74d2c4..396a69e957d96 100644 --- a/src/renderers/dom/client/syntheticEvents/SyntheticFocusEvent.js +++ b/src/renderers/dom/client/syntheticEvents/SyntheticFocusEvent.js @@ -28,8 +28,8 @@ var FocusEventInterface = { * @param {object} nativeEvent Native browser event. * @extends {SyntheticUIEvent} */ -function SyntheticFocusEvent(dispatchConfig, dispatchMarker, nativeEvent) { - SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); +function SyntheticFocusEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); } SyntheticUIEvent.augmentClass(SyntheticFocusEvent, FocusEventInterface); diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticInputEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticInputEvent.js index 7444f3400bad9..0ee7407748457 100644 --- a/src/renderers/dom/client/syntheticEvents/SyntheticInputEvent.js +++ b/src/renderers/dom/client/syntheticEvents/SyntheticInputEvent.js @@ -32,8 +32,9 @@ var InputEventInterface = { function SyntheticInputEvent( dispatchConfig, dispatchMarker, - nativeEvent) { - SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); + nativeEvent, + nativeEventTarget) { + SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); } SyntheticEvent.augmentClass( diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticKeyboardEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticKeyboardEvent.js index e8dbf3aee9d37..8a03e60c46437 100644 --- a/src/renderers/dom/client/syntheticEvents/SyntheticKeyboardEvent.js +++ b/src/renderers/dom/client/syntheticEvents/SyntheticKeyboardEvent.js @@ -76,8 +76,8 @@ var KeyboardEventInterface = { * @param {object} nativeEvent Native browser event. * @extends {SyntheticUIEvent} */ -function SyntheticKeyboardEvent(dispatchConfig, dispatchMarker, nativeEvent) { - SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); +function SyntheticKeyboardEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); } SyntheticUIEvent.augmentClass(SyntheticKeyboardEvent, KeyboardEventInterface); diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticMouseEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticMouseEvent.js index 6aab328c6d3bb..d1d1ab6c5ef16 100644 --- a/src/renderers/dom/client/syntheticEvents/SyntheticMouseEvent.js +++ b/src/renderers/dom/client/syntheticEvents/SyntheticMouseEvent.js @@ -72,8 +72,8 @@ var MouseEventInterface = { * @param {object} nativeEvent Native browser event. * @extends {SyntheticUIEvent} */ -function SyntheticMouseEvent(dispatchConfig, dispatchMarker, nativeEvent) { - SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); +function SyntheticMouseEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); } SyntheticUIEvent.augmentClass(SyntheticMouseEvent, MouseEventInterface); diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticTouchEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticTouchEvent.js index 221a7476a2fc7..4c4b428c13bc8 100644 --- a/src/renderers/dom/client/syntheticEvents/SyntheticTouchEvent.js +++ b/src/renderers/dom/client/syntheticEvents/SyntheticTouchEvent.js @@ -37,8 +37,8 @@ var TouchEventInterface = { * @param {object} nativeEvent Native browser event. * @extends {SyntheticUIEvent} */ -function SyntheticTouchEvent(dispatchConfig, dispatchMarker, nativeEvent) { - SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); +function SyntheticTouchEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); } SyntheticUIEvent.augmentClass(SyntheticTouchEvent, TouchEventInterface); diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticUIEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticUIEvent.js index 2fe96fd5b1d9b..fa32b1fd79460 100644 --- a/src/renderers/dom/client/syntheticEvents/SyntheticUIEvent.js +++ b/src/renderers/dom/client/syntheticEvents/SyntheticUIEvent.js @@ -51,8 +51,8 @@ var UIEventInterface = { * @param {object} nativeEvent Native browser event. * @extends {SyntheticEvent} */ -function SyntheticUIEvent(dispatchConfig, dispatchMarker, nativeEvent) { - SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); +function SyntheticUIEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); } SyntheticEvent.augmentClass(SyntheticUIEvent, UIEventInterface); diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticWheelEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticWheelEvent.js index a5b4f1512aa20..672e2746aefc4 100644 --- a/src/renderers/dom/client/syntheticEvents/SyntheticWheelEvent.js +++ b/src/renderers/dom/client/syntheticEvents/SyntheticWheelEvent.js @@ -50,8 +50,8 @@ var WheelEventInterface = { * @param {object} nativeEvent Native browser event. * @extends {SyntheticMouseEvent} */ -function SyntheticWheelEvent(dispatchConfig, dispatchMarker, nativeEvent) { - SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); +function SyntheticWheelEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); } SyntheticMouseEvent.augmentClass(SyntheticWheelEvent, WheelEventInterface); diff --git a/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticEvent-test.js b/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticEvent-test.js index df6b710b5e533..e5ef1af50991e 100644 --- a/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticEvent-test.js +++ b/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticEvent-test.js @@ -20,7 +20,8 @@ describe('SyntheticEvent', function() { SyntheticEvent = require('SyntheticEvent'); createEvent = function(nativeEvent) { - return SyntheticEvent.getPooled({}, '', nativeEvent); + var target = require('getEventTarget')(nativeEvent); + return SyntheticEvent.getPooled({}, '', nativeEvent, target); }; }); diff --git a/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticWheelEvent-test.js b/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticWheelEvent-test.js index 212467b007dce..e80a2bff6e3cf 100644 --- a/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticWheelEvent-test.js +++ b/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticWheelEvent-test.js @@ -20,7 +20,8 @@ describe('SyntheticWheelEvent', function() { SyntheticWheelEvent = require('SyntheticWheelEvent'); createEvent = function(nativeEvent) { - return SyntheticWheelEvent.getPooled({}, '', nativeEvent); + var target = require('getEventTarget')(nativeEvent); + return SyntheticWheelEvent.getPooled({}, '', nativeEvent, target); }; }); diff --git a/src/renderers/shared/event/EventPluginHub.js b/src/renderers/shared/event/EventPluginHub.js index 543fd496fcd27..801a06b13fbb3 100644 --- a/src/renderers/shared/event/EventPluginHub.js +++ b/src/renderers/shared/event/EventPluginHub.js @@ -230,7 +230,8 @@ var EventPluginHub = { topLevelType, topLevelTarget, topLevelTargetID, - nativeEvent) { + nativeEvent, + nativeEventTarget) { var events; var plugins = EventPluginRegistry.plugins; for (var i = 0; i < plugins.length; i++) { @@ -241,7 +242,8 @@ var EventPluginHub = { topLevelType, topLevelTarget, topLevelTargetID, - nativeEvent + nativeEvent, + nativeEventTarget ); if (extractedEvents) { events = accumulateInto(events, extractedEvents); diff --git a/src/renderers/shared/event/eventPlugins/ResponderEventPlugin.js b/src/renderers/shared/event/eventPlugins/ResponderEventPlugin.js index 6d01a5e513860..51d875bdf39b2 100644 --- a/src/renderers/shared/event/eventPlugins/ResponderEventPlugin.js +++ b/src/renderers/shared/event/eventPlugins/ResponderEventPlugin.js @@ -325,7 +325,8 @@ to return true:wantsResponderID| | function setResponderAndExtractTransfer( topLevelType, topLevelTargetID, - nativeEvent) { + nativeEvent, + nativeEventTarget) { var shouldSetEventType = isStartish(topLevelType) ? eventTypes.startShouldSetResponder : isMoveish(topLevelType) ? eventTypes.moveShouldSetResponder : @@ -346,7 +347,8 @@ function setResponderAndExtractTransfer( var shouldSetEvent = ResponderSyntheticEvent.getPooled( shouldSetEventType, bubbleShouldSetFrom, - nativeEvent + nativeEvent, + nativeEventTarget ); shouldSetEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; if (skipOverBubbleShouldSetFrom) { @@ -366,7 +368,8 @@ function setResponderAndExtractTransfer( var grantEvent = ResponderSyntheticEvent.getPooled( eventTypes.responderGrant, wantsResponderID, - nativeEvent + nativeEvent, + nativeEventTarget ); grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; @@ -376,7 +379,8 @@ function setResponderAndExtractTransfer( var terminationRequestEvent = ResponderSyntheticEvent.getPooled( eventTypes.responderTerminationRequest, responderID, - nativeEvent + nativeEvent, + nativeEventTarget ); terminationRequestEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; EventPropagators.accumulateDirectDispatches(terminationRequestEvent); @@ -391,7 +395,8 @@ function setResponderAndExtractTransfer( var terminateEvent = ResponderSyntheticEvent.getPooled( terminateType, responderID, - nativeEvent + nativeEvent, + nativeEventTarget ); terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; EventPropagators.accumulateDirectDispatches(terminateEvent); @@ -401,7 +406,8 @@ function setResponderAndExtractTransfer( var rejectEvent = ResponderSyntheticEvent.getPooled( eventTypes.responderReject, wantsResponderID, - nativeEvent + nativeEvent, + nativeEventTarget ); rejectEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; EventPropagators.accumulateDirectDispatches(rejectEvent); @@ -487,8 +493,8 @@ var ResponderEventPlugin = { topLevelType, topLevelTarget, topLevelTargetID, - nativeEvent) { - + nativeEvent, + nativeEventTarget) { if (isStartish(topLevelType)) { trackedTouchCount += 1; } else if (isEndish(topLevelType)) { @@ -499,10 +505,14 @@ var ResponderEventPlugin = { ); } - ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent); + ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent, nativeEventTarget); var extracted = canTriggerTransfer(topLevelType, topLevelTargetID) ? - setResponderAndExtractTransfer(topLevelType, topLevelTargetID, nativeEvent) : + setResponderAndExtractTransfer( + topLevelType, + topLevelTargetID, + nativeEvent, + nativeEventTarget) : null; // Responder may or may not have transfered on a new touch start/move. // Regardless, whoever is the responder after any potential transfer, we @@ -525,7 +535,12 @@ var ResponderEventPlugin = { if (incrementalTouch) { var gesture = - ResponderSyntheticEvent.getPooled(incrementalTouch, responderID, nativeEvent); + ResponderSyntheticEvent.getPooled( + incrementalTouch, + responderID, + nativeEvent, + nativeEventTarget + ); gesture.touchHistory = ResponderTouchHistoryStore.touchHistory; EventPropagators.accumulateDirectDispatches(gesture); extracted = accumulate(extracted, gesture); @@ -545,7 +560,7 @@ var ResponderEventPlugin = { null; if (finalTouch) { var finalEvent = - ResponderSyntheticEvent.getPooled(finalTouch, responderID, nativeEvent); + ResponderSyntheticEvent.getPooled(finalTouch, responderID, nativeEvent, nativeEventTarget); finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; EventPropagators.accumulateDirectDispatches(finalEvent); extracted = accumulate(extracted, finalEvent); diff --git a/src/renderers/shared/event/eventPlugins/ResponderSyntheticEvent.js b/src/renderers/shared/event/eventPlugins/ResponderSyntheticEvent.js index 882394f5c4a71..f91dd91fe2fe9 100644 --- a/src/renderers/shared/event/eventPlugins/ResponderSyntheticEvent.js +++ b/src/renderers/shared/event/eventPlugins/ResponderSyntheticEvent.js @@ -31,8 +31,8 @@ var ResponderEventInterface = { * @param {object} nativeEvent Native event. * @extends {SyntheticEvent} */ -function ResponderSyntheticEvent(dispatchConfig, dispatchMarker, nativeEvent) { - SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent); +function ResponderSyntheticEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) { + SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); } SyntheticEvent.augmentClass(ResponderSyntheticEvent, ResponderEventInterface); diff --git a/src/renderers/shared/event/eventPlugins/__tests__/ResponderEventPlugin-test.js b/src/renderers/shared/event/eventPlugins/__tests__/ResponderEventPlugin-test.js index b587877b73dc6..62deb238dc0fc 100644 --- a/src/renderers/shared/event/eventPlugins/__tests__/ResponderEventPlugin-test.js +++ b/src/renderers/shared/event/eventPlugins/__tests__/ResponderEventPlugin-test.js @@ -67,7 +67,7 @@ var antiSubsequence = function(arr, indices) { * @param allTouchHandles */ var _touchConfig = - function(topType, targetNodeHandle, allTouchHandles, changedIndices) { + function(topType, targetNodeHandle, allTouchHandles, changedIndices, eventTarget) { var allTouchObjects = allTouchHandles.map(touch); var changedTouchObjects = subsequence(allTouchObjects, changedIndices); var activeTouchObjects = @@ -112,7 +112,8 @@ var startConfig = function(nodeHandle, allTouchHandles, changedIndices) { topLevelTypes.topTouchStart, nodeHandle, allTouchHandles, - changedIndices + changedIndices, + nodeHandle ); }; @@ -124,7 +125,8 @@ var moveConfig = function(nodeHandle, allTouchHandles, changedIndices) { topLevelTypes.topTouchMove, nodeHandle, allTouchHandles, - changedIndices + changedIndices, + nodeHandle ); }; @@ -136,7 +138,8 @@ var endConfig = function(nodeHandle, allTouchHandles, changedIndices) { topLevelTypes.topTouchEnd, nodeHandle, allTouchHandles, - changedIndices + changedIndices, + nodeHandle ); }; @@ -290,7 +293,8 @@ var run = function(config, hierarchyConfig, nativeEventConfig) { nativeEventConfig.topLevelType, nativeEventConfig.target, nativeEventConfig.targetID, - nativeEventConfig.nativeEvent + nativeEventConfig.nativeEvent, + nativeEventConfig.target ); // At this point the negotiation events have been dispatched as part of the diff --git a/src/renderers/shared/reconciler/ReactEventEmitterMixin.js b/src/renderers/shared/reconciler/ReactEventEmitterMixin.js index 561ba692381d9..a865fda7a445c 100644 --- a/src/renderers/shared/reconciler/ReactEventEmitterMixin.js +++ b/src/renderers/shared/reconciler/ReactEventEmitterMixin.js @@ -33,14 +33,15 @@ var ReactEventEmitterMixin = { topLevelType, topLevelTarget, topLevelTargetID, - nativeEvent) { + nativeEvent, + nativeEventTarget) { var events = EventPluginHub.extractEvents( topLevelType, topLevelTarget, topLevelTargetID, - nativeEvent + nativeEvent, + nativeEventTarget ); - runEventQueueInBatch(events); }, }; diff --git a/src/shared/utils/PooledClass.js b/src/shared/utils/PooledClass.js index a582d9ded49dc..74a6e4cb16eac 100644 --- a/src/shared/utils/PooledClass.js +++ b/src/shared/utils/PooledClass.js @@ -53,6 +53,17 @@ var threeArgumentPooler = function(a1, a2, a3) { } }; +var fourArgumentPooler = function(a1, a2, a3, a4) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, a1, a2, a3, a4); + return instance; + } else { + return new Klass(a1, a2, a3, a4); + } +}; + var fiveArgumentPooler = function(a1, a2, a3, a4, a5) { var Klass = this; if (Klass.instancePool.length) { @@ -106,6 +117,7 @@ var PooledClass = { oneArgumentPooler: oneArgumentPooler, twoArgumentPooler: twoArgumentPooler, threeArgumentPooler: threeArgumentPooler, + fourArgumentPooler: fourArgumentPooler, fiveArgumentPooler: fiveArgumentPooler, }; diff --git a/src/test/ReactTestUtils.js b/src/test/ReactTestUtils.js index ee8bfbc7f26c1..560ba653b9a9d 100644 --- a/src/test/ReactTestUtils.js +++ b/src/test/ReactTestUtils.js @@ -450,7 +450,8 @@ function makeSimulator(eventType) { var event = new SyntheticEvent( dispatchConfig, ReactMount.getID(node), - fakeNativeEvent + fakeNativeEvent, + node ); assign(event, eventData);