UNPKG

d2-ui

Version:
171 lines (148 loc) 4.83 kB
/** * Copyright 2013-2014 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 TapEventPlugin * @typechecks static-only */ "use strict"; var EventConstants = require('react/lib/EventConstants'); var EventPluginUtils = require('react/lib/EventPluginUtils'); var EventPropagators = require('react/lib/EventPropagators'); var SyntheticUIEvent = require('react/lib/SyntheticUIEvent'); var TouchEventUtils = require('./TouchEventUtils'); var ViewportMetrics = require('react/lib/ViewportMetrics'); var keyOf = require('fbjs/lib/keyOf'); var topLevelTypes = EventConstants.topLevelTypes; var isStartish = EventPluginUtils.isStartish; var isEndish = EventPluginUtils.isEndish; var isTouch = function(topLevelType) { var touchTypes = [ topLevelTypes.topTouchCancel, topLevelTypes.topTouchEnd, topLevelTypes.topTouchStart, topLevelTypes.topTouchMove ]; return touchTypes.indexOf(topLevelType) >= 0; } /** * Number of pixels that are tolerated in between a `touchStart` and `touchEnd` * in order to still be considered a 'tap' event. */ var tapMoveThreshold = 10; var ignoreMouseThreshold = 750; var startCoords = {x: null, y: null}; var lastTouchEvent = null; var Axis = { x: {page: 'pageX', client: 'clientX', envScroll: 'currentPageScrollLeft'}, y: {page: 'pageY', client: 'clientY', envScroll: 'currentPageScrollTop'} }; function getAxisCoordOfEvent(axis, nativeEvent) { var singleTouch = TouchEventUtils.extractSingleTouch(nativeEvent); if (singleTouch) { return singleTouch[axis.page]; } return axis.page in nativeEvent ? nativeEvent[axis.page] : nativeEvent[axis.client] + ViewportMetrics[axis.envScroll]; } function getDistance(coords, nativeEvent) { var pageX = getAxisCoordOfEvent(Axis.x, nativeEvent); var pageY = getAxisCoordOfEvent(Axis.y, nativeEvent); return Math.pow( Math.pow(pageX - coords.x, 2) + Math.pow(pageY - coords.y, 2), 0.5 ); } var touchEvents = [ topLevelTypes.topTouchStart, topLevelTypes.topTouchCancel, topLevelTypes.topTouchEnd, topLevelTypes.topTouchMove, ]; var dependencies = [ topLevelTypes.topMouseDown, topLevelTypes.topMouseMove, topLevelTypes.topMouseUp, ].concat(touchEvents); var eventTypes = { touchTap: { phasedRegistrationNames: { bubbled: keyOf({onTouchTap: null}), captured: keyOf({onTouchTapCapture: null}) }, dependencies: dependencies } }; var now = (function() { if (Date.now) { return Date.now; } else { // IE8 support: http://stackoverflow.com/questions/9430357/please-explain-why-and-how-new-date-works-as-workaround-for-date-now-in return function () { return +new Date; } } })(); function createTapEventPlugin(shouldRejectClick) { return { tapMoveThreshold: tapMoveThreshold, ignoreMouseThreshold: ignoreMouseThreshold, eventTypes: eventTypes, /** * @param {string} topLevelType Record from `EventConstants`. * @param {DOMEventTarget} targetInst The listening component root node. * @param {object} nativeEvent Native browser event. * @return {*} An accumulation of synthetic events. * @see {EventPluginHub.extractEvents} */ extractEvents: function( topLevelType, targetInst, nativeEvent, nativeEventTarget ) { if (isTouch(topLevelType)) { lastTouchEvent = now(); } else { if (shouldRejectClick(lastTouchEvent, now())) { return null; } } if (!isStartish(topLevelType) && !isEndish(topLevelType)) { return null; } var event = null; var distance = getDistance(startCoords, nativeEvent); if (isEndish(topLevelType) && distance < tapMoveThreshold) { event = SyntheticUIEvent.getPooled( eventTypes.touchTap, targetInst, nativeEvent, nativeEventTarget ); } if (isStartish(topLevelType)) { startCoords.x = getAxisCoordOfEvent(Axis.x, nativeEvent); startCoords.y = getAxisCoordOfEvent(Axis.y, nativeEvent); } else if (isEndish(topLevelType)) { startCoords.x = 0; startCoords.y = 0; } EventPropagators.accumulateTwoPhaseDispatches(event); return event; } }; } module.exports = createTapEventPlugin;