Files
dbgate/packages/web/src/utility/dragDropFileTarget.ts
Jan Prochazka 500c1c76ba D & D CSV files
2021-03-13 20:28:06 +01:00

87 lines
2.4 KiB
TypeScript

import _ from 'lodash';
import { isFileDragActive } from '../stores';
import { fromEvent } from 'file-selector';
import uploadFiles from './uploadFiles';
function isEvtWithFiles(event) {
if (!event.dataTransfer) {
return !!event.target && !!event.target.files;
}
// https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/types
// https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Recommended_drag_types#file
return Array.prototype.some.call(
event.dataTransfer.types,
type => type === 'Files' || type === 'application/x-moz-file'
);
}
export default function dragDropFileTarget(node, items) {
let dragTargetsRef = [];
function handleDragEnter(event) {
event.preventDefault();
event.stopPropagation();
dragTargetsRef = [...dragTargetsRef, event.target];
if (isEvtWithFiles(event)) {
isFileDragActive.set(true);
}
return false;
}
function handleDragOver(event) {
event.preventDefault();
event.stopPropagation();
if (event.dataTransfer) {
try {
event.dataTransfer.dropEffect = 'copy';
} catch {}
}
}
function handleDragLeave(event) {
event.preventDefault();
event.stopPropagation();
// Only deactivate once the dropzone and all children have been left
const targets = dragTargetsRef.filter(target => node && node.contains(target));
// Make sure to remove a target present multiple times only once
// (Firefox may fire dragenter/dragleave multiple times on the same element)
const targetIdx = targets.indexOf(event.target);
if (targetIdx !== -1) {
targets.splice(targetIdx, 1);
}
dragTargetsRef = targets;
if (targets.length > 0) {
return;
}
isFileDragActive.set(false);
}
async function handleDrop(event) {
event.preventDefault();
event.stopPropagation();
isFileDragActive.set(false);
if (isEvtWithFiles(event)) {
const files = await fromEvent(event);
uploadFiles(files);
}
}
node.addEventListener('dragenter', handleDragEnter);
node.addEventListener('dragover', handleDragOver);
node.addEventListener('dragleave', handleDragLeave);
node.addEventListener('drop', handleDrop);
return {
destroy() {
node.removeEventListener('dragenter', handleDragEnter);
node.removeEventListener('dragover', handleDragOver);
node.removeEventListener('dragleave', handleDragLeave);
node.removeEventListener('drop', handleDrop);
},
};
}