text: /**
   * Copyright 2013 Facebook, Inc.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   * @providesModule EnterLeaveEventPlugin
   * @typechecks static-only
   */
  
  "use strict";
  
  var EventConstants = require('EventConstants');
  var EventPropagators = require('EventPropagators');
  var ExecutionEnvironment = require('ExecutionEnvironment');
  var SyntheticMouseEvent = require('SyntheticMouseEvent');
  
  var ReactMount = require('ReactMount');
  var keyOf = require('keyOf');
  
  var topLevelTypes = EventConstants.topLevelTypes;
  var getFirstReactDOM = ReactMount.getFirstReactDOM;
  
  var eventTypes = {
    mouseEnter: {registrationName: keyOf({onMouseEnter: null})},
    mouseLeave: {registrationName: keyOf({onMouseLeave: 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) {
      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 from, to;
      if (topLevelType === topLevelTypes.topMouseOut) {
        from = topLevelTarget;
        to =
          getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement) ||
          ExecutionEnvironment.global;
      } else {
        from = ExecutionEnvironment.global;
        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
      );
      var enter = SyntheticMouseEvent.getPooled(
        eventTypes.mouseEnter,
        toID,
        nativeEvent
      );
  
      EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID);
      return [leave, enter];
    }
  
  };
  
  module.exports = EnterLeaveEventPlugin;
  