/**1* Copyright 2013-2015, Facebook, Inc.2* All rights reserved.3*4* This source code is licensed under the BSD-style license found in the5* LICENSE file in the root directory of this source tree. An additional grant6* of patent rights can be found in the PATENTS file in the same directory.7*8* @providesModule EventPropagators9*/1011'use strict';1213var EventConstants = require("./EventConstants");14var EventPluginHub = require("./EventPluginHub");1516var accumulateInto = require("./accumulateInto");17var forEachAccumulated = require("./forEachAccumulated");1819var PropagationPhases = EventConstants.PropagationPhases;20var getListener = EventPluginHub.getListener;2122/**23* Some event types have a notion of different registration names for different24* "phases" of propagation. This finds listeners by a given phase.25*/26function listenerAtPhase(id, event, propagationPhase) {27var registrationName =28event.dispatchConfig.phasedRegistrationNames[propagationPhase];29return getListener(id, registrationName);30}3132/**33* Tags a `SyntheticEvent` with dispatched listeners. Creating this function34* here, allows us to not have to bind or create functions for each event.35* Mutating the event's members allows us to not have to create a wrapping36* "dispatch" object that pairs the event with the listener.37*/38function accumulateDirectionalDispatches(domID, upwards, event) {39if ("production" !== process.env.NODE_ENV) {40if (!domID) {41throw new Error('Dispatching id must not be null');42}43}44var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured;45var listener = listenerAtPhase(domID, event, phase);46if (listener) {47event._dispatchListeners =48accumulateInto(event._dispatchListeners, listener);49event._dispatchIDs = accumulateInto(event._dispatchIDs, domID);50}51}5253/**54* Collect dispatches (must be entirely collected before dispatching - see unit55* tests). Lazily allocate the array to conserve memory. We must loop through56* each event and perform the traversal for each one. We can not perform a57* single traversal for the entire collection of events because each event may58* have a different target.59*/60function accumulateTwoPhaseDispatchesSingle(event) {61if (event && event.dispatchConfig.phasedRegistrationNames) {62EventPluginHub.injection.getInstanceHandle().traverseTwoPhase(63event.dispatchMarker,64accumulateDirectionalDispatches,65event66);67}68}697071/**72* Accumulates without regard to direction, does not look for phased73* registration names. Same as `accumulateDirectDispatchesSingle` but without74* requiring that the `dispatchMarker` be the same as the dispatched ID.75*/76function accumulateDispatches(id, ignoredDirection, event) {77if (event && event.dispatchConfig.registrationName) {78var registrationName = event.dispatchConfig.registrationName;79var listener = getListener(id, registrationName);80if (listener) {81event._dispatchListeners =82accumulateInto(event._dispatchListeners, listener);83event._dispatchIDs = accumulateInto(event._dispatchIDs, id);84}85}86}8788/**89* Accumulates dispatches on an `SyntheticEvent`, but only for the90* `dispatchMarker`.91* @param {SyntheticEvent} event92*/93function accumulateDirectDispatchesSingle(event) {94if (event && event.dispatchConfig.registrationName) {95accumulateDispatches(event.dispatchMarker, null, event);96}97}9899function accumulateTwoPhaseDispatches(events) {100forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);101}102103function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) {104EventPluginHub.injection.getInstanceHandle().traverseEnterLeave(105fromID,106toID,107accumulateDispatches,108leave,109enter110);111}112113114function accumulateDirectDispatches(events) {115forEachAccumulated(events, accumulateDirectDispatchesSingle);116}117118119120/**121* A small set of propagation patterns, each of which will accept a small amount122* of information, and generate a set of "dispatch ready event objects" - which123* are sets of events that have already been annotated with a set of dispatched124* listener functions/ids. The API is designed this way to discourage these125* propagation strategies from actually executing the dispatches, since we126* always want to collect the entire set of dispatches before executing event a127* single one.128*129* @constructor EventPropagators130*/131var EventPropagators = {132accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches,133accumulateDirectDispatches: accumulateDirectDispatches,134accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches135};136137module.exports = EventPropagators;138139140