quasar
Version:
Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time
276 lines (227 loc) • 7.98 kB
JavaScript
import { client } from '../plugins/Platform.js'
import { createDirective } from '../utils/private/create.js'
import { getModifierDirections, shouldStart } from '../utils/private/touch.js'
import { addEvt, cleanEvt, position, leftClick, stopAndPrevent, preventDraggable, noop } from '../utils/event.js'
import { clearSelection } from '../utils/private/selection.js'
import getSSRProps from '../utils/private/noop-ssr-directive-transform.js'
function parseArg (arg) {
// delta (min velocity -- dist / time)
// mobile min distance on first move
// desktop min distance until deciding if it's a swipe or not
const data = [ 0.06, 6, 50 ]
if (typeof arg === 'string' && arg.length) {
arg.split(':').forEach((val, index) => {
const v = parseFloat(val)
v && (data[ index ] = v)
})
}
return data
}
export default createDirective(__QUASAR_SSR_SERVER__
? { name: 'touch-swipe', getSSRProps }
: {
name: 'touch-swipe',
beforeMount (el, { value, arg, modifiers }) {
// early return, we don't need to do anything
if (modifiers.mouse !== true && client.has.touch !== true) {
return
}
const mouseCapture = modifiers.mouseCapture === true ? 'Capture' : ''
const ctx = {
handler: value,
sensitivity: parseArg(arg),
direction: getModifierDirections(modifiers),
noop,
mouseStart (evt) {
if (shouldStart(evt, ctx) && leftClick(evt)) {
addEvt(ctx, 'temp', [
[ document, 'mousemove', 'move', `notPassive${ mouseCapture }` ],
[ document, 'mouseup', 'end', 'notPassiveCapture' ]
])
ctx.start(evt, true)
}
},
touchStart (evt) {
if (shouldStart(evt, ctx)) {
const target = evt.target
addEvt(ctx, 'temp', [
[ target, 'touchmove', 'move', 'notPassiveCapture' ],
[ target, 'touchcancel', 'end', 'notPassiveCapture' ],
[ target, 'touchend', 'end', 'notPassiveCapture' ]
])
ctx.start(evt)
}
},
start (evt, mouseEvent) {
client.is.firefox === true && preventDraggable(el, true)
const pos = position(evt)
ctx.event = {
x: pos.left,
y: pos.top,
time: Date.now(),
mouse: mouseEvent === true,
dir: false
}
},
move (evt) {
if (ctx.event === void 0) {
return
}
if (ctx.event.dir !== false) {
stopAndPrevent(evt)
return
}
const time = Date.now() - ctx.event.time
if (time === 0) {
return
}
const
pos = position(evt),
distX = pos.left - ctx.event.x,
absX = Math.abs(distX),
distY = pos.top - ctx.event.y,
absY = Math.abs(distY)
if (ctx.event.mouse !== true) {
if (absX < ctx.sensitivity[ 1 ] && absY < ctx.sensitivity[ 1 ]) {
ctx.end(evt)
return
}
}
else if (absX < ctx.sensitivity[ 2 ] && absY < ctx.sensitivity[ 2 ]) {
return
}
const
velX = absX / time,
velY = absY / time
if (
ctx.direction.vertical === true
&& absX < absY
&& absX < 100
&& velY > ctx.sensitivity[ 0 ]
) {
ctx.event.dir = distY < 0 ? 'up' : 'down'
}
if (
ctx.direction.horizontal === true
&& absX > absY
&& absY < 100
&& velX > ctx.sensitivity[ 0 ]
) {
ctx.event.dir = distX < 0 ? 'left' : 'right'
}
if (
ctx.direction.up === true
&& absX < absY
&& distY < 0
&& absX < 100
&& velY > ctx.sensitivity[ 0 ]
) {
ctx.event.dir = 'up'
}
if (
ctx.direction.down === true
&& absX < absY
&& distY > 0
&& absX < 100
&& velY > ctx.sensitivity[ 0 ]
) {
ctx.event.dir = 'down'
}
if (
ctx.direction.left === true
&& absX > absY
&& distX < 0
&& absY < 100
&& velX > ctx.sensitivity[ 0 ]
) {
ctx.event.dir = 'left'
}
if (
ctx.direction.right === true
&& absX > absY
&& distX > 0
&& absY < 100
&& velX > ctx.sensitivity[ 0 ]
) {
ctx.event.dir = 'right'
}
if (ctx.event.dir !== false) {
stopAndPrevent(evt)
if (ctx.event.mouse === true) {
document.body.classList.add('no-pointer-events--children')
document.body.classList.add('non-selectable')
clearSelection()
ctx.styleCleanup = withDelay => {
ctx.styleCleanup = void 0
document.body.classList.remove('non-selectable')
const remove = () => {
document.body.classList.remove('no-pointer-events--children')
}
if (withDelay === true) { setTimeout(remove, 50) }
else { remove() }
}
}
ctx.handler({
evt,
touch: ctx.event.mouse !== true,
mouse: ctx.event.mouse,
direction: ctx.event.dir,
duration: time,
distance: {
x: absX,
y: absY
}
})
}
else {
ctx.end(evt)
}
},
end (evt) {
if (ctx.event === void 0) {
return
}
cleanEvt(ctx, 'temp')
client.is.firefox === true && preventDraggable(el, false)
ctx.styleCleanup !== void 0 && ctx.styleCleanup(true)
evt !== void 0 && ctx.event.dir !== false && stopAndPrevent(evt)
ctx.event = void 0
}
}
el.__qtouchswipe = ctx
if (modifiers.mouse === true) {
// account for UMD too where modifiers will be lowercased to work
const capture = modifiers.mouseCapture === true || modifiers.mousecapture === true
? 'Capture'
: ''
addEvt(ctx, 'main', [
[ el, 'mousedown', 'mouseStart', `passive${ capture }` ]
])
}
client.has.touch === true && addEvt(ctx, 'main', [
[ el, 'touchstart', 'touchStart', `passive${ modifiers.capture === true ? 'Capture' : '' }` ],
[ el, 'touchmove', 'noop', 'notPassiveCapture' ] // cannot be passive (ex: iOS scroll)
])
},
updated (el, bindings) {
const ctx = el.__qtouchswipe
if (ctx !== void 0) {
if (bindings.oldValue !== bindings.value) {
typeof bindings.value !== 'function' && ctx.end()
ctx.handler = bindings.value
}
ctx.direction = getModifierDirections(bindings.modifiers)
}
},
beforeUnmount (el) {
const ctx = el.__qtouchswipe
if (ctx !== void 0) {
cleanEvt(ctx, 'main')
cleanEvt(ctx, 'temp')
client.is.firefox === true && preventDraggable(el, false)
ctx.styleCleanup !== void 0 && ctx.styleCleanup()
delete el.__qtouchswipe
}
}
}
)