philomena/assets/js/utils/draggable.ts

81 lines
2.3 KiB
TypeScript
Raw Normal View History

2019-10-05 02:09:52 +02:00
import { $$ } from './dom';
2022-03-25 22:34:08 +01:00
let dragSrcEl: HTMLElement | undefined;
2019-10-05 02:09:52 +02:00
2022-03-25 22:34:08 +01:00
function dragStart(event: DragEvent, target: HTMLElement) {
2019-10-05 02:09:52 +02:00
target.classList.add('dragging');
dragSrcEl = target;
2022-03-25 22:34:08 +01:00
if (!event.dataTransfer) return;
2019-10-05 02:09:52 +02:00
if (event.dataTransfer.items.length === 0) {
event.dataTransfer.setData('text/plain', '');
}
event.dataTransfer.effectAllowed = 'move';
}
2022-03-25 22:34:08 +01:00
function dragOver(event: DragEvent) {
2019-10-05 02:09:52 +02:00
event.preventDefault();
2022-03-25 22:34:08 +01:00
if (event.dataTransfer) {
event.dataTransfer.dropEffect = 'move';
}
2019-10-05 02:09:52 +02:00
}
2022-03-25 22:34:08 +01:00
function dragEnter(event: DragEvent, target: HTMLElement) {
2019-10-05 02:09:52 +02:00
target.classList.add('over');
}
2022-03-25 22:34:08 +01:00
function dragLeave(event: DragEvent, target: HTMLElement) {
2019-10-05 02:09:52 +02:00
target.classList.remove('over');
}
2022-03-25 22:34:08 +01:00
function drop(event: DragEvent, target: HTMLElement) {
2019-10-05 02:09:52 +02:00
event.preventDefault();
2022-03-25 22:34:08 +01:00
if (!dragSrcEl) return;
2019-10-05 02:09:52 +02:00
dragSrcEl.classList.remove('dragging');
if (dragSrcEl === target) return;
// divide the target element into two sets of coordinates
2022-03-25 22:34:08 +01:00
// and determine how to act based on the relative mouse position
2019-10-05 02:09:52 +02:00
const bbox = target.getBoundingClientRect();
2022-03-25 22:34:08 +01:00
const detX = bbox.left + bbox.width / 2;
2019-10-05 02:09:52 +02:00
if (event.clientX < detX) {
target.insertAdjacentElement('beforebegin', dragSrcEl);
}
else {
target.insertAdjacentElement('afterend', dragSrcEl);
}
}
2022-03-25 22:34:08 +01:00
function dragEnd(event: DragEvent, target: HTMLElement) {
dragSrcEl?.classList.remove('dragging');
2019-10-05 02:09:52 +02:00
2022-03-25 22:34:08 +01:00
if (target.parentNode) {
$$('.over', target.parentNode).forEach(t => t.classList.remove('over'));
}
2019-10-05 02:09:52 +02:00
}
2022-03-25 22:34:08 +01:00
function wrapper<E extends Event, T extends Element>(func: (event: E, target: T) => void) {
return function(event: E) {
const evtTarget = event.target as EventTarget | Element | null;
if (evtTarget && 'closest' in evtTarget && typeof evtTarget.closest === 'function') {
const target: T | null = evtTarget.closest('.drag-container [draggable]');
if (target) func(event, target);
}
2019-10-05 02:09:52 +02:00
};
}
export function initDraggables() {
document.addEventListener('dragstart', wrapper(dragStart));
document.addEventListener('dragover', wrapper(dragOver));
document.addEventListener('dragenter', wrapper(dragEnter));
document.addEventListener('dragleave', wrapper(dragLeave));
document.addEventListener('dragend', wrapper(dragEnd));
document.addEventListener('drop', wrapper(drop));
}