Spaces:
Paused
Paused
| import { debounce_timeout } from './constants.js'; | |
| /** | |
| * Drag and drop handler | |
| * | |
| * Can be used on any element, enabling drag&drop styling and callback on drop. | |
| */ | |
| export class DragAndDropHandler { | |
| /** @private @type {JQuery.Selector} */ selector; | |
| /** @private @type {(files: File[], event:JQuery.DropEvent<HTMLElement, undefined, any, any>) => void} */ onDropCallback; | |
| /** @private @type {NodeJS.Timeout} Remark: Not actually NodeJS timeout, but it's close */ dragLeaveTimeout; | |
| /** @private @type {boolean} */ noAnimation; | |
| /** | |
| * Create a DragAndDropHandler | |
| * @param {JQuery.Selector} selector - The CSS selector for the elements to enable drag and drop | |
| * @param {(files: File[], event:JQuery.DropEvent<HTMLElement, undefined, any, any>) => void} onDropCallback - The callback function to handle the drop event | |
| */ | |
| constructor(selector, onDropCallback, { noAnimation = false } = {}) { | |
| this.selector = selector; | |
| this.onDropCallback = onDropCallback; | |
| this.dragLeaveTimeout = null; | |
| this.noAnimation = noAnimation; | |
| this.init(); | |
| } | |
| /** | |
| * Destroy the drag and drop functionality | |
| */ | |
| destroy() { | |
| if (this.selector === 'body') { | |
| $(document.body).off('dragover', this.handleDragOver.bind(this)); | |
| $(document.body).off('dragleave', this.handleDragLeave.bind(this)); | |
| $(document.body).off('drop', this.handleDrop.bind(this)); | |
| } else { | |
| $(document.body).off('dragover', this.selector, this.handleDragOver.bind(this)); | |
| $(document.body).off('dragleave', this.selector, this.handleDragLeave.bind(this)); | |
| $(document.body).off('drop', this.selector, this.handleDrop.bind(this)); | |
| } | |
| $(this.selector).remove('drop_target no_animation'); | |
| } | |
| /** | |
| * Initialize the drag and drop functionality | |
| * Automatically called on construction | |
| * @private | |
| */ | |
| init() { | |
| if (this.selector === 'body') { | |
| $(document.body).on('dragover', this.handleDragOver.bind(this)); | |
| $(document.body).on('dragleave', this.handleDragLeave.bind(this)); | |
| $(document.body).on('drop', this.handleDrop.bind(this)); | |
| } else { | |
| $(document.body).on('dragover', this.selector, this.handleDragOver.bind(this)); | |
| $(document.body).on('dragleave', this.selector, this.handleDragLeave.bind(this)); | |
| $(document.body).on('drop', this.selector, this.handleDrop.bind(this)); | |
| } | |
| $(this.selector).addClass('drop_target'); | |
| if (this.noAnimation) $(this.selector).addClass('no_animation'); | |
| } | |
| /** | |
| * @param {JQuery.DragOverEvent<HTMLElement, undefined, any, any>} event - The dragover event | |
| * @private | |
| */ | |
| handleDragOver(event) { | |
| event.preventDefault(); | |
| event.stopPropagation(); | |
| clearTimeout(this.dragLeaveTimeout); | |
| $(this.selector).addClass('drop_target dragover'); | |
| if (this.noAnimation) $(this.selector).addClass('no_animation'); | |
| } | |
| /** | |
| * @param {JQuery.DragLeaveEvent<HTMLElement, undefined, any, any>} event - The dragleave event | |
| * @private | |
| */ | |
| handleDragLeave(event) { | |
| event.preventDefault(); | |
| event.stopPropagation(); | |
| // Debounce the removal of the class, so it doesn't "flicker" on dragging over | |
| clearTimeout(this.dragLeaveTimeout); | |
| this.dragLeaveTimeout = setTimeout(() => { | |
| $(this.selector).removeClass('dragover'); | |
| }, debounce_timeout.quick); | |
| } | |
| /** | |
| * @param {JQuery.DropEvent<HTMLElement, undefined, any, any>} event - The drop event | |
| * @private | |
| */ | |
| handleDrop(event) { | |
| event.preventDefault(); | |
| event.stopPropagation(); | |
| clearTimeout(this.dragLeaveTimeout); | |
| $(this.selector).removeClass('dragover'); | |
| const files = Array.from(event.originalEvent.dataTransfer.files); | |
| this.onDropCallback(files, event); | |
| } | |
| } | |