Skip to content

Instantly share code, notes, and snippets.

@dozoisch
Created January 22, 2016 03:49
Show Gist options
  • Save dozoisch/2dacd84ef3e28d78a42d to your computer and use it in GitHub Desktop.
Save dozoisch/2dacd84ef3e28d78a42d to your computer and use it in GitHub Desktop.
Tests about react TapEventPlugin to add Support for touchPress.
/**
* 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
*/
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 EventPluginHub = require('react/lib/EventPluginHub');
var keyOf = require('fbjs/lib/keyOf');
var topLevelTypes = EventConstants.topLevelTypes;
var isStartish = EventPluginUtils.isStartish;
var isEndish = EventPluginUtils.isEndish;
var isMoveish = EventPluginUtils.isMoveish;
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 longPressDelay = 500;
var startTime = null;
var longPressTimeout = null;
var startCoords = { x: null, y: null };
var lastTouchEvent = null;
var isCanceled = false;
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,
},
touchPress: {
phasedRegistrationNames: {
bubbled: keyOf({ onTouchPress: null }),
captured: keyOf({ onTouchPressCapture: null }),
},
dependencies,
},
};
const now = Date.now;
var TapEventPlugin = {
tapMoveThreshold,
ignoreMouseThreshold,
eventTypes,
/**
* @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(topLevelType, topLevelTarget, topLevelTargetID, nativeEvent, nativeEventTarget) {
if (isTouch(topLevelType)) {
lastTouchEvent = now();
} else {
if (lastTouchEvent && (now() - lastTouchEvent) < ignoreMouseThreshold) {
return null;
}
}
var isEnd = isEndish(topLevelType);
var isStart = isStartish(topLevelType);
if (isMoveish(topLevelType)) {
if (isCanceled || getDistance(startCoords, nativeEvent) > tapMoveThreshold) {
clearTimeout(longPressTimeout);
isCanceled = true;
return null;
}
} else if (isStart) {
isCanceled = false;
startTime = now();
longPressTimeout = setTimeout(function() {
var pressEvent = SyntheticUIEvent.getPooled(
eventTypes.touchPress,
topLevelTargetID,
nativeEvent,
nativeEventTarget
);
EventPropagators.accumulateTwoPhaseDispatches(pressEvent);
EventPluginHub.enqueueEvents(pressEvent);
EventPluginHub.processEventQueue(false);
}, longPressDelay);
} else if (isEnd) {
clearTimeout(longPressTimeout);
}
if ((!isStart && !isEnd) || isCanceled || now() - startTime > longPressDelay) {
return null;
}
var event = null;
var distance = getDistance(startCoords, nativeEvent);
if (isEnd && distance < tapMoveThreshold) {
event = SyntheticUIEvent.getPooled(
eventTypes.touchTap,
topLevelTargetID,
nativeEvent,
nativeEventTarget
);
}
if (isStart) {
startCoords.x = getAxisCoordOfEvent(Axis.x, nativeEvent);
startCoords.y = getAxisCoordOfEvent(Axis.y, nativeEvent);
} else if (isEnd) {
startCoords.x = 0;
startCoords.y = 0;
}
EventPropagators.accumulateTwoPhaseDispatches(event);
return event;
},
};
export default TapEventPlugin;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment