/
interactablePreventDefault.ts
114 lines (95 loc) · 3.47 KB
/
interactablePreventDefault.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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import { matchesSelector, nodeContains } from '../utils/domUtils'
import events from '../utils/events'
import * as is from '../utils/is'
import { getWindow } from '../utils/window'
declare module '@interactjs/core/Interactable' {
interface Interactable {
preventDefault: typeof preventDefault
checkAndPreventDefault: (event: Event) => void
}
}
function preventDefault (this: Interact.Interactable, newValue?: 'always' | 'never' | 'auto') {
if (/^(always|never|auto)$/.test(newValue)) {
this.options.preventDefault = newValue
return this
}
if (is.bool(newValue)) {
this.options.preventDefault = newValue ? 'always' : 'never'
return this
}
return this.options.preventDefault
}
function checkAndPreventDefault (interactable: Interact.Interactable, scope: Interact.Scope, event: Event) {
const setting = interactable.options.preventDefault
if (setting === 'never') { return }
if (setting === 'always') {
event.preventDefault()
return
}
// setting === 'auto'
// if the browser supports passive event listeners and isn't running on iOS,
// don't preventDefault of touch{start,move} events. CSS touch-action and
// user-select should be used instead of calling event.preventDefault().
if (events.supportsPassive && /^touch(start|move)$/.test(event.type)) {
const doc = getWindow(event.target).document
const docOptions = scope.getDocOptions(doc)
if (!(docOptions && docOptions.events) || docOptions.events.passive !== false) {
return
}
}
// don't preventDefault of pointerdown events
if (/^(mouse|pointer|touch)*(down|start)/i.test(event.type)) {
return
}
// don't preventDefault on editable elements
if (is.element(event.target) &&
matchesSelector(event.target, 'input,select,textarea,[contenteditable=true],[contenteditable=true] *')) {
return
}
event.preventDefault()
}
function onInteractionEvent ({ interaction, event }: { interaction: Interact.Interaction, event: Interact.PointerEventType }) {
if (interaction.interactable) {
interaction.interactable.checkAndPreventDefault(event as Event)
}
}
export function install (scope: Interact.Scope) {
/** @lends Interactable */
const { Interactable } = scope
/**
* Returns or sets whether to prevent the browser's default behaviour in
* response to pointer events. Can be set to:
* - `'always'` to always prevent
* - `'never'` to never prevent
* - `'auto'` to let interact.js try to determine what would be best
*
* @param {string} [newValue] `'always'`, `'never'` or `'auto'`
* @return {string | Interactable} The current setting or this Interactable
*/
Interactable.prototype.preventDefault = preventDefault
Interactable.prototype.checkAndPreventDefault = function (event) {
return checkAndPreventDefault(this, scope, event)
}
// prevent native HTML5 drag on interact.js target elements
scope.interactions.docEvents.push({
type: 'dragstart',
listener (event) {
for (const interaction of scope.interactions.list) {
if (interaction.element &&
(interaction.element === event.target ||
nodeContains(interaction.element, event.target))) {
interaction.interactable.checkAndPreventDefault(event)
return
}
}
},
})
}
export default {
id: 'core/interactablePreventDefault',
install,
listeners: ['down', 'move', 'up', 'cancel'].reduce((acc, eventType) => {
acc[`interactions:${eventType}`] = onInteractionEvent
return acc
}, {}),
}