@progress/kendo-draggable-common
Version:
Kendo UI TypeScript package starter template
255 lines (254 loc) • 11.5 kB
JavaScript
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;
}
};