UNPKG

@progress/kendo-draggable-common

Version:
255 lines (254 loc) 11.5 kB
import { intersect } from "./algorithms"; import { getWindow, autoScrollVelocity, scrollableViewPort, getScrollableParent, isPointerInsideContainer, getDocument } from "./utils"; /** @hidden */ export var DRAG_AND_DROP_DISPATCH_ACTION; (function (DRAG_AND_DROP_DISPATCH_ACTION) { DRAG_AND_DROP_DISPATCH_ACTION["POINTER_DOWN"] = "pointerdown"; DRAG_AND_DROP_DISPATCH_ACTION["POINTER_MOVE"] = "pointermove"; DRAG_AND_DROP_DISPATCH_ACTION["POINTER_UP"] = "pointerup"; DRAG_AND_DROP_DISPATCH_ACTION["POINTER_CANCEL"] = "pointercancel"; DRAG_AND_DROP_DISPATCH_ACTION["MOUSE_DOWN"] = "mousedown"; DRAG_AND_DROP_DISPATCH_ACTION["MOUSE_MOVE"] = "mousemove"; DRAG_AND_DROP_DISPATCH_ACTION["MOUSE_UP"] = "mouseup"; DRAG_AND_DROP_DISPATCH_ACTION["CONTEXT_MENU"] = "contextmenu"; DRAG_AND_DROP_DISPATCH_ACTION["TOUCH_START"] = "touchstart"; DRAG_AND_DROP_DISPATCH_ACTION["TOUCH_MOVE"] = "touchmove"; DRAG_AND_DROP_DISPATCH_ACTION["TOUCH_END"] = "touchend"; DRAG_AND_DROP_DISPATCH_ACTION["TOUCH_CANCEL"] = "touchcancel"; DRAG_AND_DROP_DISPATCH_ACTION["SCROLL"] = "scroll"; DRAG_AND_DROP_DISPATCH_ACTION["START"] = "KENDO_DRAG_AND_DROP_START"; DRAG_AND_DROP_DISPATCH_ACTION["MOVE"] = "KENDO_DRAG_AND_DROP_MOVE"; DRAG_AND_DROP_DISPATCH_ACTION["END"] = "KENDO_DRAG_AND_DROP_END"; DRAG_AND_DROP_DISPATCH_ACTION["CANCEL"] = "KENDO_DRAG_AND_DROP_CANCEL"; })(DRAG_AND_DROP_DISPATCH_ACTION || (DRAG_AND_DROP_DISPATCH_ACTION = {})); const isTouchEvent = (event) => /^touch/.test(event.type); const isScrollEvent = (event) => /^(scroll)/.test(event.type); /** @hidden */ export const normalizeEvent = (event, state) => (isTouchEvent(event) ? ({ pageX: event.changedTouches[0].pageX, pageY: event.changedTouches[0].pageY, clientX: event.changedTouches[0].clientX, clientY: event.changedTouches[0].clientY, scrollX: state.scrollOffset.x, scrollY: state.scrollOffset.y, offsetX: state.offset.x, offsetY: state.offset.y, type: event.type, originalEvent: event, isTouch: true, altKey: false, ctrlKey: false, shiftKey: false, metaKey: false }) : isScrollEvent(event) ? ({ pageX: state.pageOffset.x, pageY: state.pageOffset.y, clientX: state.clientOffset.x, clientY: state.clientOffset.y, scrollX: state.scrollOffset.x, scrollY: state.scrollOffset.y, offsetX: state.offset.x, offsetY: state.offset.y, type: event.type, originalEvent: event, altKey: false, ctrlKey: false, shiftKey: false, metaKey: false }) : ({ pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY, offsetX: event.offsetX, offsetY: event.offsetY, scrollX: state.scrollOffset.x, scrollY: state.scrollOffset.y, type: event.type, ctrlKey: event.ctrlKey, shiftKey: event.shiftKey, altKey: event.altKey, metaKey: event.metaKey, originalEvent: event })); const noop = () => { }; /** @hidden */ export const dispatchDragAndDrop = (state, action, callbacks = {}) => { const { onIsPressedChange = noop, onIsScrollingChange = noop, onVelocityChange = noop, onOffsetChange = noop, onPageOffsetChange = noop, onClientOffsetChange = noop, onScrollOffsetChange = noop, onInitialScrollOffsetChange = noop } = callbacks; const drag = action.payload; const element = drag.element; const hint = drag.hint; const autoScrollDirection = state.autoScrollDirection; const overrideScrollableParent = state.scrollableParent; const event = normalizeEvent(action.event, state); switch (event.type) { case DRAG_AND_DROP_DISPATCH_ACTION.POINTER_DOWN: if (event.type === DRAG_AND_DROP_DISPATCH_ACTION.POINTER_DOWN && (!event.originalEvent.isPrimary || event.originalEvent.button !== 0)) { break; } // In rare cases where the `which` attribute is available in the mouse event // we check if the `left button` is explicitly clicked: // https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/which#return_value case DRAG_AND_DROP_DISPATCH_ACTION.MOUSE_DOWN: if (event.type === DRAG_AND_DROP_DISPATCH_ACTION.MOUSE_DOWN && (event.originalEvent.which && event.originalEvent.which > 1) || state.ignoreMouse) { break; } case DRAG_AND_DROP_DISPATCH_ACTION.TOUCH_START: if (event.type === DRAG_AND_DROP_DISPATCH_ACTION.TOUCH_START && event.originalEvent.touches.length !== 1) { break; } case DRAG_AND_DROP_DISPATCH_ACTION.START: { const scrollableParent = overrideScrollableParent || getScrollableParent(action.payload.element); onInitialScrollOffsetChange(scrollableParent instanceof Window ? { x: scrollableParent.scrollX, y: scrollableParent.scrollY } : { x: scrollableParent.scrollLeft, y: scrollableParent.scrollTop }); onClientOffsetChange({ x: event.clientX, y: event.clientY }); onPageOffsetChange({ x: event.pageX, y: event.pageY }); onOffsetChange({ x: event.offsetX, y: event.offsetY }); onIsPressedChange(true); if (drag.onPress) { drag.onPress(event); } break; } case DRAG_AND_DROP_DISPATCH_ACTION.SCROLL: if (event.type === DRAG_AND_DROP_DISPATCH_ACTION.SCROLL && !state.pressed) { break; } const scrollableParent = overrideScrollableParent || getScrollableParent(element); const scrollOffset = scrollableParent instanceof Window ? { x: scrollableParent.scrollX, y: scrollableParent.scrollY } : { x: scrollableParent.scrollLeft, y: scrollableParent.scrollTop }; event.scrollX = scrollOffset.x - state.initialScrollOffset.x; event.scrollY = scrollOffset.y - state.initialScrollOffset.y; onScrollOffsetChange({ x: event.scrollX, y: event.scrollY }); case DRAG_AND_DROP_DISPATCH_ACTION.POINTER_MOVE: if (event.type === DRAG_AND_DROP_DISPATCH_ACTION.POINTER_MOVE && !event.originalEvent.isPrimary) { break; } case DRAG_AND_DROP_DISPATCH_ACTION.MOUSE_MOVE: case DRAG_AND_DROP_DISPATCH_ACTION.TOUCH_MOVE: if (event.type === DRAG_AND_DROP_DISPATCH_ACTION.TOUCH_MOVE && event.originalEvent.touches.length !== 1) { break; } case DRAG_AND_DROP_DISPATCH_ACTION.MOVE: { if (state.pressed) { if (state.autoScroll && event.originalEvent.type !== 'scroll') { if (element) { const document = getDocument(element); const scrollableParent = overrideScrollableParent || getScrollableParent(document.elementFromPoint(event.clientX, event.clientY)); const newVelocity = autoScrollVelocity(event.clientX, event.clientY, scrollableViewPort(scrollableParent, getWindow(element))); onVelocityChange({ x: (autoScrollDirection && autoScrollDirection.horizontal === false) ? 0 : newVelocity.x, y: (autoScrollDirection && autoScrollDirection.vertical === false) ? 0 : newVelocity.y }); onIsScrollingChange(newVelocity.y !== 0 || newVelocity.x !== 0); } } if (!state.drag && drag.onDragStart) { drag.onDragStart(event); } if (drag.onDrag) { drag.onDrag(event); } const dropElement = intersect(hint || element, state.drops.map((drop) => drop && drop.element).filter((d) => d !== (hint || element))); const drop = state.drops.find((drop) => drop.element === dropElement); if (drop && dropElement && isPointerInsideContainer(event.clientX, event.clientY, overrideScrollableParent || getScrollableParent(dropElement)) && dropElement !== element) { if ((state.drop && state.drop.element) !== dropElement) { if (state.drop && state.drop.onDragLeave) { state.drop.onDragLeave(event); } if (drop.onDragEnter) { drop.onDragEnter(event); } } else { if (drop.onDragOver) { drop.onDragOver(event); } } } else if (state.drop && state.drop.onDragLeave) { state.drop.onDragLeave(event); } } onClientOffsetChange({ x: event.clientX, y: event.clientY }); onPageOffsetChange({ x: event.pageX, y: event.pageY }); break; } case DRAG_AND_DROP_DISPATCH_ACTION.POINTER_UP: if (event.type === DRAG_AND_DROP_DISPATCH_ACTION.POINTER_UP && !event.originalEvent.isPrimary) { break; } case DRAG_AND_DROP_DISPATCH_ACTION.MOUSE_UP: // the last finger has been lifted, and the user is not doing gesture. // there might be a better way to handle this. case DRAG_AND_DROP_DISPATCH_ACTION.TOUCH_END: if (event.type === DRAG_AND_DROP_DISPATCH_ACTION.TOUCH_END && event.originalEvent.touches.length !== 1) { break; } case DRAG_AND_DROP_DISPATCH_ACTION.END: { onIsPressedChange(false); onIsScrollingChange(false); onScrollOffsetChange({ x: 0, y: 0 }); if (drag.onRelease) { drag.onRelease(event); } if (state.drop && state.drop.onDrop) { state.drop.onDrop(event); } if (state.drag && drag.onDragEnd) { drag.onDragEnd(event); } break; } case DRAG_AND_DROP_DISPATCH_ACTION.POINTER_CANCEL: case DRAG_AND_DROP_DISPATCH_ACTION.CONTEXT_MENU: case DRAG_AND_DROP_DISPATCH_ACTION.TOUCH_CANCEL: case DRAG_AND_DROP_DISPATCH_ACTION.CANCEL: { onIsPressedChange(false); onIsScrollingChange(false); onScrollOffsetChange({ x: 0, y: 0 }); if (drag.onDragEnd) { drag.onDragEnd(event); } if (state.drop && state.drop.onDragLeave) { state.drop.onDragLeave(event); } break; } default: break; } };