mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Use Synthetic Events
Swaps out usage of `AbstractEvent` with `SyntheticEvent` (and subclasses).
This commit is contained in:
committed by
Paul O’Shannessy
parent
03464dc148
commit
88e90d5601
+2
-2
@@ -229,7 +229,7 @@ describe('ReactEventEmitter', function() {
|
||||
|
||||
it('should invoke handlers that were removed while bubbling', function() {
|
||||
var handleParentClick = mocks.getMockFunction();
|
||||
var handleChildClick = function(abstractEvent) {
|
||||
var handleChildClick = function(event) {
|
||||
ReactEventEmitter.deleteAllListeners(PARENT.id);
|
||||
};
|
||||
ReactEventEmitter.putListener(CHILD.id, ON_CLICK_KEY, handleChildClick);
|
||||
@@ -240,7 +240,7 @@ describe('ReactEventEmitter', function() {
|
||||
|
||||
it('should not invoke newly inserted handlers while bubbling', function() {
|
||||
var handleParentClick = mocks.getMockFunction();
|
||||
var handleChildClick = function(abstractEvent) {
|
||||
var handleChildClick = function(event) {
|
||||
ReactEventEmitter.putListener(PARENT.id, ON_CLICK_KEY, handleParentClick);
|
||||
};
|
||||
ReactEventEmitter.putListener(CHILD.id, ON_CLICK_KEY, handleChildClick);
|
||||
@@ -1,253 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @providesModule AbstractEvent
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var BrowserEnv = require('BrowserEnv');
|
||||
var PooledClass = require('PooledClass');
|
||||
var TouchEventUtils = require('TouchEventUtils');
|
||||
|
||||
var emptyFunction = require('emptyFunction');
|
||||
|
||||
var MAX_POOL_SIZE = 20;
|
||||
|
||||
/**
|
||||
* AbstractEvent copy constructor. @see `PooledClass`. Provides a single place
|
||||
* to define all cross browser normalization of DOM events. Does not attempt to
|
||||
* extend a native event, rather creates a completely new object that has a
|
||||
* reference to the nativeEvent through .nativeEvent member. The property .data
|
||||
* should hold all data that is extracted from the event in a cross browser
|
||||
* manner. Application code should use the data field when possible, not the
|
||||
* unreliable native event.
|
||||
*/
|
||||
function AbstractEvent(
|
||||
reactEventType,
|
||||
reactTargetID, // Allows the abstract target to differ from native.
|
||||
nativeEvent,
|
||||
data) {
|
||||
this.reactEventType = reactEventType;
|
||||
this.reactTargetID = reactTargetID || '';
|
||||
this.nativeEvent = nativeEvent;
|
||||
this.data = data;
|
||||
// TODO: Deprecate storing target - doesn't always make sense for some types
|
||||
this.target = nativeEvent && nativeEvent.target;
|
||||
|
||||
/**
|
||||
* As a performance optimization, we tag the existing event with the listeners
|
||||
* (or listener [singular] if only one). This avoids having to package up an
|
||||
* abstract event along with the set of listeners into a wrapping "dispatch"
|
||||
* object. No one should ever read this property except event system and
|
||||
* plugin/dispatcher code. We also tag the abstract event with a parallel
|
||||
* ID array. _dispatchListeners[i] is being dispatched to a DOM node at ID
|
||||
* _dispatchIDs[i]. The lengths should never, ever, ever be different.
|
||||
*/
|
||||
this._dispatchListeners = null;
|
||||
this._dispatchIDs = null;
|
||||
|
||||
this.isPropagationStopped = false;
|
||||
this.isPersistent = emptyFunction.thatReturnsFalse;
|
||||
}
|
||||
|
||||
/** `PooledClass` looks for this. */
|
||||
AbstractEvent.poolSize = MAX_POOL_SIZE;
|
||||
|
||||
/**
|
||||
* `PooledClass` looks for `destructor` on each instance it releases. We need to
|
||||
* ensure that we remove all references to listeners which could trap large
|
||||
* amounts of memory in their closures.
|
||||
*/
|
||||
AbstractEvent.prototype.destructor = function() {
|
||||
this.target = null;
|
||||
this._dispatchListeners = null;
|
||||
this._dispatchIDs = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Enhance the `AbstractEvent` class to have pooling abilities. We instruct
|
||||
* `PooledClass` that our copy constructor accepts five arguments (this is just
|
||||
* a performance optimization). These objects are instantiated frequently.
|
||||
*/
|
||||
PooledClass.addPoolingTo(AbstractEvent, PooledClass.fiveArgumentPooler);
|
||||
|
||||
AbstractEvent.prototype.stopPropagation = function() {
|
||||
this.isPropagationStopped = true;
|
||||
if (this.nativeEvent.stopPropagation) {
|
||||
this.nativeEvent.stopPropagation();
|
||||
}
|
||||
// IE8 only understands cancelBubble, not stopPropagation().
|
||||
this.nativeEvent.cancelBubble = true;
|
||||
};
|
||||
|
||||
AbstractEvent.prototype.preventDefault = function() {
|
||||
AbstractEvent.preventDefaultOnNativeEvent(this.nativeEvent);
|
||||
};
|
||||
|
||||
/**
|
||||
* We clear out all dispatched `AbstractEvent`s after each event loop, adding
|
||||
* them back into the pool. This allows a way to hold onto a reference that
|
||||
* won't be added back into the pool.
|
||||
*/
|
||||
AbstractEvent.prototype.persist = function() {
|
||||
this.isPersistent = emptyFunction.thatReturnsTrue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility function for preventing default in cross browser manner.
|
||||
*/
|
||||
AbstractEvent.preventDefaultOnNativeEvent = function(nativeEvent) {
|
||||
if (nativeEvent.preventDefault) {
|
||||
nativeEvent.preventDefault();
|
||||
} else {
|
||||
nativeEvent.returnValue = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Element} target The target element.
|
||||
*/
|
||||
AbstractEvent.normalizeScrollDataFromTarget = function(target) {
|
||||
return {
|
||||
scrollTop: target.scrollTop,
|
||||
scrollLeft: target.scrollLeft,
|
||||
clientWidth: target.clientWidth,
|
||||
clientHeight: target.clientHeight,
|
||||
scrollHeight: target.scrollHeight,
|
||||
scrollWidth: target.scrollWidth
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* There are some normalizations that need to happen for various browsers. In
|
||||
* addition to replacing the general event fixing with a framework such as
|
||||
* jquery, we need to normalize mouse events here. Code below is mostly borrowed
|
||||
* from: jScrollPane/script/jquery.mousewheel.js
|
||||
*/
|
||||
AbstractEvent.normalizeMouseWheelData = function(nativeEvent) {
|
||||
var delta = 0;
|
||||
var deltaX = 0;
|
||||
var deltaY = 0;
|
||||
|
||||
/* traditional scroll wheel data */
|
||||
if ( nativeEvent.wheelDelta ) { delta = nativeEvent.wheelDelta/120; }
|
||||
if ( nativeEvent.detail ) { delta = -nativeEvent.detail/3; }
|
||||
|
||||
/* Multidimensional scroll (touchpads) with deltas */
|
||||
deltaY = delta;
|
||||
|
||||
/* Gecko based browsers */
|
||||
if (nativeEvent.axis !== undefined &&
|
||||
nativeEvent.axis === nativeEvent.HORIZONTAL_AXIS ) {
|
||||
deltaY = 0;
|
||||
deltaX = -delta;
|
||||
}
|
||||
|
||||
/* Webkit based browsers */
|
||||
if (nativeEvent.wheelDeltaY !== undefined ) {
|
||||
deltaY = nativeEvent.wheelDeltaY/120;
|
||||
}
|
||||
if (nativeEvent.wheelDeltaX !== undefined ) {
|
||||
deltaX = -nativeEvent.wheelDeltaX/120;
|
||||
}
|
||||
|
||||
return { delta: delta, deltaX: deltaX, deltaY: deltaY };
|
||||
};
|
||||
|
||||
/**
|
||||
* I <3 Quirksmode.org:
|
||||
* http://www.quirksmode.org/js/events_properties.html
|
||||
*/
|
||||
AbstractEvent.isNativeClickEventRightClick = function(nativeEvent) {
|
||||
return nativeEvent.which ? nativeEvent.which === 3 :
|
||||
nativeEvent.button ? nativeEvent.button === 2 :
|
||||
false;
|
||||
};
|
||||
|
||||
AbstractEvent.normalizePointerData = function(nativeEvent) {
|
||||
return {
|
||||
globalX: AbstractEvent.eventPageX(nativeEvent),
|
||||
globalY: AbstractEvent.eventPageY(nativeEvent),
|
||||
rightMouseButton:
|
||||
AbstractEvent.isNativeClickEventRightClick(nativeEvent)
|
||||
};
|
||||
};
|
||||
|
||||
AbstractEvent.normalizeDragEventData =
|
||||
function(nativeEvent, globalX, globalY, startX, startY) {
|
||||
return {
|
||||
globalX: globalX,
|
||||
globalY: globalY,
|
||||
startX: startX,
|
||||
startY: startY
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Warning: It is possible to move your finger on a touch surface, yet not
|
||||
* effect the `eventPageX/Y` because the touch had caused a scroll that
|
||||
* compensated for your movement. To track movements across the page, prevent
|
||||
* default to avoid scrolling, and control scrolling in javascript.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the exact position of a touch/mouse event on the page with respect to
|
||||
* the document body. The only reason why this method is needed instead of using
|
||||
* `TouchEventUtils.extractSingleTouch` is to support IE8-. Mouse events in all
|
||||
* browsers except IE8- contain a pageY. IE8 and below require clientY
|
||||
* computation:
|
||||
*
|
||||
* @param {Event} nativeEvent Native event, possibly touch or mouse.
|
||||
* @return {number} Coordinate with respect to document body.
|
||||
*/
|
||||
AbstractEvent.eventPageY = function(nativeEvent) {
|
||||
var singleTouch = TouchEventUtils.extractSingleTouch(nativeEvent);
|
||||
if (singleTouch) {
|
||||
return singleTouch.pageY;
|
||||
} else if (typeof nativeEvent.pageY !== 'undefined') {
|
||||
return nativeEvent.pageY;
|
||||
} else {
|
||||
return nativeEvent.clientY + BrowserEnv.currentPageScrollTop;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @see `AbstractEvent.eventPageY`.
|
||||
*
|
||||
* @param {Event} nativeEvent Native event, possibly touch or mouse.
|
||||
* @return {number} Coordinate with respect to document body.
|
||||
*/
|
||||
AbstractEvent.eventPageX = function(nativeEvent) {
|
||||
var singleTouch = TouchEventUtils.extractSingleTouch(nativeEvent);
|
||||
if (singleTouch) {
|
||||
return singleTouch.pageX;
|
||||
} else if (typeof nativeEvent.pageX !== 'undefined') {
|
||||
return nativeEvent.pageX;
|
||||
} else {
|
||||
return nativeEvent.clientX + BrowserEnv.currentPageScrollLeft;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
AbstractEvent.persistentCloneOf = function(abstractEvent) {
|
||||
abstractEvent.persist();
|
||||
return abstractEvent;
|
||||
};
|
||||
|
||||
module.exports = AbstractEvent;
|
||||
|
||||
@@ -65,7 +65,7 @@ var executeDispatchesAndRelease = function(event) {
|
||||
* Required. When a top-level event is fired, this method is expected to
|
||||
* extract synthetic events that will in turn be queued and dispatched.
|
||||
*
|
||||
* `abstractEventTypes` {object}
|
||||
* `eventTypes` {object}
|
||||
* Optional, plugins that fire events must publish a mapping of registration
|
||||
* names that are used to register listeners. Values of this mapping must
|
||||
* be objects that contain `registrationName` or `phasedRegistrationNames`.
|
||||
|
||||
@@ -60,7 +60,7 @@ function recomputePluginOrdering() {
|
||||
pluginName
|
||||
);
|
||||
EventPluginRegistry.plugins[pluginIndex] = PluginModule;
|
||||
var publishedEvents = PluginModule.abstractEventTypes;
|
||||
var publishedEvents = PluginModule.eventTypes;
|
||||
for (var eventName in publishedEvents) {
|
||||
invariant(
|
||||
publishEventForPlugin(publishedEvents[eventName], PluginModule),
|
||||
@@ -198,7 +198,7 @@ var EventPluginRegistry = {
|
||||
* @internal
|
||||
*/
|
||||
getPluginModuleForEvent: function(event) {
|
||||
var dispatchConfig = event.reactEventType;
|
||||
var dispatchConfig = event.dispatchConfig;
|
||||
if (dispatchConfig.registrationName) {
|
||||
return EventPluginRegistry.registrationNames[
|
||||
dispatchConfig.registrationName
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
"use strict";
|
||||
|
||||
var EventConstants = require('EventConstants');
|
||||
var AbstractEvent = require('AbstractEvent');
|
||||
|
||||
var invariant = require('invariant');
|
||||
|
||||
@@ -40,27 +39,11 @@ function isStartish(topLevelType) {
|
||||
topLevelType === topLevelTypes.topTouchStart;
|
||||
}
|
||||
|
||||
function storePageCoordsIn(obj, nativeEvent) {
|
||||
var pageX = AbstractEvent.eventPageX(nativeEvent);
|
||||
var pageY = AbstractEvent.eventPageY(nativeEvent);
|
||||
obj.pageX = pageX;
|
||||
obj.pageY = pageY;
|
||||
}
|
||||
|
||||
function eventDistance(coords, nativeEvent) {
|
||||
var pageX = AbstractEvent.eventPageX(nativeEvent);
|
||||
var pageY = AbstractEvent.eventPageY(nativeEvent);
|
||||
return Math.pow(
|
||||
Math.pow(pageX - coords.pageX, 2) + Math.pow(pageY - coords.pageY, 2),
|
||||
0.5
|
||||
);
|
||||
}
|
||||
|
||||
var validateEventDispatches;
|
||||
if (__DEV__) {
|
||||
validateEventDispatches = function(abstractEvent) {
|
||||
var dispatchListeners = abstractEvent._dispatchListeners;
|
||||
var dispatchIDs = abstractEvent._dispatchIDs;
|
||||
validateEventDispatches = function(event) {
|
||||
var dispatchListeners = event._dispatchListeners;
|
||||
var dispatchIDs = event._dispatchIDs;
|
||||
|
||||
var listenersIsArr = Array.isArray(dispatchListeners);
|
||||
var idsIsArr = Array.isArray(dispatchIDs);
|
||||
@@ -71,53 +54,52 @@ if (__DEV__) {
|
||||
|
||||
invariant(
|
||||
idsIsArr === listenersIsArr && IDsLen === listenersLen,
|
||||
'EventPluginUtils: Invalid `abstractEvent`.'
|
||||
'EventPluginUtils: Invalid `event`.'
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes `cb(abstractEvent, listener, id)`. Avoids using call if no scope is
|
||||
* Invokes `cb(event, listener, id)`. Avoids using call if no scope is
|
||||
* provided. The `(listener,id)` pair effectively forms the "dispatch" but are
|
||||
* kept separate to conserve memory.
|
||||
*/
|
||||
function forEachEventDispatch(abstractEvent, cb) {
|
||||
var dispatchListeners = abstractEvent._dispatchListeners;
|
||||
var dispatchIDs = abstractEvent._dispatchIDs;
|
||||
function forEachEventDispatch(event, cb) {
|
||||
var dispatchListeners = event._dispatchListeners;
|
||||
var dispatchIDs = event._dispatchIDs;
|
||||
if (__DEV__) {
|
||||
validateEventDispatches(abstractEvent);
|
||||
validateEventDispatches(event);
|
||||
}
|
||||
if (Array.isArray(dispatchListeners)) {
|
||||
var i;
|
||||
for (
|
||||
i = 0;
|
||||
i < dispatchListeners.length && !abstractEvent.isPropagationStopped;
|
||||
i++) {
|
||||
for (var i = 0; i < dispatchListeners.length; i++) {
|
||||
if (event.isPropagationStopped()) {
|
||||
break;
|
||||
}
|
||||
// Listeners and IDs are two parallel arrays that are always in sync.
|
||||
cb(abstractEvent, dispatchListeners[i], dispatchIDs[i]);
|
||||
cb(event, dispatchListeners[i], dispatchIDs[i]);
|
||||
}
|
||||
} else if (dispatchListeners) {
|
||||
cb(abstractEvent, dispatchListeners, dispatchIDs);
|
||||
cb(event, dispatchListeners, dispatchIDs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation of PluginModule.executeDispatch().
|
||||
* @param {AbstractEvent} AbstractEvent to handle
|
||||
* @param {SyntheticEvent} SyntheticEvent to handle
|
||||
* @param {function} Application-level callback
|
||||
* @param {string} domID DOM id to pass to the callback.
|
||||
*/
|
||||
function executeDispatch(abstractEvent, listener, domID) {
|
||||
listener(abstractEvent, domID);
|
||||
function executeDispatch(event, listener, domID) {
|
||||
listener(event, domID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard/simple iteration through an event's collected dispatches.
|
||||
*/
|
||||
function executeDispatchesInOrder(abstractEvent, executeDispatch) {
|
||||
forEachEventDispatch(abstractEvent, executeDispatch);
|
||||
abstractEvent._dispatchListeners = null;
|
||||
abstractEvent._dispatchIDs = null;
|
||||
function executeDispatchesInOrder(event, executeDispatch) {
|
||||
forEachEventDispatch(event, executeDispatch);
|
||||
event._dispatchListeners = null;
|
||||
event._dispatchIDs = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,25 +109,24 @@ function executeDispatchesInOrder(abstractEvent, executeDispatch) {
|
||||
* @returns id of the first dispatch execution who's listener returns true, or
|
||||
* null if no listener returned true.
|
||||
*/
|
||||
function executeDispatchesInOrderStopAtTrue(abstractEvent) {
|
||||
var dispatchListeners = abstractEvent._dispatchListeners;
|
||||
var dispatchIDs = abstractEvent._dispatchIDs;
|
||||
function executeDispatchesInOrderStopAtTrue(event) {
|
||||
var dispatchListeners = event._dispatchListeners;
|
||||
var dispatchIDs = event._dispatchIDs;
|
||||
if (__DEV__) {
|
||||
validateEventDispatches(abstractEvent);
|
||||
validateEventDispatches(event);
|
||||
}
|
||||
if (Array.isArray(dispatchListeners)) {
|
||||
var i;
|
||||
for (
|
||||
i = 0;
|
||||
i < dispatchListeners.length && !abstractEvent.isPropagationStopped;
|
||||
i++) {
|
||||
for (var i = 0; i < dispatchListeners.length; i++) {
|
||||
if (event.isPropagationStopped()) {
|
||||
break;
|
||||
}
|
||||
// Listeners and IDs are two parallel arrays that are always in sync.
|
||||
if (dispatchListeners[i](abstractEvent, dispatchIDs[i])) {
|
||||
if (dispatchListeners[i](event, dispatchIDs[i])) {
|
||||
return dispatchIDs[i];
|
||||
}
|
||||
}
|
||||
} else if (dispatchListeners) {
|
||||
if (dispatchListeners(abstractEvent, dispatchIDs)) {
|
||||
if (dispatchListeners(event, dispatchIDs)) {
|
||||
return dispatchIDs;
|
||||
}
|
||||
}
|
||||
@@ -161,30 +142,30 @@ function executeDispatchesInOrderStopAtTrue(abstractEvent) {
|
||||
*
|
||||
* @returns The return value of executing the single dispatch.
|
||||
*/
|
||||
function executeDirectDispatch(abstractEvent) {
|
||||
function executeDirectDispatch(event) {
|
||||
if (__DEV__) {
|
||||
validateEventDispatches(abstractEvent);
|
||||
validateEventDispatches(event);
|
||||
}
|
||||
var dispatchListener = abstractEvent._dispatchListeners;
|
||||
var dispatchID = abstractEvent._dispatchIDs;
|
||||
var dispatchListener = event._dispatchListeners;
|
||||
var dispatchID = event._dispatchIDs;
|
||||
invariant(
|
||||
!Array.isArray(dispatchListener),
|
||||
'executeDirectDispatch(...): Invalid `abstractEvent`.'
|
||||
'executeDirectDispatch(...): Invalid `event`.'
|
||||
);
|
||||
var res = dispatchListener ?
|
||||
dispatchListener(abstractEvent, dispatchID) :
|
||||
dispatchListener(event, dispatchID) :
|
||||
null;
|
||||
abstractEvent._dispatchListeners = null;
|
||||
abstractEvent._dispatchIDs = null;
|
||||
event._dispatchListeners = null;
|
||||
event._dispatchIDs = null;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {AbstractEvent} abstractEvent
|
||||
* @param {SyntheticEvent} event
|
||||
* @returns {bool} True iff number of dispatches accumulated is greater than 0.
|
||||
*/
|
||||
function hasDispatches(abstractEvent) {
|
||||
return !!abstractEvent._dispatchListeners;
|
||||
function hasDispatches(event) {
|
||||
return !!event._dispatchListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,8 +175,6 @@ var EventPluginUtils = {
|
||||
isEndish: isEndish,
|
||||
isMoveish: isMoveish,
|
||||
isStartish: isStartish,
|
||||
storePageCoordsIn: storePageCoordsIn,
|
||||
eventDistance: eventDistance,
|
||||
executeDispatchesInOrder: executeDispatchesInOrder,
|
||||
executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue,
|
||||
executeDirectDispatch: executeDirectDispatch,
|
||||
|
||||
@@ -56,19 +56,19 @@ var injection = {
|
||||
* Some event types have a notion of different registration names for different
|
||||
* "phases" of propagation. This finds listeners by a given phase.
|
||||
*/
|
||||
function listenerAtPhase(id, abstractEvent, propagationPhase) {
|
||||
function listenerAtPhase(id, event, propagationPhase) {
|
||||
var registrationName =
|
||||
abstractEvent.reactEventType.phasedRegistrationNames[propagationPhase];
|
||||
event.dispatchConfig.phasedRegistrationNames[propagationPhase];
|
||||
return getListener(id, registrationName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags an `AbstractEvent` with dispatched listeners. Creating this function
|
||||
* Tags a `SyntheticEvent` with dispatched listeners. Creating this function
|
||||
* here, allows us to not have to bind or create functions for each event.
|
||||
* Mutating the event's members allows us to not have to create a wrapping
|
||||
* "dispatch" object that pairs the event with the listener.
|
||||
*/
|
||||
function accumulateDirectionalDispatches(domID, upwards, abstractEvent) {
|
||||
function accumulateDirectionalDispatches(domID, upwards, event) {
|
||||
if (__DEV__) {
|
||||
if (!domID) {
|
||||
throw new Error('Dispatching id must not be null');
|
||||
@@ -76,11 +76,10 @@ function accumulateDirectionalDispatches(domID, upwards, abstractEvent) {
|
||||
injection.validate();
|
||||
}
|
||||
var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured;
|
||||
var listener = listenerAtPhase(domID, abstractEvent, phase);
|
||||
var listener = listenerAtPhase(domID, event, phase);
|
||||
if (listener) {
|
||||
abstractEvent._dispatchListeners =
|
||||
accumulate(abstractEvent._dispatchListeners, listener);
|
||||
abstractEvent._dispatchIDs = accumulate(abstractEvent._dispatchIDs, domID);
|
||||
event._dispatchListeners = accumulate(event._dispatchListeners, listener);
|
||||
event._dispatchIDs = accumulate(event._dispatchIDs, domID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,12 +90,12 @@ function accumulateDirectionalDispatches(domID, upwards, abstractEvent) {
|
||||
* single traversal for the entire collection of events because each event may
|
||||
* have a different target.
|
||||
*/
|
||||
function accumulateTwoPhaseDispatchesSingle(abstractEvent) {
|
||||
if (abstractEvent && abstractEvent.reactEventType.phasedRegistrationNames) {
|
||||
function accumulateTwoPhaseDispatchesSingle(event) {
|
||||
if (event && event.dispatchConfig.phasedRegistrationNames) {
|
||||
injection.InstanceHandle.traverseTwoPhase(
|
||||
abstractEvent.reactTargetID,
|
||||
event.dispatchMarker,
|
||||
accumulateDirectionalDispatches,
|
||||
abstractEvent
|
||||
event
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -105,36 +104,35 @@ function accumulateTwoPhaseDispatchesSingle(abstractEvent) {
|
||||
/**
|
||||
* Accumulates without regard to direction, does not look for phased
|
||||
* registration names. Same as `accumulateDirectDispatchesSingle` but without
|
||||
* requiring that the `reactTargetID` be the same as the dispatched ID.
|
||||
* requiring that the `dispatchMarker` be the same as the dispatched ID.
|
||||
*/
|
||||
function accumulateDispatches(id, ignoredDirection, abstractEvent) {
|
||||
if (abstractEvent && abstractEvent.reactEventType.registrationName) {
|
||||
var registrationName = abstractEvent.reactEventType.registrationName;
|
||||
function accumulateDispatches(id, ignoredDirection, event) {
|
||||
if (event && event.dispatchConfig.registrationName) {
|
||||
var registrationName = event.dispatchConfig.registrationName;
|
||||
var listener = getListener(id, registrationName);
|
||||
if (listener) {
|
||||
abstractEvent._dispatchListeners =
|
||||
accumulate(abstractEvent._dispatchListeners, listener);
|
||||
abstractEvent._dispatchIDs = accumulate(abstractEvent._dispatchIDs, id);
|
||||
event._dispatchListeners = accumulate(event._dispatchListeners, listener);
|
||||
event._dispatchIDs = accumulate(event._dispatchIDs, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accumulates dispatches on an `AbstractEvent`, but only for the
|
||||
* `reactTargetID`.
|
||||
* @param {AbstractEvent} abstractEvent
|
||||
* Accumulates dispatches on an `SyntheticEvent`, but only for the
|
||||
* `dispatchMarker`.
|
||||
* @param {SyntheticEvent} event
|
||||
*/
|
||||
function accumulateDirectDispatchesSingle(abstractEvent) {
|
||||
if (abstractEvent && abstractEvent.reactEventType.registrationName) {
|
||||
accumulateDispatches(abstractEvent.reactTargetID, null, abstractEvent);
|
||||
function accumulateDirectDispatchesSingle(event) {
|
||||
if (event && event.dispatchConfig.registrationName) {
|
||||
accumulateDispatches(event.dispatchMarker, null, event);
|
||||
}
|
||||
}
|
||||
|
||||
function accumulateTwoPhaseDispatches(abstractEvents) {
|
||||
function accumulateTwoPhaseDispatches(events) {
|
||||
if (__DEV__) {
|
||||
injection.validate();
|
||||
}
|
||||
forEachAccumulated(abstractEvents, accumulateTwoPhaseDispatchesSingle);
|
||||
forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);
|
||||
}
|
||||
|
||||
function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) {
|
||||
@@ -151,11 +149,11 @@ function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) {
|
||||
}
|
||||
|
||||
|
||||
function accumulateDirectDispatches(abstractEvents) {
|
||||
function accumulateDirectDispatches(events) {
|
||||
if (__DEV__) {
|
||||
injection.validate();
|
||||
}
|
||||
forEachAccumulated(abstractEvents, accumulateDirectDispatchesSingle);
|
||||
forEachAccumulated(events, accumulateDirectDispatchesSingle);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -155,13 +155,13 @@ describe('EventPluginRegistry', function() {
|
||||
|
||||
it('should publish registration names of injected plugins', function() {
|
||||
var OnePlugin = createPlugin({
|
||||
abstractEventTypes: {
|
||||
eventTypes: {
|
||||
click: {registrationName: 'onClick'},
|
||||
focus: {registrationName: 'onFocus'}
|
||||
}
|
||||
});
|
||||
var TwoPlugin = createPlugin({
|
||||
abstractEventTypes: {
|
||||
eventTypes: {
|
||||
magic: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: 'onMagicBubble',
|
||||
@@ -189,12 +189,12 @@ describe('EventPluginRegistry', function() {
|
||||
|
||||
it('should throw if multiple registration names collide', function() {
|
||||
var OnePlugin = createPlugin({
|
||||
abstractEventTypes: {
|
||||
eventTypes: {
|
||||
photoCapture: {registrationName: 'onPhotoCapture'}
|
||||
}
|
||||
});
|
||||
var TwoPlugin = createPlugin({
|
||||
abstractEventTypes: {
|
||||
eventTypes: {
|
||||
photo: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: 'onPhotoBubble',
|
||||
@@ -219,7 +219,7 @@ describe('EventPluginRegistry', function() {
|
||||
|
||||
it('should throw if an invalid event is published', function() {
|
||||
var OnePlugin = createPlugin({
|
||||
abstractEventTypes: {
|
||||
eventTypes: {
|
||||
badEvent: {/* missing configuration */}
|
||||
}
|
||||
});
|
||||
@@ -246,14 +246,14 @@ describe('EventPluginRegistry', function() {
|
||||
};
|
||||
|
||||
var OnePlugin = createPlugin({
|
||||
abstractEventTypes: {
|
||||
eventTypes: {
|
||||
click: clickDispatchConfig,
|
||||
magic: magicDispatchConfig
|
||||
}
|
||||
});
|
||||
|
||||
var clickEvent = {reactEventType: clickDispatchConfig};
|
||||
var magicEvent = {reactEventType: magicDispatchConfig};
|
||||
var clickEvent = {dispatchConfig: clickDispatchConfig};
|
||||
var magicEvent = {dispatchConfig: magicDispatchConfig};
|
||||
|
||||
expect(EventPluginRegistry.getPluginModuleForEvent(clickEvent)).toBe(null);
|
||||
expect(EventPluginRegistry.getPluginModuleForEvent(magicEvent)).toBe(null);
|
||||
|
||||
@@ -133,14 +133,14 @@ if (__DEV__) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This plugin does not really extract any abstract events. Rather it just looks
|
||||
* at the top level event and bumps up counters as appropriate
|
||||
* This plugin does not really extract any synthetic events. Rather it just
|
||||
* looks at the top-level event and bumps up counters as appropriate
|
||||
*
|
||||
* @param {string} topLevelType Record from `EventConstants`.
|
||||
* @param {DOMEventTarget} topLevelTarget The listening component root node.
|
||||
* @param {string} topLevelTargetID ID of `topLevelTarget`.
|
||||
* @param {object} nativeEvent Native browser event.
|
||||
* @return {*} An accumulation of `AbstractEvent`s.
|
||||
* @return {*} An accumulation of synthetic events.
|
||||
* @see {EventPluginHub.extractEvents}
|
||||
*/
|
||||
function extractEvents(
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
var EventConstants = require('EventConstants');
|
||||
var EventPropagators = require('EventPropagators');
|
||||
var ExecutionEnvironment = require('ExecutionEnvironment');
|
||||
var AbstractEvent = require('AbstractEvent');
|
||||
var EventConstants = require('EventConstants');
|
||||
var ReactInstanceHandles = require('ReactInstanceHandles');
|
||||
var SyntheticMouseEvent = require('SyntheticMouseEvent');
|
||||
|
||||
var getDOMNodeID = require('getDOMNodeID');
|
||||
var keyOf = require('keyOf');
|
||||
@@ -31,78 +31,77 @@ var keyOf = require('keyOf');
|
||||
var topLevelTypes = EventConstants.topLevelTypes;
|
||||
var getFirstReactDOM = ReactInstanceHandles.getFirstReactDOM;
|
||||
|
||||
var abstractEventTypes = {
|
||||
var eventTypes = {
|
||||
mouseEnter: {registrationName: keyOf({onMouseEnter: null})},
|
||||
mouseLeave: {registrationName: keyOf({onMouseLeave: null})}
|
||||
};
|
||||
|
||||
/**
|
||||
* For almost every interaction we care about, there will be a top-level
|
||||
* `mouseover` and `mouseout` event that occurs so only pay attention to one of
|
||||
* the two (to avoid duplicate events). We use the `mouseout` event.
|
||||
*
|
||||
* However, there's one interaction where there will be no `mouseout` event to
|
||||
* rely on - mousing from outside the browser *into* the chrome. We detect this
|
||||
* scenario and only in that case, we use the `mouseover` event.
|
||||
*
|
||||
* @param {string} topLevelType Record from `EventConstants`.
|
||||
* @param {DOMEventTarget} topLevelTarget The listening component root node.
|
||||
* @param {string} topLevelTargetID ID of `topLevelTarget`.
|
||||
* @param {object} nativeEvent Native browser event.
|
||||
* @return {*} An accumulation of `AbstractEvent`s.
|
||||
* @see {EventPluginHub.extractEvents}
|
||||
*/
|
||||
var extractEvents = function(
|
||||
topLevelType,
|
||||
topLevelTarget,
|
||||
topLevelTargetID,
|
||||
nativeEvent) {
|
||||
if (topLevelType === topLevelTypes.topMouseOver &&
|
||||
(nativeEvent.relatedTarget || nativeEvent.fromElement)) {
|
||||
return null;
|
||||
}
|
||||
if (topLevelType !== topLevelTypes.topMouseOut &&
|
||||
topLevelType !== topLevelTypes.topMouseOver) {
|
||||
return null; // Must not be a mouse in or mouse out - ignoring.
|
||||
}
|
||||
|
||||
var to, from;
|
||||
if (topLevelType === topLevelTypes.topMouseOut) {
|
||||
to = getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement) ||
|
||||
ExecutionEnvironment.global;
|
||||
from = topLevelTarget;
|
||||
} else {
|
||||
to = topLevelTarget;
|
||||
from = ExecutionEnvironment.global;
|
||||
}
|
||||
|
||||
// Nothing pertains to our managed components.
|
||||
if (from === to) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var fromID = from ? getDOMNodeID(from) : '';
|
||||
var toID = to ? getDOMNodeID(to) : '';
|
||||
|
||||
var leave = AbstractEvent.getPooled(
|
||||
abstractEventTypes.mouseLeave,
|
||||
fromID,
|
||||
nativeEvent
|
||||
);
|
||||
var enter = AbstractEvent.getPooled(
|
||||
abstractEventTypes.mouseEnter,
|
||||
toID,
|
||||
nativeEvent
|
||||
);
|
||||
|
||||
EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID);
|
||||
|
||||
return [leave, enter];
|
||||
};
|
||||
|
||||
var EnterLeaveEventPlugin = {
|
||||
abstractEventTypes: abstractEventTypes,
|
||||
extractEvents: extractEvents
|
||||
|
||||
eventTypes: eventTypes,
|
||||
|
||||
/**
|
||||
* For almost every interaction we care about, there will be both a top-level
|
||||
* `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that
|
||||
* we do not extract duplicate events. However, moving the mouse into the
|
||||
* browser from outside will not fire a `mouseout` event. In this case, we use
|
||||
* the `mouseover` top-level event.
|
||||
*
|
||||
* @param {string} topLevelType Record from `EventConstants`.
|
||||
* @param {DOMEventTarget} topLevelTarget The listening component root node.
|
||||
* @param {string} topLevelTargetID ID of `topLevelTarget`.
|
||||
* @param {object} nativeEvent Native browser event.
|
||||
* @return {*} An accumulation of synthetic events.
|
||||
* @see {EventPluginHub.extractEvents}
|
||||
*/
|
||||
extractEvents: function(
|
||||
topLevelType,
|
||||
topLevelTarget,
|
||||
topLevelTargetID,
|
||||
nativeEvent) {
|
||||
if (topLevelType === topLevelTypes.topMouseOver &&
|
||||
(nativeEvent.relatedTarget || nativeEvent.fromElement)) {
|
||||
return null;
|
||||
}
|
||||
if (topLevelType !== topLevelTypes.topMouseOut &&
|
||||
topLevelType !== topLevelTypes.topMouseOver) {
|
||||
// Must not be a mouse in or mouse out - ignoring.
|
||||
return null;
|
||||
}
|
||||
|
||||
var from, to;
|
||||
if (topLevelType === topLevelTypes.topMouseOut) {
|
||||
from = topLevelTarget;
|
||||
to = getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement)
|
||||
|| ExecutionEnvironment.global;
|
||||
} else {
|
||||
from = ExecutionEnvironment.global;
|
||||
to = topLevelTarget;
|
||||
}
|
||||
|
||||
if (from === to) {
|
||||
// Nothing pertains to our managed components.
|
||||
return null;
|
||||
}
|
||||
|
||||
var fromID = from ? getDOMNodeID(from) : '';
|
||||
var toID = to ? getDOMNodeID(to) : '';
|
||||
|
||||
var leave = SyntheticMouseEvent.getPooled(
|
||||
eventTypes.mouseLeave,
|
||||
fromID,
|
||||
nativeEvent
|
||||
);
|
||||
var enter = SyntheticMouseEvent.getPooled(
|
||||
eventTypes.mouseEnter,
|
||||
toID,
|
||||
nativeEvent
|
||||
);
|
||||
|
||||
EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID);
|
||||
return [leave, enter];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = EnterLeaveEventPlugin;
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
var AbstractEvent = require('AbstractEvent');
|
||||
var EventConstants = require('EventConstants');
|
||||
var EventPluginUtils = require('EventPluginUtils');
|
||||
var EventPropagators = require('EventPropagators');
|
||||
var SyntheticEvent = require('SyntheticEvent');
|
||||
|
||||
var accumulate = require('accumulate');
|
||||
var keyOf = require('keyOf');
|
||||
@@ -41,11 +41,7 @@ var executeDispatchesInOrderStopAtTrue =
|
||||
var responderID = null;
|
||||
var isPressing = false;
|
||||
|
||||
var getResponderID = function() {
|
||||
return responderID;
|
||||
};
|
||||
|
||||
var abstractEventTypes = {
|
||||
var eventTypes = {
|
||||
/**
|
||||
* On a `touchStart`/`mouseDown`, is it desired that this element become the
|
||||
* responder?
|
||||
@@ -116,22 +112,22 @@ var abstractEventTypes = {
|
||||
* `extractEvents()`.
|
||||
* - These events that are returned from `extractEvents` are "deferred
|
||||
* dispatched events".
|
||||
* - When returned from `extractEvents`, deferred dispatched events
|
||||
* contain an "accumulation" of deferred dispatches.
|
||||
* -- These deferred dispatches are accumulated/collected before they are
|
||||
* returned, but processed at a later time by the `EventPluginHub` (hence the
|
||||
* name deferred).
|
||||
* - When returned from `extractEvents`, deferred-dispatched events contain an
|
||||
* "accumulation" of deferred dispatches.
|
||||
* - These deferred dispatches are accumulated/collected before they are
|
||||
* returned, but processed at a later time by the `EventPluginHub` (hence the
|
||||
* name deferred).
|
||||
*
|
||||
* In the process of returning their deferred dispatched events, event plugins
|
||||
* In the process of returning their deferred-dispatched events, event plugins
|
||||
* themselves can dispatch events on-demand without returning them from
|
||||
* `extractEvents`. Plugins might want to do this, so that they can use
|
||||
* event dispatching as a tool that helps them decide which events should be
|
||||
* extracted in the first place.
|
||||
* `extractEvents`. Plugins might want to do this, so that they can use event
|
||||
* dispatching as a tool that helps them decide which events should be extracted
|
||||
* in the first place.
|
||||
*
|
||||
* "On-Demand-Dispatched Events":
|
||||
*
|
||||
* - On-demand dispatched are not returned from `extractEvents`.
|
||||
* - On-demand dispatched events are dispatched during the process of returning
|
||||
* - On-demand-dispatched events are not returned from `extractEvents`.
|
||||
* - On-demand-dispatched events are dispatched during the process of returning
|
||||
* the deferred-dispatched events.
|
||||
* - They should not have side effects.
|
||||
* - They should be avoided, and/or eventually be replaced with another
|
||||
@@ -158,81 +154,81 @@ var abstractEventTypes = {
|
||||
* - `touchStart` (`EventPluginHub` dispatches as usual)
|
||||
* - `responderGrant/Reject` (`EventPluginHub` dispatches as usual)
|
||||
*
|
||||
* @returns {Accumulation<AbstractEvent>}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string} topLevelType Record from `EventConstants`.
|
||||
* @param {string} renderedTargetID ID of deepest React rendered element.
|
||||
* @param {string} topLevelTargetID ID of deepest React rendered element.
|
||||
* @param {object} nativeEvent Native browser event.
|
||||
* @return {*} An accumulation of extracted `AbstractEvent`s.
|
||||
* @return {*} An accumulation of synthetic events.
|
||||
*/
|
||||
var setResponderAndExtractTransfer =
|
||||
function(topLevelType, renderedTargetID, nativeEvent) {
|
||||
var type;
|
||||
var shouldSetEventType =
|
||||
isStartish(topLevelType) ? abstractEventTypes.startShouldSetResponder :
|
||||
isMoveish(topLevelType) ? abstractEventTypes.moveShouldSetResponder :
|
||||
abstractEventTypes.scrollShouldSetResponder;
|
||||
function setResponderAndExtractTransfer(
|
||||
topLevelType,
|
||||
topLevelTargetID,
|
||||
nativeEvent) {
|
||||
var shouldSetEventType =
|
||||
isStartish(topLevelType) ? eventTypes.startShouldSetResponder :
|
||||
isMoveish(topLevelType) ? eventTypes.moveShouldSetResponder :
|
||||
eventTypes.scrollShouldSetResponder;
|
||||
|
||||
var bubbleShouldSetFrom = responderID || renderedTargetID;
|
||||
var shouldSetEvent = AbstractEvent.getPooled(
|
||||
shouldSetEventType,
|
||||
bubbleShouldSetFrom,
|
||||
topLevelType,
|
||||
nativeEvent,
|
||||
AbstractEvent.normalizePointerData(nativeEvent)
|
||||
);
|
||||
EventPropagators.accumulateTwoPhaseDispatches(shouldSetEvent);
|
||||
var wantsResponderID = executeDispatchesInOrderStopAtTrue(shouldSetEvent);
|
||||
AbstractEvent.release(shouldSetEvent);
|
||||
var bubbleShouldSetFrom = responderID || topLevelTargetID;
|
||||
var shouldSetEvent = SyntheticEvent.getPooled(
|
||||
shouldSetEventType,
|
||||
bubbleShouldSetFrom,
|
||||
nativeEvent
|
||||
);
|
||||
EventPropagators.accumulateTwoPhaseDispatches(shouldSetEvent);
|
||||
var wantsResponderID = executeDispatchesInOrderStopAtTrue(shouldSetEvent);
|
||||
if (!shouldSetEvent.isPersistent()) {
|
||||
shouldSetEvent.constructor.release(shouldSetEvent);
|
||||
}
|
||||
|
||||
if (!wantsResponderID || wantsResponderID === responderID) {
|
||||
return null;
|
||||
}
|
||||
var extracted;
|
||||
var grantEvent = AbstractEvent.getPooled(
|
||||
abstractEventTypes.responderGrant,
|
||||
wantsResponderID,
|
||||
topLevelType,
|
||||
if (!wantsResponderID || wantsResponderID === responderID) {
|
||||
return null;
|
||||
}
|
||||
var extracted;
|
||||
var grantEvent = SyntheticEvent.getPooled(
|
||||
eventTypes.responderGrant,
|
||||
wantsResponderID,
|
||||
nativeEvent
|
||||
);
|
||||
|
||||
EventPropagators.accumulateDirectDispatches(grantEvent);
|
||||
if (responderID) {
|
||||
var terminationRequestEvent = SyntheticEvent.getPooled(
|
||||
eventTypes.responderTerminationRequest,
|
||||
responderID,
|
||||
nativeEvent
|
||||
);
|
||||
|
||||
EventPropagators.accumulateDirectDispatches(grantEvent);
|
||||
if (responderID) {
|
||||
type = abstractEventTypes.responderTerminationRequest;
|
||||
var terminationRequestEvent = AbstractEvent.getPooled(type, responderID);
|
||||
EventPropagators.accumulateDirectDispatches(terminationRequestEvent);
|
||||
var shouldSwitch = !hasDispatches(terminationRequestEvent) ||
|
||||
executeDirectDispatch(terminationRequestEvent);
|
||||
AbstractEvent.release(terminationRequestEvent);
|
||||
if (shouldSwitch) {
|
||||
var terminateType = abstractEventTypes.responderTerminate;
|
||||
var terminateEvent = AbstractEvent.getPooled(
|
||||
terminateType,
|
||||
responderID,
|
||||
topLevelType,
|
||||
nativeEvent
|
||||
);
|
||||
EventPropagators.accumulateDirectDispatches(terminateEvent);
|
||||
extracted = accumulate(extracted, [grantEvent, terminateEvent]);
|
||||
responderID = wantsResponderID;
|
||||
} else {
|
||||
var rejectEvent = AbstractEvent.getPooled(
|
||||
abstractEventTypes.responderReject,
|
||||
wantsResponderID,
|
||||
topLevelType,
|
||||
nativeEvent
|
||||
);
|
||||
EventPropagators.accumulateDirectDispatches(rejectEvent);
|
||||
extracted = accumulate(extracted, rejectEvent);
|
||||
}
|
||||
} else {
|
||||
extracted = accumulate(extracted, grantEvent);
|
||||
responderID = wantsResponderID;
|
||||
EventPropagators.accumulateDirectDispatches(terminationRequestEvent);
|
||||
var shouldSwitch = !hasDispatches(terminationRequestEvent) ||
|
||||
executeDirectDispatch(terminationRequestEvent);
|
||||
if (!terminationRequestEvent.isPersistent()) {
|
||||
terminationRequestEvent.constructor.release(terminationRequestEvent);
|
||||
}
|
||||
return extracted;
|
||||
};
|
||||
|
||||
if (shouldSwitch) {
|
||||
var terminateType = eventTypes.responderTerminate;
|
||||
var terminateEvent = SyntheticEvent.getPooled(
|
||||
terminateType,
|
||||
responderID,
|
||||
nativeEvent
|
||||
);
|
||||
EventPropagators.accumulateDirectDispatches(terminateEvent);
|
||||
extracted = accumulate(extracted, [grantEvent, terminateEvent]);
|
||||
responderID = wantsResponderID;
|
||||
} else {
|
||||
var rejectEvent = SyntheticEvent.getPooled(
|
||||
eventTypes.responderReject,
|
||||
wantsResponderID,
|
||||
nativeEvent
|
||||
);
|
||||
EventPropagators.accumulateDirectDispatches(rejectEvent);
|
||||
extracted = accumulate(extracted, rejectEvent);
|
||||
}
|
||||
} else {
|
||||
extracted = accumulate(extracted, grantEvent);
|
||||
responderID = wantsResponderID;
|
||||
}
|
||||
return extracted;
|
||||
}
|
||||
|
||||
/**
|
||||
* A transfer is a negotiation between a currently set responder and the next
|
||||
@@ -241,9 +237,8 @@ var setResponderAndExtractTransfer =
|
||||
* currently a responder set (in other words as long as the user is pressing
|
||||
* down).
|
||||
*
|
||||
* @param {EventConstants.topLevelTypes} topLevelType
|
||||
* @return {boolean} Whether or not a transfer of responder could possibly
|
||||
* occur.
|
||||
* @param {string} topLevelType Record from `EventConstants`.
|
||||
* @return {boolean} True if a transfer of responder could possibly occur.
|
||||
*/
|
||||
function canTriggerTransfer(topLevelType) {
|
||||
return topLevelType === EventConstants.topLevelTypes.topScroll ||
|
||||
@@ -251,69 +246,71 @@ function canTriggerTransfer(topLevelType) {
|
||||
(isPressing && isMoveish(topLevelType));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} topLevelType Record from `EventConstants`.
|
||||
* @param {DOMEventTarget} topLevelTarget The listening component root node.
|
||||
* @param {string} topLevelTargetID ID of `topLevelTarget`.
|
||||
* @param {object} nativeEvent Native browser event.
|
||||
* @return {*} An accumulation of `AbstractEvent`s.
|
||||
* @see {EventPluginHub.extractEvents}
|
||||
*/
|
||||
var extractEvents = function(
|
||||
topLevelType,
|
||||
topLevelTarget,
|
||||
topLevelTargetID,
|
||||
nativeEvent) {
|
||||
var extracted;
|
||||
// Must have missed an end event - reset the state here.
|
||||
if (responderID && isStartish(topLevelType)) {
|
||||
responderID = null;
|
||||
}
|
||||
if (isStartish(topLevelType)) {
|
||||
isPressing = true;
|
||||
} else if (isEndish(topLevelType)) {
|
||||
isPressing = false;
|
||||
}
|
||||
if (canTriggerTransfer(topLevelType)) {
|
||||
var transfer = setResponderAndExtractTransfer(
|
||||
topLevelType,
|
||||
topLevelTargetID,
|
||||
nativeEvent
|
||||
);
|
||||
if (transfer) {
|
||||
extracted = accumulate(extracted, transfer);
|
||||
}
|
||||
}
|
||||
// Now that we know the responder is set correctly, we can dispatch
|
||||
// responder type events (directly to the responder).
|
||||
var type = isMoveish(topLevelType) ? abstractEventTypes.responderMove :
|
||||
isEndish(topLevelType) ? abstractEventTypes.responderRelease :
|
||||
isStartish(topLevelType) ? abstractEventTypes.responderStart : null;
|
||||
if (type) {
|
||||
var data = AbstractEvent.normalizePointerData(nativeEvent);
|
||||
var gesture = AbstractEvent.getPooled(
|
||||
type,
|
||||
responderID,
|
||||
nativeEvent,
|
||||
data
|
||||
);
|
||||
EventPropagators.accumulateDirectDispatches(gesture);
|
||||
extracted = accumulate(extracted, gesture);
|
||||
}
|
||||
if (type === abstractEventTypes.responderRelease) {
|
||||
responderID = null;
|
||||
}
|
||||
return extracted;
|
||||
};
|
||||
|
||||
/**
|
||||
* Event plugin for formalizing the negotiation between claiming locks on
|
||||
* receiving touches.
|
||||
*/
|
||||
var ResponderEventPlugin = {
|
||||
abstractEventTypes: abstractEventTypes,
|
||||
extractEvents: extractEvents,
|
||||
getResponderID: getResponderID
|
||||
|
||||
getResponderID: function() {
|
||||
return responderID;
|
||||
},
|
||||
|
||||
eventTypes: eventTypes,
|
||||
|
||||
/**
|
||||
* @param {string} topLevelType Record from `EventConstants`.
|
||||
* @param {DOMEventTarget} topLevelTarget The listening component root node.
|
||||
* @param {string} topLevelTargetID ID of `topLevelTarget`.
|
||||
* @param {object} nativeEvent Native browser event.
|
||||
* @return {*} An accumulation of synthetic events.
|
||||
* @see {EventPluginHub.extractEvents}
|
||||
*/
|
||||
extractEvents: function(
|
||||
topLevelType,
|
||||
topLevelTarget,
|
||||
topLevelTargetID,
|
||||
nativeEvent) {
|
||||
var extracted;
|
||||
// Must have missed an end event - reset the state here.
|
||||
if (responderID && isStartish(topLevelType)) {
|
||||
responderID = null;
|
||||
}
|
||||
if (isStartish(topLevelType)) {
|
||||
isPressing = true;
|
||||
} else if (isEndish(topLevelType)) {
|
||||
isPressing = false;
|
||||
}
|
||||
if (canTriggerTransfer(topLevelType)) {
|
||||
var transfer = setResponderAndExtractTransfer(
|
||||
topLevelType,
|
||||
topLevelTargetID,
|
||||
nativeEvent
|
||||
);
|
||||
if (transfer) {
|
||||
extracted = accumulate(extracted, transfer);
|
||||
}
|
||||
}
|
||||
// Now that we know the responder is set correctly, we can dispatch
|
||||
// responder type events (directly to the responder).
|
||||
var type = isMoveish(topLevelType) ? eventTypes.responderMove :
|
||||
isEndish(topLevelType) ? eventTypes.responderRelease :
|
||||
isStartish(topLevelType) ? eventTypes.responderStart : null;
|
||||
if (type) {
|
||||
var gesture = SyntheticEvent.getPooled(
|
||||
type,
|
||||
responderID || '',
|
||||
nativeEvent
|
||||
);
|
||||
EventPropagators.accumulateDirectDispatches(gesture);
|
||||
extracted = accumulate(extracted, gesture);
|
||||
}
|
||||
if (type === eventTypes.responderRelease) {
|
||||
responderID = null;
|
||||
}
|
||||
return extracted;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = ResponderEventPlugin;
|
||||
|
||||
@@ -18,201 +18,237 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
var AbstractEvent = require('AbstractEvent');
|
||||
var EventConstants = require('EventConstants');
|
||||
var EventPropagators = require('EventPropagators');
|
||||
var SyntheticEvent = require('SyntheticEvent');
|
||||
var SyntheticFocusEvent = require('SyntheticFocusEvent');
|
||||
var SyntheticKeyboardEvent = require('SyntheticKeyboardEvent');
|
||||
var SyntheticMouseEvent = require('SyntheticMouseEvent');
|
||||
var SyntheticMutationEvent = require('SyntheticMutationEvent');
|
||||
var SyntheticTouchEvent = require('SyntheticTouchEvent');
|
||||
var SyntheticUIEvent = require('SyntheticUIEvent');
|
||||
var SyntheticWheelEvent = require('SyntheticWheelEvent');
|
||||
|
||||
var invariant = require('invariant');
|
||||
var keyOf = require('keyOf');
|
||||
|
||||
var topLevelTypes = EventConstants.topLevelTypes;
|
||||
|
||||
var SimpleEventPlugin = {
|
||||
abstractEventTypes: {
|
||||
// Note: We do not allow listening to mouseOver events. Instead, use the
|
||||
// onMouseEnter/onMouseLeave created by `EnterLeaveEventPlugin`.
|
||||
mouseDown: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onMouseDown: true}),
|
||||
captured: keyOf({onMouseDownCapture: true})
|
||||
}
|
||||
},
|
||||
mouseUp: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onMouseUp: true}),
|
||||
captured: keyOf({onMouseUpCapture: true})
|
||||
}
|
||||
},
|
||||
mouseMove: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onMouseMove: true}),
|
||||
captured: keyOf({onMouseMoveCapture: true})
|
||||
}
|
||||
},
|
||||
doubleClick: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDoubleClick: true}),
|
||||
captured: keyOf({onDoubleClickCapture: true})
|
||||
}
|
||||
},
|
||||
click: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onClick: true}),
|
||||
captured: keyOf({onClickCapture: true})
|
||||
}
|
||||
},
|
||||
wheel: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onWheel: true}),
|
||||
captured: keyOf({onWheelCapture: true})
|
||||
}
|
||||
},
|
||||
touchStart: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onTouchStart: true}),
|
||||
captured: keyOf({onTouchStartCapture: true})
|
||||
}
|
||||
},
|
||||
touchEnd: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onTouchEnd: true}),
|
||||
captured: keyOf({onTouchEndCapture: true})
|
||||
}
|
||||
},
|
||||
touchCancel: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onTouchCancel: true}),
|
||||
captured: keyOf({onTouchCancelCapture: true})
|
||||
}
|
||||
},
|
||||
touchMove: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onTouchMove: true}),
|
||||
captured: keyOf({onTouchMoveCapture: true})
|
||||
}
|
||||
},
|
||||
keyUp: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onKeyUp: true}),
|
||||
captured: keyOf({onKeyUpCapture: true})
|
||||
}
|
||||
},
|
||||
keyPress: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onKeyPress: true}),
|
||||
captured: keyOf({onKeyPressCapture: true})
|
||||
}
|
||||
},
|
||||
keyDown: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onKeyDown: true}),
|
||||
captured: keyOf({onKeyDownCapture: true})
|
||||
}
|
||||
},
|
||||
input: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onInput: true}),
|
||||
captured: keyOf({onInputCapture: true})
|
||||
}
|
||||
},
|
||||
focus: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onFocus: true}),
|
||||
captured: keyOf({onFocusCapture: true})
|
||||
}
|
||||
},
|
||||
blur: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onBlur: true}),
|
||||
captured: keyOf({onBlurCapture: true})
|
||||
}
|
||||
},
|
||||
scroll: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onScroll: true}),
|
||||
captured: keyOf({onScrollCapture: true})
|
||||
}
|
||||
},
|
||||
change: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onChange: true}),
|
||||
captured: keyOf({onChangeCapture: true})
|
||||
}
|
||||
},
|
||||
submit: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onSubmit: true}),
|
||||
captured: keyOf({onSubmitCapture: true})
|
||||
}
|
||||
},
|
||||
DOMCharacterDataModified: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDOMCharacterDataModified: true}),
|
||||
captured: keyOf({onDOMCharacterDataModifiedCapture: true})
|
||||
}
|
||||
},
|
||||
drag: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDrag: true}),
|
||||
captured: keyOf({onDragCapture: true})
|
||||
}
|
||||
},
|
||||
dragEnd: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDragEnd: true}),
|
||||
captured: keyOf({onDragEndCapture: true})
|
||||
}
|
||||
},
|
||||
dragEnter: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDragEnter: true}),
|
||||
captured: keyOf({onDragEnterCapture: true})
|
||||
}
|
||||
},
|
||||
dragExit: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDragExit: true}),
|
||||
captured: keyOf({onDragExitCapture: true})
|
||||
}
|
||||
},
|
||||
dragLeave: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDragLeave: true}),
|
||||
captured: keyOf({onDragLeaveCapture: true})
|
||||
}
|
||||
},
|
||||
dragOver: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDragOver: true}),
|
||||
captured: keyOf({onDragOverCapture: true})
|
||||
}
|
||||
},
|
||||
dragStart: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDragStart: true}),
|
||||
captured: keyOf({onDragStartCapture: true})
|
||||
}
|
||||
},
|
||||
drop: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDrop: true}),
|
||||
captured: keyOf({onDropCapture: true})
|
||||
}
|
||||
var eventTypes = {
|
||||
blur: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onBlur: true}),
|
||||
captured: keyOf({onBlurCapture: true})
|
||||
}
|
||||
},
|
||||
change: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onChange: true}),
|
||||
captured: keyOf({onChangeCapture: true})
|
||||
}
|
||||
},
|
||||
click: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onClick: true}),
|
||||
captured: keyOf({onClickCapture: true})
|
||||
}
|
||||
},
|
||||
doubleClick: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDoubleClick: true}),
|
||||
captured: keyOf({onDoubleClickCapture: true})
|
||||
}
|
||||
},
|
||||
drag: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDrag: true}),
|
||||
captured: keyOf({onDragCapture: true})
|
||||
}
|
||||
},
|
||||
dragEnd: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDragEnd: true}),
|
||||
captured: keyOf({onDragEndCapture: true})
|
||||
}
|
||||
},
|
||||
dragEnter: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDragEnter: true}),
|
||||
captured: keyOf({onDragEnterCapture: true})
|
||||
}
|
||||
},
|
||||
dragExit: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDragExit: true}),
|
||||
captured: keyOf({onDragExitCapture: true})
|
||||
}
|
||||
},
|
||||
dragLeave: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDragLeave: true}),
|
||||
captured: keyOf({onDragLeaveCapture: true})
|
||||
}
|
||||
},
|
||||
dragOver: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDragOver: true}),
|
||||
captured: keyOf({onDragOverCapture: true})
|
||||
}
|
||||
},
|
||||
dragStart: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDragStart: true}),
|
||||
captured: keyOf({onDragStartCapture: true})
|
||||
}
|
||||
},
|
||||
drop: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onDrop: true}),
|
||||
captured: keyOf({onDropCapture: true})
|
||||
}
|
||||
},
|
||||
focus: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onFocus: true}),
|
||||
captured: keyOf({onFocusCapture: true})
|
||||
}
|
||||
},
|
||||
input: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onInput: true}),
|
||||
captured: keyOf({onInputCapture: true})
|
||||
}
|
||||
},
|
||||
keyDown: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onKeyDown: true}),
|
||||
captured: keyOf({onKeyDownCapture: true})
|
||||
}
|
||||
},
|
||||
keyPress: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onKeyPress: true}),
|
||||
captured: keyOf({onKeyPressCapture: true})
|
||||
}
|
||||
},
|
||||
keyUp: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onKeyUp: true}),
|
||||
captured: keyOf({onKeyUpCapture: true})
|
||||
}
|
||||
},
|
||||
// Note: We do not allow listening to mouseOver events. Instead, use the
|
||||
// onMouseEnter/onMouseLeave created by `EnterLeaveEventPlugin`.
|
||||
mouseDown: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onMouseDown: true}),
|
||||
captured: keyOf({onMouseDownCapture: true})
|
||||
}
|
||||
},
|
||||
mouseMove: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onMouseMove: true}),
|
||||
captured: keyOf({onMouseMoveCapture: true})
|
||||
}
|
||||
},
|
||||
mouseUp: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onMouseUp: true}),
|
||||
captured: keyOf({onMouseUpCapture: true})
|
||||
}
|
||||
},
|
||||
scroll: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onScroll: true}),
|
||||
captured: keyOf({onScrollCapture: true})
|
||||
}
|
||||
},
|
||||
submit: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onSubmit: true}),
|
||||
captured: keyOf({onSubmitCapture: true})
|
||||
}
|
||||
},
|
||||
touchCancel: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onTouchCancel: true}),
|
||||
captured: keyOf({onTouchCancelCapture: true})
|
||||
}
|
||||
},
|
||||
touchEnd: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onTouchEnd: true}),
|
||||
captured: keyOf({onTouchEndCapture: true})
|
||||
}
|
||||
},
|
||||
touchMove: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onTouchMove: true}),
|
||||
captured: keyOf({onTouchMoveCapture: true})
|
||||
}
|
||||
},
|
||||
touchStart: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onTouchStart: true}),
|
||||
captured: keyOf({onTouchStartCapture: true})
|
||||
}
|
||||
},
|
||||
wheel: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onWheel: true}),
|
||||
captured: keyOf({onWheelCapture: true})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var topLevelEventsToDispatchConfig = {
|
||||
topBlur: eventTypes.blur,
|
||||
topChange: eventTypes.change,
|
||||
topClick: eventTypes.click,
|
||||
topDoubleClick: eventTypes.doubleClick,
|
||||
topDOMCharacterDataModified: eventTypes.DOMCharacterDataModified,
|
||||
topDrag: eventTypes.drag,
|
||||
topDragEnd: eventTypes.dragEnd,
|
||||
topDragEnter: eventTypes.dragEnter,
|
||||
topDragExit: eventTypes.dragExit,
|
||||
topDragLeave: eventTypes.dragLeave,
|
||||
topDragOver: eventTypes.dragOver,
|
||||
topDragStart: eventTypes.dragStart,
|
||||
topDrop: eventTypes.drop,
|
||||
topFocus: eventTypes.focus,
|
||||
topInput: eventTypes.input,
|
||||
topKeyDown: eventTypes.keyDown,
|
||||
topKeyPress: eventTypes.keyPress,
|
||||
topKeyUp: eventTypes.keyUp,
|
||||
topMouseDown: eventTypes.mouseDown,
|
||||
topMouseMove: eventTypes.mouseMove,
|
||||
topMouseUp: eventTypes.mouseUp,
|
||||
topScroll: eventTypes.scroll,
|
||||
topSubmit: eventTypes.submit,
|
||||
topTouchCancel: eventTypes.touchCancel,
|
||||
topTouchEnd: eventTypes.touchEnd,
|
||||
topTouchMove: eventTypes.touchMove,
|
||||
topTouchStart: eventTypes.touchStart,
|
||||
topWheel: eventTypes.wheel
|
||||
};
|
||||
|
||||
var SimpleEventPlugin = {
|
||||
|
||||
eventTypes: eventTypes,
|
||||
|
||||
/**
|
||||
* Same as the default implementation, except cancels the event when return
|
||||
* value is false.
|
||||
*
|
||||
* @param {AbstractEvent} AbstractEvent to handle
|
||||
* @param {function} Application-level callback
|
||||
* @param {string} domID DOM id to pass to the callback.
|
||||
* @param {object} Event to be dispatched.
|
||||
* @param {function} Application-level callback.
|
||||
* @param {string} domID DOM ID to pass to the callback.
|
||||
*/
|
||||
executeDispatch: function(abstractEvent, listener, domID) {
|
||||
var returnValue = listener(abstractEvent, domID);
|
||||
executeDispatch: function(event, listener, domID) {
|
||||
var returnValue = listener(event, domID);
|
||||
if (returnValue === false) {
|
||||
abstractEvent.stopPropagation();
|
||||
abstractEvent.preventDefault();
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -221,7 +257,7 @@ var SimpleEventPlugin = {
|
||||
* @param {DOMEventTarget} topLevelTarget The listening component root node.
|
||||
* @param {string} topLevelTargetID ID of `topLevelTarget`.
|
||||
* @param {object} nativeEvent Native browser event.
|
||||
* @return {*} An accumulation of `AbstractEvent`s.
|
||||
* @return {*} An accumulation of synthetic events.
|
||||
* @see {EventPluginHub.extractEvents}
|
||||
*/
|
||||
extractEvents: function(
|
||||
@@ -229,29 +265,30 @@ var SimpleEventPlugin = {
|
||||
topLevelTarget,
|
||||
topLevelTargetID,
|
||||
nativeEvent) {
|
||||
var data;
|
||||
var abstractEventType =
|
||||
SimpleEventPlugin.topLevelTypesToAbstract[topLevelType];
|
||||
if (!abstractEventType) {
|
||||
var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType];
|
||||
if (!dispatchConfig) {
|
||||
return null;
|
||||
}
|
||||
var EventConstructor;
|
||||
switch(topLevelType) {
|
||||
case topLevelTypes.topWheel:
|
||||
data = AbstractEvent.normalizeMouseWheelData(nativeEvent);
|
||||
case topLevelTypes.topChange:
|
||||
case topLevelTypes.topInput:
|
||||
case topLevelTypes.topSubmit:
|
||||
// HTML Events
|
||||
// @see http://www.w3.org/TR/html5/index.html#events-0
|
||||
EventConstructor = SyntheticEvent;
|
||||
break;
|
||||
case topLevelTypes.topScroll:
|
||||
data = AbstractEvent.normalizeScrollDataFromTarget(topLevelTarget);
|
||||
case topLevelTypes.topKeyDown:
|
||||
case topLevelTypes.topKeyPress:
|
||||
case topLevelTypes.topKeyUp:
|
||||
EventConstructor = SyntheticKeyboardEvent;
|
||||
break;
|
||||
case topLevelTypes.topBlur:
|
||||
case topLevelTypes.topFocus:
|
||||
EventConstructor = SyntheticFocusEvent;
|
||||
break;
|
||||
case topLevelTypes.topClick:
|
||||
case topLevelTypes.topDoubleClick:
|
||||
case topLevelTypes.topChange:
|
||||
case topLevelTypes.topDOMCharacterDataModified:
|
||||
case topLevelTypes.topMouseDown:
|
||||
case topLevelTypes.topMouseUp:
|
||||
case topLevelTypes.topMouseMove:
|
||||
case topLevelTypes.topTouchMove:
|
||||
case topLevelTypes.topTouchStart:
|
||||
case topLevelTypes.topTouchEnd:
|
||||
case topLevelTypes.topDrag:
|
||||
case topLevelTypes.topDragEnd:
|
||||
case topLevelTypes.topDragEnter:
|
||||
@@ -260,53 +297,41 @@ var SimpleEventPlugin = {
|
||||
case topLevelTypes.topDragOver:
|
||||
case topLevelTypes.topDragStart:
|
||||
case topLevelTypes.topDrop:
|
||||
data = AbstractEvent.normalizePointerData(nativeEvent);
|
||||
// todo: Use AbstractEvent.normalizeDragEventData for drag/drop?
|
||||
case topLevelTypes.topMouseDown:
|
||||
case topLevelTypes.topMouseMove:
|
||||
case topLevelTypes.topMouseUp:
|
||||
EventConstructor = SyntheticMouseEvent;
|
||||
break;
|
||||
case topLevelTypes.topDOMCharacterDataModified:
|
||||
EventConstructor = SyntheticMutationEvent;
|
||||
break;
|
||||
case topLevelTypes.topTouchCancel:
|
||||
case topLevelTypes.topTouchEnd:
|
||||
case topLevelTypes.topTouchMove:
|
||||
case topLevelTypes.topTouchStart:
|
||||
EventConstructor = SyntheticTouchEvent;
|
||||
break;
|
||||
case topLevelTypes.topScroll:
|
||||
EventConstructor = SyntheticUIEvent;
|
||||
break;
|
||||
case topLevelTypes.topWheel:
|
||||
EventConstructor = SyntheticWheelEvent;
|
||||
break;
|
||||
default:
|
||||
data = null;
|
||||
}
|
||||
var abstractEvent = AbstractEvent.getPooled(
|
||||
abstractEventType,
|
||||
topLevelTargetID,
|
||||
nativeEvent,
|
||||
data
|
||||
invariant(
|
||||
EventConstructor,
|
||||
'SimpleEventPlugin: Unhandled event type, `%s`.',
|
||||
topLevelType
|
||||
);
|
||||
EventPropagators.accumulateTwoPhaseDispatches(abstractEvent);
|
||||
return abstractEvent;
|
||||
var event = EventConstructor.getPooled(
|
||||
dispatchConfig,
|
||||
topLevelTargetID,
|
||||
nativeEvent
|
||||
);
|
||||
EventPropagators.accumulateTwoPhaseDispatches(event);
|
||||
return event;
|
||||
}
|
||||
};
|
||||
|
||||
SimpleEventPlugin.topLevelTypesToAbstract = {
|
||||
topMouseDown: SimpleEventPlugin.abstractEventTypes.mouseDown,
|
||||
topMouseUp: SimpleEventPlugin.abstractEventTypes.mouseUp,
|
||||
topMouseMove: SimpleEventPlugin.abstractEventTypes.mouseMove,
|
||||
topClick: SimpleEventPlugin.abstractEventTypes.click,
|
||||
topDoubleClick: SimpleEventPlugin.abstractEventTypes.doubleClick,
|
||||
topWheel: SimpleEventPlugin.abstractEventTypes.wheel,
|
||||
topTouchStart: SimpleEventPlugin.abstractEventTypes.touchStart,
|
||||
topTouchEnd: SimpleEventPlugin.abstractEventTypes.touchEnd,
|
||||
topTouchMove: SimpleEventPlugin.abstractEventTypes.touchMove,
|
||||
topTouchCancel: SimpleEventPlugin.abstractEventTypes.touchCancel,
|
||||
topKeyUp: SimpleEventPlugin.abstractEventTypes.keyUp,
|
||||
topKeyPress: SimpleEventPlugin.abstractEventTypes.keyPress,
|
||||
topKeyDown: SimpleEventPlugin.abstractEventTypes.keyDown,
|
||||
topInput: SimpleEventPlugin.abstractEventTypes.input,
|
||||
topFocus: SimpleEventPlugin.abstractEventTypes.focus,
|
||||
topBlur: SimpleEventPlugin.abstractEventTypes.blur,
|
||||
topScroll: SimpleEventPlugin.abstractEventTypes.scroll,
|
||||
topChange: SimpleEventPlugin.abstractEventTypes.change,
|
||||
topSubmit: SimpleEventPlugin.abstractEventTypes.submit,
|
||||
topDOMCharacterDataModified:
|
||||
SimpleEventPlugin.abstractEventTypes.DOMCharacterDataModified,
|
||||
topDrag: SimpleEventPlugin.abstractEventTypes.drag,
|
||||
topDragEnd: SimpleEventPlugin.abstractEventTypes.dragEnd,
|
||||
topDragEnter: SimpleEventPlugin.abstractEventTypes.dragEnter,
|
||||
topDragExit: SimpleEventPlugin.abstractEventTypes.dragExit,
|
||||
topDragLeave: SimpleEventPlugin.abstractEventTypes.dragLeave,
|
||||
topDragOver: SimpleEventPlugin.abstractEventTypes.dragOver,
|
||||
topDragStart: SimpleEventPlugin.abstractEventTypes.dragStart,
|
||||
topDrop: SimpleEventPlugin.abstractEventTypes.drop
|
||||
};
|
||||
|
||||
module.exports = SimpleEventPlugin;
|
||||
|
||||
@@ -19,25 +19,49 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
var AbstractEvent = require('AbstractEvent');
|
||||
var BrowserEnv = require('BrowserEnv');
|
||||
var EventPluginUtils = require('EventPluginUtils');
|
||||
var EventPropagators = require('EventPropagators');
|
||||
var SyntheticUIEvent = require('SyntheticUIEvent');
|
||||
var TouchEventUtils = require('TouchEventUtils');
|
||||
|
||||
var keyOf = require('keyOf');
|
||||
|
||||
var isStartish = EventPluginUtils.isStartish;
|
||||
var isEndish = EventPluginUtils.isEndish;
|
||||
var storePageCoordsIn = EventPluginUtils.storePageCoordsIn;
|
||||
var eventDistance = EventPluginUtils.eventDistance;
|
||||
|
||||
/**
|
||||
* The number of pixels that are tolerated in between a touchStart and
|
||||
* touchEnd in order to still be considered a 'tap' event.
|
||||
* Number of pixels that are tolerated in between a `touchStart` and `touchEnd`
|
||||
* in order to still be considered a 'tap' event.
|
||||
*/
|
||||
var tapMoveThreshold = 10;
|
||||
var startCoords = {x: null, y: null};
|
||||
|
||||
var abstractEventTypes = {
|
||||
var Axis = {
|
||||
x: {page: 'pageX', client: 'clientX', envScroll: 'currentPageScrollLeft'},
|
||||
y: {page: 'pageY', client: 'clientY', envScroll: 'currentPageScrollTop'}
|
||||
};
|
||||
|
||||
function getAxisCoordOfEvent(axis, nativeEvent) {
|
||||
var singleTouch = TouchEventUtils.extractSingleTouch(nativeEvent);
|
||||
if (singleTouch) {
|
||||
return singleTouch[axis.page];
|
||||
}
|
||||
return axis.page in nativeEvent ?
|
||||
nativeEvent[axis.page] :
|
||||
nativeEvent[axis.client] + BrowserEnv[axis.envScroll];
|
||||
}
|
||||
|
||||
function getDistance(coords, nativeEvent) {
|
||||
var pageX = getAxisCoordOfEvent(Axis.x, nativeEvent);
|
||||
var pageY = getAxisCoordOfEvent(Axis.y, nativeEvent);
|
||||
return Math.pow(
|
||||
Math.pow(pageX - coords.x, 2) + Math.pow(pageY - coords.y, 2),
|
||||
0.5
|
||||
);
|
||||
}
|
||||
|
||||
var eventTypes = {
|
||||
touchTap: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onTouchTap: null}),
|
||||
@@ -46,46 +70,48 @@ var abstractEventTypes = {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} topLevelType Record from `EventConstants`.
|
||||
* @param {DOMEventTarget} topLevelTarget The listening component root node.
|
||||
* @param {string} topLevelTargetID ID of `topLevelTarget`.
|
||||
* @param {object} nativeEvent Native browser event.
|
||||
* @return {*} An accumulation of `AbstractEvent`s.
|
||||
* @see {EventPluginHub.extractEvents}
|
||||
*/
|
||||
var extractEvents = function(
|
||||
topLevelType,
|
||||
topLevelTarget,
|
||||
topLevelTargetID,
|
||||
nativeEvent) {
|
||||
if (!isStartish(topLevelType) && !isEndish(topLevelType)) {
|
||||
return;
|
||||
}
|
||||
var abstractEvent;
|
||||
var dist = eventDistance(startCoords, nativeEvent);
|
||||
if (isEndish(topLevelType) && dist < tapMoveThreshold) {
|
||||
abstractEvent = AbstractEvent.getPooled(
|
||||
abstractEventTypes.touchTap,
|
||||
topLevelTargetID,
|
||||
nativeEvent
|
||||
);
|
||||
}
|
||||
if (isStartish(topLevelType)) {
|
||||
storePageCoordsIn(startCoords, nativeEvent);
|
||||
} else if (isEndish(topLevelType)) {
|
||||
startCoords.x = 0;
|
||||
startCoords.y = 0;
|
||||
}
|
||||
EventPropagators.accumulateTwoPhaseDispatches(abstractEvent);
|
||||
return abstractEvent;
|
||||
};
|
||||
|
||||
var TapEventPlugin = {
|
||||
|
||||
tapMoveThreshold: tapMoveThreshold,
|
||||
startCoords: startCoords,
|
||||
abstractEventTypes: abstractEventTypes,
|
||||
extractEvents: extractEvents
|
||||
|
||||
eventTypes: eventTypes,
|
||||
|
||||
/**
|
||||
* @param {string} topLevelType Record from `EventConstants`.
|
||||
* @param {DOMEventTarget} topLevelTarget The listening component root node.
|
||||
* @param {string} topLevelTargetID ID of `topLevelTarget`.
|
||||
* @param {object} nativeEvent Native browser event.
|
||||
* @return {*} An accumulation of synthetic events.
|
||||
* @see {EventPluginHub.extractEvents}
|
||||
*/
|
||||
extractEvents: function(
|
||||
topLevelType,
|
||||
topLevelTarget,
|
||||
topLevelTargetID,
|
||||
nativeEvent) {
|
||||
if (!isStartish(topLevelType) && !isEndish(topLevelType)) {
|
||||
return null;
|
||||
}
|
||||
var event = null;
|
||||
var distance = getDistance(startCoords, nativeEvent);
|
||||
if (isEndish(topLevelType) && distance < tapMoveThreshold) {
|
||||
event = SyntheticUIEvent.getPooled(
|
||||
eventTypes.touchTap,
|
||||
topLevelTargetID,
|
||||
nativeEvent
|
||||
);
|
||||
}
|
||||
if (isStartish(topLevelType)) {
|
||||
startCoords.x = getAxisCoordOfEvent(Axis.x, nativeEvent);
|
||||
startCoords.y = getAxisCoordOfEvent(Axis.y, nativeEvent);
|
||||
} else if (isEndish(topLevelType)) {
|
||||
startCoords.x = 0;
|
||||
startCoords.y = 0;
|
||||
}
|
||||
EventPropagators.accumulateTwoPhaseDispatches(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = TapEventPlugin;
|
||||
|
||||
@@ -18,18 +18,18 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
var AbstractEvent = require('AbstractEvent');
|
||||
var EventConstants = require('EventConstants');
|
||||
var EventPluginHub = require('EventPluginHub');
|
||||
var EventPropagators = require('EventPropagators');
|
||||
var ExecutionEnvironment = require('ExecutionEnvironment');
|
||||
var SyntheticEvent = require('SyntheticEvent');
|
||||
|
||||
var isEventSupported = require('isEventSupported');
|
||||
var keyOf = require('keyOf');
|
||||
|
||||
var topLevelTypes = EventConstants.topLevelTypes;
|
||||
|
||||
var abstractEventTypes = {
|
||||
var eventTypes = {
|
||||
textChange: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onTextChange: null}),
|
||||
@@ -121,29 +121,28 @@ var stopWatching = function() {
|
||||
* the value of the active element has changed.
|
||||
*/
|
||||
var handlePropertyChange = function(nativeEvent) {
|
||||
var value;
|
||||
var abstractEvent;
|
||||
|
||||
if (nativeEvent.propertyName === "value") {
|
||||
value = nativeEvent.srcElement.value;
|
||||
if (value !== activeElementValue) {
|
||||
activeElementValue = value;
|
||||
|
||||
abstractEvent = AbstractEvent.getPooled(
|
||||
abstractEventTypes.textChange,
|
||||
activeElementID,
|
||||
nativeEvent
|
||||
);
|
||||
EventPropagators.accumulateTwoPhaseDispatches(abstractEvent);
|
||||
|
||||
// If propertychange bubbled, we'd just bind to it like all the other
|
||||
// events and have it go through ReactEventTopLevelCallback. Since it
|
||||
// doesn't, we manually listen for the propertychange event and so we
|
||||
// have to enqueue and process the abstract event manually.
|
||||
EventPluginHub.enqueueEvents(abstractEvent);
|
||||
EventPluginHub.processEventQueue();
|
||||
}
|
||||
if (nativeEvent.propertyName !== "value") {
|
||||
return;
|
||||
}
|
||||
var value = nativeEvent.srcElement.value;
|
||||
if (value === activeElementValue) {
|
||||
return;
|
||||
}
|
||||
activeElementValue = value;
|
||||
|
||||
var event = SyntheticEvent.getPooled(
|
||||
eventTypes.textChange,
|
||||
activeElementID,
|
||||
nativeEvent
|
||||
);
|
||||
EventPropagators.accumulateTwoPhaseDispatches(event);
|
||||
|
||||
// If propertychange bubbled, we'd just bind to it like all the other events
|
||||
// and have it go through ReactEventTopLevelCallback. Since it doesn't, we
|
||||
// manually listen for the propertychange event and so we have to enqueue and
|
||||
// process the abstract event manually.
|
||||
EventPluginHub.enqueueEvents(event);
|
||||
EventPluginHub.processEventQueue();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -154,8 +153,7 @@ if (isInputSupported) {
|
||||
targetIDForTextChangeEvent = function(
|
||||
topLevelType,
|
||||
topLevelTarget,
|
||||
topLevelTargetID,
|
||||
nativeEvent) {
|
||||
topLevelTargetID) {
|
||||
if (topLevelType === topLevelTypes.topInput) {
|
||||
// In modern browsers (i.e., not IE8 or IE9), the input event is exactly
|
||||
// what we want so fall through here and trigger an abstract event...
|
||||
@@ -171,8 +169,7 @@ if (isInputSupported) {
|
||||
targetIDForTextChangeEvent = function(
|
||||
topLevelType,
|
||||
topLevelTarget,
|
||||
topLevelTargetID,
|
||||
nativeEvent) {
|
||||
topLevelTargetID) {
|
||||
if (topLevelType === topLevelTypes.topFocus) {
|
||||
// In IE8, we can capture almost all .value changes by adding a
|
||||
// propertychange handler and looking for events with propertyName
|
||||
@@ -214,40 +211,40 @@ if (isInputSupported) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} topLevelType Record from `EventConstants`.
|
||||
* @param {DOMEventTarget} topLevelTarget The listening component root node.
|
||||
* @param {string} topLevelTargetID ID of `topLevelTarget`.
|
||||
* @param {object} nativeEvent Native browser event.
|
||||
* @return {*} An accumulation of `AbstractEvent`s.
|
||||
* @see {EventPluginHub.extractEvents}
|
||||
*/
|
||||
var extractEvents = function(
|
||||
topLevelType,
|
||||
topLevelTarget,
|
||||
topLevelTargetID,
|
||||
nativeEvent) {
|
||||
var targetID = targetIDForTextChangeEvent(
|
||||
topLevelType,
|
||||
topLevelTarget,
|
||||
topLevelTargetID,
|
||||
nativeEvent
|
||||
);
|
||||
|
||||
if (targetID) {
|
||||
var abstractEvent = AbstractEvent.getPooled(
|
||||
abstractEventTypes.textChange,
|
||||
targetID,
|
||||
nativeEvent
|
||||
);
|
||||
EventPropagators.accumulateTwoPhaseDispatches(abstractEvent);
|
||||
return abstractEvent;
|
||||
}
|
||||
};
|
||||
|
||||
var TextChangeEventPlugin = {
|
||||
abstractEventTypes: abstractEventTypes,
|
||||
extractEvents: extractEvents
|
||||
|
||||
eventTypes: eventTypes,
|
||||
|
||||
/**
|
||||
* @param {string} topLevelType Record from `EventConstants`.
|
||||
* @param {DOMEventTarget} topLevelTarget The listening component root node.
|
||||
* @param {string} topLevelTargetID ID of `topLevelTarget`.
|
||||
* @param {object} nativeEvent Native browser event.
|
||||
* @return {*} An accumulation of synthetic events.
|
||||
* @see {EventPluginHub.extractEvents}
|
||||
*/
|
||||
extractEvents: function(
|
||||
topLevelType,
|
||||
topLevelTarget,
|
||||
topLevelTargetID,
|
||||
nativeEvent) {
|
||||
var targetID = targetIDForTextChangeEvent(
|
||||
topLevelType,
|
||||
topLevelTarget,
|
||||
topLevelTargetID
|
||||
);
|
||||
|
||||
if (targetID) {
|
||||
var event = SyntheticEvent.getPooled(
|
||||
eventTypes.textChange,
|
||||
targetID,
|
||||
nativeEvent
|
||||
);
|
||||
EventPropagators.accumulateTwoPhaseDispatches(event);
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = TextChangeEventPlugin;
|
||||
|
||||
@@ -23,21 +23,21 @@ var EventConstants;
|
||||
var EventPropagators;
|
||||
var ReactInstanceHandles;
|
||||
var ResponderEventPlugin;
|
||||
var AbstractEvent;
|
||||
var SyntheticEvent;
|
||||
|
||||
var GRANDPARENT_ID = '.reactRoot[0]';
|
||||
var PARENT_ID = '.reactRoot[0].0';
|
||||
var CHILD_ID = '.reactRoot[0].0.0';
|
||||
|
||||
var topLevelTypes;
|
||||
var responderAbstractEventTypes;
|
||||
var responderEventTypes;
|
||||
var spies;
|
||||
|
||||
var DUMMY_NATIVE_EVENT = {};
|
||||
var DUMMY_RENDERED_TARGET = {};
|
||||
|
||||
var onStartShouldSetResponder = function(id, cb, capture) {
|
||||
var registrationNames = responderAbstractEventTypes
|
||||
var registrationNames = responderEventTypes
|
||||
.startShouldSetResponder
|
||||
.phasedRegistrationNames;
|
||||
CallbackRegistry.putListener(
|
||||
@@ -48,7 +48,7 @@ var onStartShouldSetResponder = function(id, cb, capture) {
|
||||
};
|
||||
|
||||
var onScrollShouldSetResponder = function(id, cb, capture) {
|
||||
var registrationNames = responderAbstractEventTypes
|
||||
var registrationNames = responderEventTypes
|
||||
.scrollShouldSetResponder
|
||||
.phasedRegistrationNames;
|
||||
CallbackRegistry.putListener(
|
||||
@@ -59,7 +59,7 @@ var onScrollShouldSetResponder = function(id, cb, capture) {
|
||||
};
|
||||
|
||||
var onMoveShouldSetResponder = function(id, cb, capture) {
|
||||
var registrationNames = responderAbstractEventTypes
|
||||
var registrationNames = responderEventTypes
|
||||
.moveShouldSetResponder
|
||||
.phasedRegistrationNames;
|
||||
CallbackRegistry.putListener(
|
||||
@@ -73,7 +73,7 @@ var onMoveShouldSetResponder = function(id, cb, capture) {
|
||||
var onResponderGrant = function(id, cb) {
|
||||
CallbackRegistry.putListener(
|
||||
id,
|
||||
responderAbstractEventTypes.responderGrant.registrationName,
|
||||
responderEventTypes.responderGrant.registrationName,
|
||||
cb
|
||||
);
|
||||
};
|
||||
@@ -165,44 +165,40 @@ var existsInExtraction = function(extracted, test) {
|
||||
* Helper validators.
|
||||
*/
|
||||
function assertGrantEvent(id, extracted) {
|
||||
var test = function(abstractEvent) {
|
||||
return abstractEvent instanceof AbstractEvent &&
|
||||
abstractEvent.reactEventType ===
|
||||
responderAbstractEventTypes.responderGrant &&
|
||||
abstractEvent.reactTargetID === id;
|
||||
var test = function(event) {
|
||||
return event instanceof SyntheticEvent &&
|
||||
event.dispatchConfig === responderEventTypes.responderGrant &&
|
||||
event.dispatchMarker === id;
|
||||
};
|
||||
expect(ResponderEventPlugin.getResponderID()).toBe(id);
|
||||
expect(existsInExtraction(extracted, test)).toBe(true);
|
||||
}
|
||||
|
||||
function assertResponderMoveEvent(id, extracted) {
|
||||
var test = function(abstractEvent) {
|
||||
return abstractEvent instanceof AbstractEvent &&
|
||||
abstractEvent.reactEventType ===
|
||||
responderAbstractEventTypes.responderMove &&
|
||||
abstractEvent.reactTargetID === id;
|
||||
var test = function(event) {
|
||||
return event instanceof SyntheticEvent &&
|
||||
event.dispatchConfig === responderEventTypes.responderMove &&
|
||||
event.dispatchMarker === id;
|
||||
};
|
||||
expect(ResponderEventPlugin.getResponderID()).toBe(id);
|
||||
expect(existsInExtraction(extracted, test)).toBe(true);
|
||||
}
|
||||
|
||||
function assertTerminateEvent(id, extracted) {
|
||||
var test = function(abstractEvent) {
|
||||
return abstractEvent instanceof AbstractEvent &&
|
||||
abstractEvent.reactEventType ===
|
||||
responderAbstractEventTypes.responderTerminate &&
|
||||
abstractEvent.reactTargetID === id;
|
||||
var test = function(event) {
|
||||
return event instanceof SyntheticEvent &&
|
||||
event.dispatchConfig === responderEventTypes.responderTerminate &&
|
||||
event.dispatchMarker === id;
|
||||
};
|
||||
expect(ResponderEventPlugin.getResponderID()).not.toBe(id);
|
||||
expect(existsInExtraction(extracted, test)).toBe(true);
|
||||
}
|
||||
|
||||
function assertRelease(id, extracted) {
|
||||
var test = function(abstractEvent) {
|
||||
return abstractEvent instanceof AbstractEvent &&
|
||||
abstractEvent.reactEventType ===
|
||||
responderAbstractEventTypes.responderRelease &&
|
||||
abstractEvent.reactTargetID === id;
|
||||
var test = function(event) {
|
||||
return event instanceof SyntheticEvent &&
|
||||
event.dispatchConfig === responderEventTypes.responderRelease &&
|
||||
event.dispatchMarker === id;
|
||||
};
|
||||
expect(ResponderEventPlugin.getResponderID()).toBe(null);
|
||||
expect(existsInExtraction(extracted, test)).toBe(true);
|
||||
@@ -226,12 +222,12 @@ describe('ResponderEventPlugin', function() {
|
||||
beforeEach(function() {
|
||||
require('mock-modules').dumpCache();
|
||||
|
||||
AbstractEvent = require('AbstractEvent');
|
||||
CallbackRegistry = require('CallbackRegistry');
|
||||
EventConstants = require('EventConstants');
|
||||
EventPropagators = require('EventPropagators');
|
||||
ReactInstanceHandles = require('ReactInstanceHandles');
|
||||
ResponderEventPlugin = require('ResponderEventPlugin');
|
||||
SyntheticEvent = require('SyntheticEvent');
|
||||
EventPropagators.injection.injectInstanceHandle(ReactInstanceHandles);
|
||||
|
||||
// dumpCache, in open-source tests, only resets existing mocks. It does not
|
||||
@@ -240,7 +236,7 @@ describe('ResponderEventPlugin', function() {
|
||||
CallbackRegistry.__purge();
|
||||
|
||||
topLevelTypes = EventConstants.topLevelTypes;
|
||||
responderAbstractEventTypes = ResponderEventPlugin.abstractEventTypes;
|
||||
responderEventTypes = ResponderEventPlugin.eventTypes;
|
||||
|
||||
spies = {
|
||||
onStartShouldSetResponderChild: function() {},
|
||||
|
||||
@@ -187,7 +187,7 @@ var ReactTestUtils = {
|
||||
* on and `Element` node.
|
||||
* @param topLevelType {Object} A type from `EventConstants.topLevelTypes`
|
||||
* @param {!Element} node The dom to simulate an event occurring on.
|
||||
* @param {?Event} fakeNativeEvent Fake native event to pass to ReactEvent.
|
||||
* @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
|
||||
*/
|
||||
simulateEventOnNode: function(topLevelType, node, fakeNativeEvent) {
|
||||
var virtualHandler =
|
||||
@@ -203,7 +203,7 @@ var ReactTestUtils = {
|
||||
* on the `ReactNativeComponent` `comp`.
|
||||
* @param topLevelType {Object} A type from `EventConstants.topLevelTypes`.
|
||||
* @param comp {!ReactNativeComponent}
|
||||
* @param {?Event} fakeNativeEvent Fake native event to pass to ReactEvent.
|
||||
* @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
|
||||
*/
|
||||
simulateEventOnDOMComponent: function(topLevelType, comp, fakeNativeEvent) {
|
||||
var reactRootID = comp._rootNodeID || comp._rootDomId;
|
||||
@@ -280,7 +280,7 @@ for (eventType in topLevelTypes) {
|
||||
eventType.charAt(3).toLowerCase() + eventType.substr(4) : eventType;
|
||||
/**
|
||||
* @param {!Element || ReactNativeComponent} domComponentOrNode
|
||||
* @param {?Event} nativeEventData Fake native event to pass to ReactEvent.
|
||||
* @param {?Event} nativeEventData Fake native event to use in SyntheticEvent.
|
||||
*/
|
||||
ReactTestUtils.Simulate[convenienceName] = makeSimulator(eventType);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user