mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Drag&Drop handler utility and animation
This commit is contained in:
107
public/scripts/dragdrop.js
vendored
Normal file
107
public/scripts/dragdrop.js
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
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} */ 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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user