/** * 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("./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) { 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 ); leave.type = 'mouseleave'; leave.target = from; leave.relatedTarget = to; var enter = SyntheticMouseEvent.getPooled( eventTypes.mouseEnter, toID, nativeEvent ); 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;