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.
138 lines
4.5 KiB
138 lines
4.5 KiB
/** |
|
* 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 EventPropagators |
|
*/ |
|
|
|
'use strict'; |
|
|
|
var EventConstants = require("./EventConstants"); |
|
var EventPluginHub = require("./EventPluginHub"); |
|
|
|
var accumulateInto = require("./accumulateInto"); |
|
var forEachAccumulated = require("./forEachAccumulated"); |
|
|
|
var PropagationPhases = EventConstants.PropagationPhases; |
|
var getListener = EventPluginHub.getListener; |
|
|
|
/** |
|
* 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, event, propagationPhase) { |
|
var registrationName = |
|
event.dispatchConfig.phasedRegistrationNames[propagationPhase]; |
|
return getListener(id, registrationName); |
|
} |
|
|
|
/** |
|
* 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, event) { |
|
if ("production" !== process.env.NODE_ENV) { |
|
if (!domID) { |
|
throw new Error('Dispatching id must not be null'); |
|
} |
|
} |
|
var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured; |
|
var listener = listenerAtPhase(domID, event, phase); |
|
if (listener) { |
|
event._dispatchListeners = |
|
accumulateInto(event._dispatchListeners, listener); |
|
event._dispatchIDs = accumulateInto(event._dispatchIDs, domID); |
|
} |
|
} |
|
|
|
/** |
|
* Collect dispatches (must be entirely collected before dispatching - see unit |
|
* tests). Lazily allocate the array to conserve memory. We must loop through |
|
* each event and perform the traversal for each one. We can not perform a |
|
* single traversal for the entire collection of events because each event may |
|
* have a different target. |
|
*/ |
|
function accumulateTwoPhaseDispatchesSingle(event) { |
|
if (event && event.dispatchConfig.phasedRegistrationNames) { |
|
EventPluginHub.injection.getInstanceHandle().traverseTwoPhase( |
|
event.dispatchMarker, |
|
accumulateDirectionalDispatches, |
|
event |
|
); |
|
} |
|
} |
|
|
|
|
|
/** |
|
* Accumulates without regard to direction, does not look for phased |
|
* registration names. Same as `accumulateDirectDispatchesSingle` but without |
|
* requiring that the `dispatchMarker` be the same as the dispatched ID. |
|
*/ |
|
function accumulateDispatches(id, ignoredDirection, event) { |
|
if (event && event.dispatchConfig.registrationName) { |
|
var registrationName = event.dispatchConfig.registrationName; |
|
var listener = getListener(id, registrationName); |
|
if (listener) { |
|
event._dispatchListeners = |
|
accumulateInto(event._dispatchListeners, listener); |
|
event._dispatchIDs = accumulateInto(event._dispatchIDs, id); |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* Accumulates dispatches on an `SyntheticEvent`, but only for the |
|
* `dispatchMarker`. |
|
* @param {SyntheticEvent} event |
|
*/ |
|
function accumulateDirectDispatchesSingle(event) { |
|
if (event && event.dispatchConfig.registrationName) { |
|
accumulateDispatches(event.dispatchMarker, null, event); |
|
} |
|
} |
|
|
|
function accumulateTwoPhaseDispatches(events) { |
|
forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); |
|
} |
|
|
|
function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) { |
|
EventPluginHub.injection.getInstanceHandle().traverseEnterLeave( |
|
fromID, |
|
toID, |
|
accumulateDispatches, |
|
leave, |
|
enter |
|
); |
|
} |
|
|
|
|
|
function accumulateDirectDispatches(events) { |
|
forEachAccumulated(events, accumulateDirectDispatchesSingle); |
|
} |
|
|
|
|
|
|
|
/** |
|
* A small set of propagation patterns, each of which will accept a small amount |
|
* of information, and generate a set of "dispatch ready event objects" - which |
|
* are sets of events that have already been annotated with a set of dispatched |
|
* listener functions/ids. The API is designed this way to discourage these |
|
* propagation strategies from actually executing the dispatches, since we |
|
* always want to collect the entire set of dispatches before executing event a |
|
* single one. |
|
* |
|
* @constructor EventPropagators |
|
*/ |
|
var EventPropagators = { |
|
accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches, |
|
accumulateDirectDispatches: accumulateDirectDispatches, |
|
accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches |
|
}; |
|
|
|
module.exports = EventPropagators;
|
|
|