UNPKG

quasar

Version:

Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time

266 lines (209 loc) 7.41 kB
import Platform from '../plugins/Platform.js' import { position, leftClick, stopAndPrevent, prevent, listenOpts } from '../utils/event.js' import { setObserver, removeObserver } from '../utils/touch.js' import { clearSelection } from '../utils/selection.js' const keyCodes = { esc: 27, tab: 9, enter: 13, space: 32, up: 38, left: 37, right: 39, down: 40, 'delete': [8, 46] }, keyRegex = new RegExp(`^([\\d+]+|${Object.keys(keyCodes).join('|')})$`, 'i') function shouldEnd (evt, origin) { const { top, left } = position(evt) return Math.abs(left - origin.left) >= 7 || Math.abs(top - origin.top) >= 7 } const docEvtOpts = listenOpts.notPassiveCapture export default { name: 'touch-repeat', bind (el, { modifiers, value, arg }) { if (el.__qtouchrepeat) { el.__qtouchrepeat_old = el.__qtouchrepeat } const keyboard = Object.keys(modifiers).reduce((acc, key) => { if (keyRegex.test(key)) { const keyCode = parseInt(key, 10) acc.push(keyCode || keyCodes[key.toLowerCase()]) } return acc }, []) // early return, we don't need to do anything if ( modifiers.mouse !== true && Platform.has.touch !== true && keyboard.length === 0 ) { return } const durations = typeof arg === 'string' && arg.length ? arg.split(':').map(val => parseInt(val, 10)) : [0, 600, 300] const durationsLast = durations.length - 1 let ctx = { keyboard, handler: value, mouseStart (evt) { if (leftClick(evt)) { document.addEventListener('mousemove', ctx.mouseMove, docEvtOpts) document.addEventListener('mouseup', ctx.mouseEnd, docEvtOpts) document.addEventListener('click', ctx.mouseEnd, docEvtOpts) ctx.start(evt, true) } }, mouseMove (evt) { ctx.event !== void 0 && shouldEnd(evt, ctx.origin) === true && ctx.mouseEnd(evt) }, mouseEnd (evt) { document.removeEventListener('mousemove', ctx.mouseMove, docEvtOpts) document.removeEventListener('mouseup', ctx.mouseEnd, docEvtOpts) document.removeEventListener('click', ctx.mouseEnd, docEvtOpts) ctx.end(evt) }, keyboardStart (evt) { if (keyboard.includes(evt.keyCode)) { if (durations[0] === 0 || ctx.event !== void 0) { stopAndPrevent(evt) el.focus() if (ctx.event !== void 0) { return } } document.addEventListener('keyup', ctx.keyboardEnd, docEvtOpts) ctx.start(evt, false, true) } }, keyboardEnd (evt) { document.removeEventListener('keyup', ctx.keyboardEnd, docEvtOpts) ctx.end(evt) }, start (evt, mouseEvent, keyboardEvent) { removeObserver(ctx) if (mouseEvent !== true && keyboardEvent !== true) { setObserver(el, evt, ctx) } if (keyboardEvent !== true) { ctx.origin = position(evt) } if (Platform.is.mobile === true) { document.body.classList.add('non-selectable') clearSelection() } ctx.event = { touch: mouseEvent !== true && keyboardEvent !== true, mouse: mouseEvent === true, keyboard: keyboardEvent === true, startTime: new Date().getTime(), repeatCount: 0 } const fn = () => { if (ctx.event === void 0) { return } if (ctx.event.repeatCount === 0) { ctx.event.evt = evt if (keyboardEvent === true) { ctx.event.keyCode = evt.keyCode } else { ctx.event.position = position(evt) } if (Platform.is.mobile !== true) { document.documentElement.style.cursor = 'pointer' document.body.classList.add('non-selectable') clearSelection() } } ctx.event.duration = new Date().getTime() - ctx.event.startTime ctx.event.repeatCount += 1 ctx.handler(ctx.event) const index = durationsLast < ctx.event.repeatCount ? durationsLast : ctx.event.repeatCount ctx.timer = setTimeout(fn, durations[index]) } if (durations[0] === 0) { fn() } else { ctx.timer = setTimeout(fn, durations[0]) } }, move (evt) { ctx.event !== void 0 && shouldEnd(evt, ctx.origin) === true && ctx.end(evt) }, end (evt) { if (ctx.event === void 0) { return } removeObserver(ctx) const triggered = ctx.event.repeatCount > 0 triggered === true && prevent(evt) if (Platform.is.mobile === true || triggered === true) { document.documentElement.style.cursor = '' document.body.classList.remove('non-selectable') } clearTimeout(ctx.timer) ctx.timer = void 0 ctx.event = void 0 } } el.__qtouchrepeat = ctx if (modifiers.mouse === true) { el.addEventListener('mousedown', ctx.mouseStart, modifiers.mouseCapture) } if (keyboard.length > 0) { el.addEventListener('keydown', ctx.keyboardStart, modifiers.keyCapture) } if (Platform.has.touch === true) { const opts = listenOpts['notPassive' + (modifiers.capture === true ? 'Capture' : '')] el.addEventListener('touchstart', ctx.start, opts) el.addEventListener('touchmove', ctx.move, opts) el.addEventListener('touchcancel', ctx.end, opts) el.addEventListener('touchend', ctx.end, opts) } }, update (el, binding) { let ctx = el.__qtouchrepeat if (ctx !== void 0 && binding.oldValue !== binding.value) { ctx.handler = binding.value } }, unbind (el, { modifiers }) { let ctx = el.__qtouchrepeat_old || el.__qtouchrepeat if (ctx !== void 0) { removeObserver(ctx) clearTimeout(ctx.timer) if (Platform.is.mobile === true || (ctx.event !== void 0 && ctx.event.repeatCount > 0)) { document.documentElement.style.cursor = '' document.body.classList.remove('non-selectable') } ctx.timer = void 0 ctx.event = void 0 if (modifiers.mouse === true) { el.removeEventListener('mousedown', ctx.mouseStart, modifiers.mouseCapture) document.removeEventListener('mousemove', ctx.mouseMove, docEvtOpts) document.removeEventListener('mouseup', ctx.mouseEnd, docEvtOpts) document.removeEventListener('click', ctx.mouseEnd, docEvtOpts) } if (ctx.keyboard.length > 0) { el.removeEventListener('keydown', ctx.keyboardStart, modifiers.keyCapture) document.removeEventListener('keyup', ctx.keyboardEnd, docEvtOpts) } if (Platform.has.touch === true) { const opts = listenOpts['notPassive' + (modifiers.capture === true ? 'Capture' : '')] el.removeEventListener('touchstart', ctx.start, opts) el.removeEventListener('touchmove', ctx.move, opts) el.removeEventListener('touchcancel', ctx.end, opts) el.removeEventListener('touchend', ctx.end, opts) } delete el[el.__qtouchrepeat_old ? '__qtouchrepeat_old' : '__qtouchrepeat'] } } }