Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ let currentResponder: ResponderInstance = {
node: null,
idPath: null
};
const responderTouchHistoryStore = new ResponderTouchHistoryStore();

function changeCurrentResponder(responder: ResponderInstance) {
currentResponder = responder;
Expand Down Expand Up @@ -294,7 +295,7 @@ function eventListener(domEvent: any) {
const isEndEvent = isEndish(eventType);
const isScrollEvent = isScroll(eventType);
const isSelectionChangeEvent = isSelectionChange(eventType);
const responderEvent = createResponderEvent(domEvent);
const responderEvent = createResponderEvent(domEvent, responderTouchHistoryStore);

/**
* Record the state of active pointers
Expand All @@ -310,7 +311,7 @@ function eventListener(domEvent: any) {
trackedTouchCount = 0;
}
}
ResponderTouchHistoryStore.recordTouchTrack(eventType, responderEvent.nativeEvent);
responderTouchHistoryStore.recordTouchTrack(eventType, responderEvent.nativeEvent);
}

/**
Expand Down Expand Up @@ -646,7 +647,7 @@ export function terminateResponder() {
if (id != null && node != null) {
const { onResponderTerminate } = getResponderConfig(id);
if (onResponderTerminate != null) {
const event = createResponderEvent({});
const event = createResponderEvent({}, responderTouchHistoryStore);
event.currentTarget = node;
onResponderTerminate(event);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,6 @@ type TouchRecord = {|

const __DEV__ = process.env.NODE_ENV !== 'production';
const MAX_TOUCH_BANK = 20;
const touchBank: Array<TouchRecord> = [];
const touchHistory = {
touchBank,
numberActiveTouches: 0,
// If there is only one active touch, we remember its location. This prevents
// us having to loop through all of the touches all the time in the most
// common case.
indexOfSingleActiveTouch: -1,
mostRecentTimeStamp: 0
};

function timestampForTouch(touch: Touch): number {
// The legacy internal implementation provides "timeStamp", which has been
Expand Down Expand Up @@ -97,106 +87,117 @@ function getTouchIdentifier({ identifier }: Touch): number {
return identifier;
}

function recordTouchStart(touch: Touch): void {
const identifier = getTouchIdentifier(touch);
const touchRecord = touchBank[identifier];
if (touchRecord) {
resetTouchRecord(touchRecord, touch);
} else {
touchBank[identifier] = createTouchRecord(touch);
}
touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
}
export default class ResponderTouchHistoryStore {
_touchBank: Array<TouchRecord> = [];
_touchHistory = {
touchBank: this._touchBank,
numberActiveTouches: 0,
// If there is only one active touch, we remember its location. This prevents
// us having to loop through all of the touches all the time in the most
// common case.
indexOfSingleActiveTouch: -1,
mostRecentTimeStamp: 0
};

function recordTouchMove(touch: Touch): void {
const touchRecord = touchBank[getTouchIdentifier(touch)];
if (touchRecord) {
touchRecord.touchActive = true;
touchRecord.previousPageX = touchRecord.currentPageX;
touchRecord.previousPageY = touchRecord.currentPageY;
touchRecord.previousTimeStamp = touchRecord.currentTimeStamp;
touchRecord.currentPageX = touch.pageX;
touchRecord.currentPageY = touch.pageY;
touchRecord.currentTimeStamp = timestampForTouch(touch);
touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
} else {
console.warn(
'Cannot record touch move without a touch start.\n',
`Touch Move: ${printTouch(touch)}\n`,
`Touch Bank: ${printTouchBank()}`
);
}
}
_recordTouchStart = (touch: Touch): void => {
const identifier = getTouchIdentifier(touch);
const touchRecord = this._touchBank[identifier];
if (touchRecord) {
resetTouchRecord(touchRecord, touch);
} else {
this._touchBank[identifier] = createTouchRecord(touch);
}
this._touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
};

function recordTouchEnd(touch: Touch): void {
const touchRecord = touchBank[getTouchIdentifier(touch)];
if (touchRecord) {
touchRecord.touchActive = false;
touchRecord.previousPageX = touchRecord.currentPageX;
touchRecord.previousPageY = touchRecord.currentPageY;
touchRecord.previousTimeStamp = touchRecord.currentTimeStamp;
touchRecord.currentPageX = touch.pageX;
touchRecord.currentPageY = touch.pageY;
touchRecord.currentTimeStamp = timestampForTouch(touch);
touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
} else {
console.warn(
'Cannot record touch end without a touch start.\n',
`Touch End: ${printTouch(touch)}\n`,
`Touch Bank: ${printTouchBank()}`
);
}
}
_recordTouchMove = (touch: Touch): void => {
const touchRecord = this._touchBank[getTouchIdentifier(touch)];
if (touchRecord) {
touchRecord.touchActive = true;
touchRecord.previousPageX = touchRecord.currentPageX;
touchRecord.previousPageY = touchRecord.currentPageY;
touchRecord.previousTimeStamp = touchRecord.currentTimeStamp;
touchRecord.currentPageX = touch.pageX;
touchRecord.currentPageY = touch.pageY;
touchRecord.currentTimeStamp = timestampForTouch(touch);
this._touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
} else {
console.warn(
'Cannot record touch move without a touch start.\n',
`Touch Move: ${this._printTouch(touch)}\n`,
`Touch Bank: ${this._printTouchBank()}`
);
}
};

function printTouch(touch: Touch): string {
return JSON.stringify({
identifier: touch.identifier,
pageX: touch.pageX,
pageY: touch.pageY,
timestamp: timestampForTouch(touch)
});
}
_recordTouchEnd = (touch: Touch): void => {
const touchRecord = this._touchBank[getTouchIdentifier(touch)];
if (touchRecord) {
touchRecord.touchActive = false;
touchRecord.previousPageX = touchRecord.currentPageX;
touchRecord.previousPageY = touchRecord.currentPageY;
touchRecord.previousTimeStamp = touchRecord.currentTimeStamp;
touchRecord.currentPageX = touch.pageX;
touchRecord.currentPageY = touch.pageY;
touchRecord.currentTimeStamp = timestampForTouch(touch);
this._touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
} else {
console.warn(
'Cannot record touch end without a touch start.\n',
`Touch End: ${this._printTouch(touch)}\n`,
`Touch Bank: ${this._printTouchBank()}`
);
}
};

function printTouchBank(): string {
let printed = JSON.stringify(touchBank.slice(0, MAX_TOUCH_BANK));
if (touchBank.length > MAX_TOUCH_BANK) {
printed += ' (original size: ' + touchBank.length + ')';
_printTouch(touch: Touch): string {
return JSON.stringify({
identifier: touch.identifier,
pageX: touch.pageX,
pageY: touch.pageY,
timestamp: timestampForTouch(touch)
});
}

_printTouchBank(): string {
let printed = JSON.stringify(this._touchBank.slice(0, MAX_TOUCH_BANK));
if (this._touchBank.length > MAX_TOUCH_BANK) {
printed += ' (original size: ' + this._touchBank.length + ')';
}
return printed;
}
return printed;
}

const ResponderTouchHistoryStore = {
recordTouchTrack(topLevelType: string, nativeEvent: TouchEvent): void {
if (isMoveish(topLevelType)) {
nativeEvent.changedTouches.forEach(recordTouchMove);
nativeEvent.changedTouches.forEach(this._recordTouchMove);
} else if (isStartish(topLevelType)) {
nativeEvent.changedTouches.forEach(recordTouchStart);
touchHistory.numberActiveTouches = nativeEvent.touches.length;
if (touchHistory.numberActiveTouches === 1) {
touchHistory.indexOfSingleActiveTouch = nativeEvent.touches[0].identifier;
nativeEvent.changedTouches.forEach(this._recordTouchStart);
this._touchHistory.numberActiveTouches = nativeEvent.touches.length;
if (this._touchHistory.numberActiveTouches === 1) {
this._touchHistory.indexOfSingleActiveTouch = nativeEvent.touches[0].identifier;
}
} else if (isEndish(topLevelType)) {
nativeEvent.changedTouches.forEach(recordTouchEnd);
touchHistory.numberActiveTouches = nativeEvent.touches.length;
if (touchHistory.numberActiveTouches === 1) {
for (let i = 0; i < touchBank.length; i++) {
const touchTrackToCheck = touchBank[i];
nativeEvent.changedTouches.forEach(this._recordTouchEnd);
this._touchHistory.numberActiveTouches = nativeEvent.touches.length;
if (this._touchHistory.numberActiveTouches === 1) {
for (let i = 0; i < this._touchBank.length; i++) {
const touchTrackToCheck = this._touchBank[i];
if (touchTrackToCheck != null && touchTrackToCheck.touchActive) {
touchHistory.indexOfSingleActiveTouch = i;
this._touchHistory.indexOfSingleActiveTouch = i;
break;
}
}
if (__DEV__) {
const activeRecord = touchBank[touchHistory.indexOfSingleActiveTouch];
const activeRecord = this._touchBank[this._touchHistory.indexOfSingleActiveTouch];
if (!(activeRecord != null && activeRecord.touchActive)) {
console.error('Cannot find single active touch.');
}
}
}
}
},

touchHistory
};
}

export default ResponderTouchHistoryStore;
get touchHistory() {
return this._touchHistory;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import type { TouchEvent } from './ResponderEventTypes';

import getBoundingClientRect from '../../modules/getBoundingClientRect';
import ResponderTouchHistoryStore from './ResponderTouchHistoryStore';
import type ResponderTouchHistoryStore from './ResponderTouchHistoryStore';

export type ResponderEvent = {|
bubbles: boolean,
Expand Down Expand Up @@ -70,7 +70,10 @@ function normalizeIdentifier(identifier) {
* Converts a native DOM event to a ResponderEvent.
* Mouse events are transformed into fake touch events.
*/
export default function createResponderEvent(domEvent: any): ResponderEvent {
export default function createResponderEvent(
domEvent: any,
responderTouchHistoryStore: ResponderTouchHistoryStore
): ResponderEvent {
let rect;
let propagationWasStopped = false;
let changedTouches;
Expand Down Expand Up @@ -182,7 +185,7 @@ export default function createResponderEvent(domEvent: any): ResponderEvent {
},
target: domEvent.target,
timeStamp: timestamp,
touchHistory: ResponderTouchHistoryStore.touchHistory
touchHistory: responderTouchHistoryStore.touchHistory
};

// Using getters and functions serves two purposes:
Expand Down