You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
218 lines
6.6 KiB
218 lines
6.6 KiB
10 years ago
|
/**
|
||
|
* Copyright 2013-2015, Facebook, Inc.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* This source code is licensed under the BSD-style license found in the
|
||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||
|
*
|
||
|
* @providesModule EventPluginUtils
|
||
|
*/
|
||
|
|
||
|
'use strict';
|
||
|
|
||
|
var EventConstants = require("./EventConstants");
|
||
|
|
||
|
var invariant = require("./invariant");
|
||
|
|
||
|
/**
|
||
|
* Injected dependencies:
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* - `Mount`: [required] Module that can convert between React dom IDs and
|
||
|
* actual node references.
|
||
|
*/
|
||
|
var injection = {
|
||
|
Mount: null,
|
||
|
injectMount: function(InjectedMount) {
|
||
|
injection.Mount = InjectedMount;
|
||
|
if ("production" !== process.env.NODE_ENV) {
|
||
|
("production" !== process.env.NODE_ENV ? invariant(
|
||
|
InjectedMount && InjectedMount.getNode,
|
||
|
'EventPluginUtils.injection.injectMount(...): Injected Mount module ' +
|
||
|
'is missing getNode.'
|
||
|
) : invariant(InjectedMount && InjectedMount.getNode));
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var topLevelTypes = EventConstants.topLevelTypes;
|
||
|
|
||
|
function isEndish(topLevelType) {
|
||
|
return topLevelType === topLevelTypes.topMouseUp ||
|
||
|
topLevelType === topLevelTypes.topTouchEnd ||
|
||
|
topLevelType === topLevelTypes.topTouchCancel;
|
||
|
}
|
||
|
|
||
|
function isMoveish(topLevelType) {
|
||
|
return topLevelType === topLevelTypes.topMouseMove ||
|
||
|
topLevelType === topLevelTypes.topTouchMove;
|
||
|
}
|
||
|
function isStartish(topLevelType) {
|
||
|
return topLevelType === topLevelTypes.topMouseDown ||
|
||
|
topLevelType === topLevelTypes.topTouchStart;
|
||
|
}
|
||
|
|
||
|
|
||
|
var validateEventDispatches;
|
||
|
if ("production" !== process.env.NODE_ENV) {
|
||
|
validateEventDispatches = function(event) {
|
||
|
var dispatchListeners = event._dispatchListeners;
|
||
|
var dispatchIDs = event._dispatchIDs;
|
||
|
|
||
|
var listenersIsArr = Array.isArray(dispatchListeners);
|
||
|
var idsIsArr = Array.isArray(dispatchIDs);
|
||
|
var IDsLen = idsIsArr ? dispatchIDs.length : dispatchIDs ? 1 : 0;
|
||
|
var listenersLen = listenersIsArr ?
|
||
|
dispatchListeners.length :
|
||
|
dispatchListeners ? 1 : 0;
|
||
|
|
||
|
("production" !== process.env.NODE_ENV ? invariant(
|
||
|
idsIsArr === listenersIsArr && IDsLen === listenersLen,
|
||
|
'EventPluginUtils: Invalid `event`.'
|
||
|
) : invariant(idsIsArr === listenersIsArr && IDsLen === listenersLen));
|
||
|
};
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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(event, cb) {
|
||
|
var dispatchListeners = event._dispatchListeners;
|
||
|
var dispatchIDs = event._dispatchIDs;
|
||
|
if ("production" !== process.env.NODE_ENV) {
|
||
|
validateEventDispatches(event);
|
||
|
}
|
||
|
if (Array.isArray(dispatchListeners)) {
|
||
|
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(event, dispatchListeners[i], dispatchIDs[i]);
|
||
|
}
|
||
|
} else if (dispatchListeners) {
|
||
|
cb(event, dispatchListeners, dispatchIDs);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Default implementation of PluginModule.executeDispatch().
|
||
|
* @param {SyntheticEvent} SyntheticEvent to handle
|
||
|
* @param {function} Application-level callback
|
||
|
* @param {string} domID DOM id to pass to the callback.
|
||
|
*/
|
||
|
function executeDispatch(event, listener, domID) {
|
||
|
event.currentTarget = injection.Mount.getNode(domID);
|
||
|
var returnValue = listener(event, domID);
|
||
|
event.currentTarget = null;
|
||
|
return returnValue;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Standard/simple iteration through an event's collected dispatches.
|
||
|
*/
|
||
|
function executeDispatchesInOrder(event, cb) {
|
||
|
forEachEventDispatch(event, cb);
|
||
|
event._dispatchListeners = null;
|
||
|
event._dispatchIDs = null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Standard/simple iteration through an event's collected dispatches, but stops
|
||
|
* at the first dispatch execution returning true, and returns that id.
|
||
|
*
|
||
|
* @return id of the first dispatch execution who's listener returns true, or
|
||
|
* null if no listener returned true.
|
||
|
*/
|
||
|
function executeDispatchesInOrderStopAtTrueImpl(event) {
|
||
|
var dispatchListeners = event._dispatchListeners;
|
||
|
var dispatchIDs = event._dispatchIDs;
|
||
|
if ("production" !== process.env.NODE_ENV) {
|
||
|
validateEventDispatches(event);
|
||
|
}
|
||
|
if (Array.isArray(dispatchListeners)) {
|
||
|
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](event, dispatchIDs[i])) {
|
||
|
return dispatchIDs[i];
|
||
|
}
|
||
|
}
|
||
|
} else if (dispatchListeners) {
|
||
|
if (dispatchListeners(event, dispatchIDs)) {
|
||
|
return dispatchIDs;
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @see executeDispatchesInOrderStopAtTrueImpl
|
||
|
*/
|
||
|
function executeDispatchesInOrderStopAtTrue(event) {
|
||
|
var ret = executeDispatchesInOrderStopAtTrueImpl(event);
|
||
|
event._dispatchIDs = null;
|
||
|
event._dispatchListeners = null;
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Execution of a "direct" dispatch - there must be at most one dispatch
|
||
|
* accumulated on the event or it is considered an error. It doesn't really make
|
||
|
* sense for an event with multiple dispatches (bubbled) to keep track of the
|
||
|
* return values at each dispatch execution, but it does tend to make sense when
|
||
|
* dealing with "direct" dispatches.
|
||
|
*
|
||
|
* @return The return value of executing the single dispatch.
|
||
|
*/
|
||
|
function executeDirectDispatch(event) {
|
||
|
if ("production" !== process.env.NODE_ENV) {
|
||
|
validateEventDispatches(event);
|
||
|
}
|
||
|
var dispatchListener = event._dispatchListeners;
|
||
|
var dispatchID = event._dispatchIDs;
|
||
|
("production" !== process.env.NODE_ENV ? invariant(
|
||
|
!Array.isArray(dispatchListener),
|
||
|
'executeDirectDispatch(...): Invalid `event`.'
|
||
|
) : invariant(!Array.isArray(dispatchListener)));
|
||
|
var res = dispatchListener ?
|
||
|
dispatchListener(event, dispatchID) :
|
||
|
null;
|
||
|
event._dispatchListeners = null;
|
||
|
event._dispatchIDs = null;
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {SyntheticEvent} event
|
||
|
* @return {bool} True iff number of dispatches accumulated is greater than 0.
|
||
|
*/
|
||
|
function hasDispatches(event) {
|
||
|
return !!event._dispatchListeners;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* General utilities that are useful in creating custom Event Plugins.
|
||
|
*/
|
||
|
var EventPluginUtils = {
|
||
|
isEndish: isEndish,
|
||
|
isMoveish: isMoveish,
|
||
|
isStartish: isStartish,
|
||
|
|
||
|
executeDirectDispatch: executeDirectDispatch,
|
||
|
executeDispatch: executeDispatch,
|
||
|
executeDispatchesInOrder: executeDispatchesInOrder,
|
||
|
executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue,
|
||
|
hasDispatches: hasDispatches,
|
||
|
injection: injection,
|
||
|
useTouchEvents: false
|
||
|
};
|
||
|
|
||
|
module.exports = EventPluginUtils;
|