/** * 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; var to; var fromID = ''; var toID = ''; if (topLevelType === topLevelTypes.topMouseOut) { from = topLevelTarget; fromID = topLevelTargetID; to = getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement); if (to) { toID = ReactMount.getID(to); } else { to = win; } to = to || win; } else { from = win; to = topLevelTarget; toID = topLevelTargetID; } if (from === to) { // Nothing pertains to our managed components. return null; } 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;