HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
File: D:/HostingSpaces/SBogers10/carrot.komma.pro/resources/js/kms/attributes/fileDragAndDropHandler.js
class FileDragAndDropHandler
{
    /**
     *
     *
     * @param areaElement {HTMLElement}
     */
    constructor(areaElement)
    {
        this.hooks = [];

        this.selectButton = areaElement.querySelector('button.select');
        if(!this.selectButton) {
            console.log('FileDragAndDropHandler:constructor The document area must have a button in it with class select. But did not have one. Not responding to drag and drop');
            return;

        }
        this.fileCatcherInput = areaElement.querySelector('input[type="file"]');
        if(!this.fileCatcherInput) {
            console.log('FileDragAndDropHandler:constructor The document area must have file input. But did not have one. Not responding to drag and drop');
            return;

        }

        this.makeElementRespondToDragOverAndLeave(areaElement);
        this.makeElementRespondToDrop(areaElement);
        this.makeElementRespondToClick(areaElement);
        this.makeFileInputPassFilesToHooks();
    }

    /**
     * Adds an event listener to the file input and makes it pass its files to the document manager
     */
    makeFileInputPassFilesToHooks()
    {
        let self = this;
        this.fileCatcherInput.addEventListener('change', function(event) {
            let nFiles = event.target.files.length;
            for(let index = 0; index < nFiles; index++) {
                let file = event.target.files[index];
                // console.log(file);
                self.createFileListForFileAndPassToHooks(file);
            }
            event.target.value = '';
        });
    }

    /**
     * Catches click on the element and passes them trough to the file input
     */
    makeElementRespondToClick(element)
    {
        let self = this;
        element.addEventListener('click', function(event) {
            self.fileCatcherInput.click();
        });
    }

    /**
     * Hooks a hookable (an object that has a addFile method / function) to the drag and drop handler so that the drag and drop handler passes inputs to the
     * hookable
     * @param hookable {Class}
     */
    hookTo(hookable)
    {
        if(typeof hookable.receiveFile !== 'function') {
            console.error('The given hookable does not have a required receiveFile method / function. Not hooking the given "hookable".');
            return;
        }
        this.hooks.push(hookable);
    }

    /**
     * @param element HTMLElement that needs to be draggable or not
     * @param respondOrNotBoolean
     * @return {FileDragAndDropHandler}
     */
    makeElementRespondToDrop(element, respondOrNotBoolean = true) {
        if (respondOrNotBoolean) {
            element.removeEventListener('drop', this.drop.bind(this));
            element.addEventListener('drop', this.drop.bind(this));
        } else {
            element.removeEventListener('drop', this.drop.bind(this));
        }

        return this
    }

    /**
     * Prepares the element so that it can receive items that are dropped onto it
     *
     * @param element HTMLElement that needs can be a drop target or not
     * @param respondOrNotBoolean wheter or not it should be a drop target
     */
    makeElementRespondToDragOverAndLeave(element, respondOrNotBoolean = true) {
        if (respondOrNotBoolean) {
            element.removeEventListener('dragover', this.dragOver.bind(this));
            element.removeEventListener('dragleave', this.dragLeave.bind(this));
            element.addEventListener('dragover', this.dragOver.bind(this));
            element.addEventListener('dragleave', this.dragLeave.bind(this));
        } else {
            element.removeEventListener('dragover', this.dragOver.bind(this));
            element.removeEventListener('dragleave', this.dragLeave.bind(this));
        }
    }

    /**
     * Occurs when a document (li) HTMLElement is being dragged over the target element.
     * So the dragEvent target is not the element that you drag, but the place / HTMLElement where it may be dropped.
     *
     * @param dragEvent
     */
    dragOver(dragEvent) {
        dragEvent.preventDefault(); //Sets target HTMLElement to allow a drop
        dragEvent.stopPropagation();
        if (!dragEvent.target.id) return;

        this.enableOrDisablePointerEventsOnChildrenOfElement(dragEvent.target, false);
        dragEvent.target.classList.add('isDropTarget');
    }

    /**
     * Occurs when a document (li) HTMLElement is NOT being dragged anymore over the target element.
     *
     * @param dragEvent
     */
    dragLeave(dragEvent) {
        if (!dragEvent.target.id) return;
        dragEvent.stopPropagation();

        this.enableOrDisablePointerEventsOnChildrenOfElement(dragEvent.target, true);
        dragEvent.target.classList.remove('isDropTarget');
    }

    /**
     * Occurs when a document is being dropped
     *
     * @param dragEvent
     */
    drop(dragEvent) {
        dragEvent.preventDefault(); //Prevent browser from activating links and buttons

        let targetElement = dragEvent.target;
        targetElement.classList.remove('isDropTarget');
        this.enableOrDisablePointerEventsOnChildrenOfElement(targetElement, true);

        // Prevent default behavior (Prevent file from being opened)
        dragEvent.preventDefault();

        if (dragEvent.dataTransfer.items) {
            // Use DataTransferItemList interface to access the file(s)
            for (let i = 0; i < dragEvent.dataTransfer.items.length; i++) {
                // If dropped items aren't files, reject them
                if (dragEvent.dataTransfer.items[i].kind === 'file') {
                    let file = dragEvent.dataTransfer.items[i].getAsFile();
                    this.createFileListForFileAndPassToHooks(file);
                }
            }
        } else {
            // Use DataTransfer interface to access the file(s)
            for (let i = 0; i < dragEvent.dataTransfer.files.length; i++) {
                let file = dragEvent.dataTransfer.files[i];
                this.createFileListForFileAndPassToHooks(file);
            }
        }
    }

    createFileListForFileAndPassToHooks(file)
    {
        let length = this.hooks.length;
        for(let index = 0; index < length; index++) {
            this.hooks[index].receiveFile(file);
        }
    }

    /**
     * Enables / disables the listening to pointer (example: mouse) events on an element
     * and all of it's children. This prevents for example the dragover event from beeing canceled
     * when dragging over an input that resides in an element which listens to the dragover event
     * because the input captures the mouse.
     */
    enableOrDisablePointerEventsOnChildrenOfElement(element, enable)
    {
        let length = element.children.length;
        for(let index = 1; index < length; index++)
        {
            if(enable === false) {
                element.children[index].style.pointerEvents = 'none';
            } else {
                element.children[index].style.pointerEvents = null;
            }

            let childrenLength = element.children.children;
            for(let childrenIndex = 1; childrenIndex < childrenLength; childrenIndex++)
            {
                this.enableOrDisablePointerEventsOnChildrenOfElement(element.children.children[index], enable);
            }
        }
    }
}