-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
TouchEvents.ts
91 lines (76 loc) · 2.53 KB
/
TouchEvents.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import { Touch } from '@ephox/dom-globals';
import { Cell, Fun, Option, Throttler } from '@ephox/katamari';
import Editor from 'tinymce/core/api/Editor';
// This is based heavily on Alloy's TapEvent.ts, just modified to use TinyMCE's event system.
const SIGNIFICANT_MOVE = 5;
const LONGPRESS_DELAY = 400;
export interface TouchHistoryData {
x: () => number;
y: () => number;
target: () => any;
}
const getTouch = (event): Option<Touch> => {
if (event.touches === undefined || event.touches.length !== 1) {
return Option.none();
}
return Option.some(event.touches[0]);
};
const isFarEnough = (touch: Touch, data: TouchHistoryData): boolean => {
const distX = Math.abs(touch.clientX - data.x());
const distY = Math.abs(touch.clientY - data.y());
return distX > SIGNIFICANT_MOVE || distY > SIGNIFICANT_MOVE;
};
const setup = (editor: Editor) => {
const startData = Cell<Option<TouchHistoryData>>(Option.none());
const longpressFired = Cell<boolean>(false);
const debounceLongpress = Throttler.last((e) => {
editor.fire('longpress', { ...e, type: 'longpress' });
longpressFired.set(true);
}, LONGPRESS_DELAY);
editor.on('touchstart', (e) => {
getTouch(e).each((touch) => {
debounceLongpress.cancel();
const data = {
x: Fun.constant(touch.clientX),
y: Fun.constant(touch.clientY),
target: Fun.constant(e.target)
};
debounceLongpress.throttle(e);
longpressFired.set(false);
startData.set(Option.some(data));
});
}, true);
editor.on('touchmove', (e) => {
debounceLongpress.cancel();
getTouch(e).each((touch) => {
startData.get().each((data) => {
if (isFarEnough(touch, data)) {
startData.set(Option.none());
longpressFired.set(false);
editor.fire('longpresscancel');
}
});
});
}, true);
editor.on('touchend touchcancel', (e) => {
debounceLongpress.cancel();
if (e.type === 'touchcancel') {
return;
}
// Cancel the touchend event if a longpress was fired, otherwise fire the tap event
startData.get()
.filter((data) => data.target().isEqualNode(e.target))
.each(() => {
if (longpressFired.get()) {
e.preventDefault();
} else {
// Don't use "e" as the args for fire since it'll mutate the type. See TINY-3254
const result = editor.fire('tap', { touches: e.touches });
if (result.isDefaultPrevented()) {
e.preventDefault();
}
}
});
}, true);
};
export default { setup };