text: /**
   * Copyright 2013-present, 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 ReactErrorUtils = require('ReactErrorUtils');
  
  var invariant = require('invariant');
  var warning = require('warning');
  
  /**
   * Injected dependencies:
   */
  
  /**
   * - `ComponentTree`: [required] Module that can convert between React instances
   *   and actual node references.
   */
  var ComponentTree;
  var TreeTraversal;
  var injection = {
    injectComponentTree: function(Injected) {
      ComponentTree = Injected;
      if (__DEV__) {
        warning(
          Injected &&
          Injected.getNodeFromInstance &&
          Injected.getInstanceFromNode,
          'EventPluginUtils.injection.injectComponentTree(...): Injected ' +
          'module is missing getNodeFromInstance or getInstanceFromNode.'
        );
      }
    },
    injectTreeTraversal: function(Injected) {
      TreeTraversal = Injected;
      if (__DEV__) {
        warning(
          Injected && Injected.isAncestor && Injected.getLowestCommonAncestor,
          'EventPluginUtils.injection.injectTreeTraversal(...): Injected ' +
          'module is missing isAncestor or getLowestCommonAncestor.'
        );
      }
    },
  };
  
  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 (__DEV__) {
    validateEventDispatches = function(event) {
      var dispatchListeners = event._dispatchListeners;
      var dispatchInstances = event._dispatchInstances;
  
      var listenersIsArr = Array.isArray(dispatchListeners);
      var listenersLen = listenersIsArr ?
        dispatchListeners.length :
        dispatchListeners ? 1 : 0;
  
      var instancesIsArr = Array.isArray(dispatchInstances);
      var instancesLen = instancesIsArr ?
        dispatchInstances.length :
        dispatchInstances ? 1 : 0;
  
      warning(
        instancesIsArr === listenersIsArr && instancesLen === listenersLen,
        'EventPluginUtils: Invalid `event`.'
      );
    };
  }
  
  /**
   * Dispatch the event to the listener.
   * @param {SyntheticEvent} event SyntheticEvent to handle
   * @param {boolean} simulated If the event is simulated (changes exn behavior)
   * @param {function} listener Application-level callback
   * @param {*} inst Internal component instance
   */
  function executeDispatch(event, simulated, listener, inst) {
    var type = event.type || 'unknown-event';
    event.currentTarget = EventPluginUtils.getNodeFromInstance(inst);
    if (simulated) {
      ReactErrorUtils.invokeGuardedCallbackWithCatch(
        type,
        listener,
        event
      );
    } else {
      ReactErrorUtils.invokeGuardedCallback(type, listener, event);
    }
    event.currentTarget = null;
  }
  
  /**
   * Standard/simple iteration through an event's collected dispatches.
   */
  function executeDispatchesInOrder(event, simulated) {
    var dispatchListeners = event._dispatchListeners;
    var dispatchInstances = event._dispatchInstances;
    if (__DEV__) {
      validateEventDispatches(event);
    }
    if (Array.isArray(dispatchListeners)) {
      for (var i = 0; i < dispatchListeners.length; i++) {
        if (event.isPropagationStopped()) {
          break;
        }
        // Listeners and Instances are two parallel arrays that are always in sync.
        executeDispatch(
          event,
          simulated,
          dispatchListeners[i],
          dispatchInstances[i]
        );
      }
    } else if (dispatchListeners) {
      executeDispatch(event, simulated, dispatchListeners, dispatchInstances);
    }
    event._dispatchListeners = null;
    event._dispatchInstances = null;
  }
  
  /**
   * Standard/simple iteration through an event's collected dispatches, but stops
   * at the first dispatch execution returning true, and returns that id.
   *
   * @return {?string} 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 dispatchInstances = event._dispatchInstances;
    if (__DEV__) {
      validateEventDispatches(event);
    }
    if (Array.isArray(dispatchListeners)) {
      for (var i = 0; i < dispatchListeners.length; i++) {
        if (event.isPropagationStopped()) {
          break;
        }
        // Listeners and Instances are two parallel arrays that are always in sync.
        if (dispatchListeners[i](event, dispatchInstances[i])) {
          return dispatchInstances[i];
        }
      }
    } else if (dispatchListeners) {
      if (dispatchListeners(event, dispatchInstances)) {
        return dispatchInstances;
      }
    }
    return null;
  }
  
  /**
   * @see executeDispatchesInOrderStopAtTrueImpl
   */
  function executeDispatchesInOrderStopAtTrue(event) {
    var ret = executeDispatchesInOrderStopAtTrueImpl(event);
    event._dispatchInstances = 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 (__DEV__) {
      validateEventDispatches(event);
    }
    var dispatchListener = event._dispatchListeners;
    var dispatchInstance = event._dispatchInstances;
    invariant(
      !Array.isArray(dispatchListener),
      'executeDirectDispatch(...): Invalid `event`.'
    );
    event.currentTarget = EventPluginUtils.getNodeFromInstance(dispatchInstance);
    var res = dispatchListener ? dispatchListener(event) : null;
    event.curentTarget = null;
    event._dispatchListeners = null;
    event._dispatchInstances = null;
    return res;
  }
  
  /**
   * @param {SyntheticEvent} event
   * @return {boolean} 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,
    executeDispatchesInOrder: executeDispatchesInOrder,
    executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue,
    hasDispatches: hasDispatches,
  
    getInstanceFromNode: function(node) {
      return ComponentTree.getInstanceFromNode(node);
    },
    getNodeFromInstance: function(node) {
      return ComponentTree.getNodeFromInstance(node);
    },
    isAncestor: function(a, b) {
      return TreeTraversal.isAncestor(a, b);
    },
    getLowestCommonAncestor: function(a, b) {
      return TreeTraversal.getLowestCommonAncestor(a, b);
    },
    getParentInstance: function(inst) {
      return TreeTraversal.getParentInstance(inst);
    },
    traverseTwoPhase: function(target, fn, arg) {
      return TreeTraversal.traverseTwoPhase(target, fn, arg);
    },
    traverseEnterLeave: function(from, to, fn, argFrom, argTo) {
      return TreeTraversal.traverseEnterLeave(from, to, fn, argFrom, argTo);
    },
  
    injection: injection,
  };
  
  module.exports = EventPluginUtils;
  