text: /**
   * 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 EnterLeaveEventPlugin
   * @typechecks static-only
   */
  
  'use strict';
  
  var EventConstants = require('./EventConstants');
  var EventPropagators = require('./EventPropagators');
  var SyntheticMouseEvent = require('./SyntheticMouseEvent');
  
  var ReactMount = require('./ReactMount');
  var keyOf = require('fbjs/lib/keyOf');
  
  var topLevelTypes = EventConstants.topLevelTypes;
  var getFirstReactDOM = ReactMount.getFirstReactDOM;
  
  var eventTypes = {
    mouseEnter: {
      registrationName: keyOf({ onMouseEnter: null }),
      dependencies: [topLevelTypes.topMouseOut, topLevelTypes.topMouseOver]
    },
    mouseLeave: {
      registrationName: keyOf({ onMouseLeave: null }),
      dependencies: [topLevelTypes.topMouseOut, topLevelTypes.topMouseOver]
    }
  };
  
  var extractedEvents = [null, null];
  
  var EnterLeaveEventPlugin = {
  
    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, nativeEventTarget) {
      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 win;
      if (topLevelTarget.window === topLevelTarget) {
        // `topLevelTarget` is probably a window object.
        win = topLevelTarget;
      } else {
        // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
        var doc = topLevelTarget.ownerDocument;
        if (doc) {
          win = doc.defaultView || doc.parentWindow;
        } else {
          win = window;
        }
      }
  
      var from, to;
      if (topLevelType === topLevelTypes.topMouseOut) {
        from = topLevelTarget;
        to = getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement) || win;
      } else {
        from = win;
        to = topLevelTarget;
      }
  
      if (from === to) {
        // Nothing pertains to our managed components.
        return null;
      }
  
      var fromID = from ? ReactMount.getID(from) : '';
      var toID = to ? ReactMount.getID(to) : '';
  
      var leave = SyntheticMouseEvent.getPooled(eventTypes.mouseLeave, fromID, nativeEvent, nativeEventTarget);
      leave.type = 'mouseleave';
      leave.target = from;
      leave.relatedTarget = to;
  
      var enter = SyntheticMouseEvent.getPooled(eventTypes.mouseEnter, toID, nativeEvent, nativeEventTarget);
      enter.type = 'mouseenter';
      enter.target = to;
      enter.relatedTarget = from;
  
      EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID);
  
      extractedEvents[0] = leave;
      extractedEvents[1] = enter;
  
      return extractedEvents;
    }
  
  };
  
  module.exports = EnterLeaveEventPlugin;