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/SBogers95/rentman.io/resources/assets/js/kms/entity/confirmationController.js
class ConfirmationController {
    /**
     * ConfirmationController constructor
     *
     * @param navigatableElement {HTMLElement}
     */
    constructor(navigatableElement) {
        if (this.validateElement(navigatableElement) === false) {
            console.error('The navigatableElement isn\'t valid. Did not enable the confirmation functionality for that navigatableElement. You passed a "'+navigatableElement.tagName+'"');
            return;
        }

        //Set translations form dataset or an empty string if not present
        this.headerText = navigatableElement.dataset.confirmHeader ? navigatableElement.dataset.confirmHeader : '';
        this.message = navigatableElement.dataset.confirmMessage ? navigatableElement.dataset.confirmMessage : '';
        this.confirmText = navigatableElement.dataset.confirmConfirmText ? navigatableElement.dataset.confirmConfirmText : '';
        this.cancelText = navigatableElement.dataset.confirmCancelText ? navigatableElement.dataset.confirmCancelText : '';
        this.navigatableElement = navigatableElement;
        this.onlyConfirmIfTrueCallback = null; //An optional callback that must return true or false to determine if the confirmation controller must show the prompt or not for the navigatableElement
        this.confirmCallback = null; //An optional callback that is triggered when the user confirmed the action

        this.addListenersToNavigatable(this.navigatableElement);
    }

    /**
     * Adds listeners to the navigatableElement that the selector from the constructor references to.
     * So that the navigatableElement works
     *
     * @param navigatableElement
     */
    addListenersToNavigatable(navigatableElement) {
        navigatableElement.addEventListener('click', (function (controller) {
            return function (clickEvent) {
                let confirm = false;
                if((controller.onlyConfirmIfTrueCallback && controller.onlyConfirmIfTrueCallback.call() === true) || !controller.onlyConfirmIfTrueCallback) confirm = true;

                if(confirm) {
                    clickEvent.preventDefault();
                    controller.showConfirmationPrompt(true, navigatableElement);
                }
            }
        })(this));
    }

    /**
     * Sets a callback that wil be used to check if we actually need to confirm the action on the navigatableElement or just allow it.
     * When the callback returns true or if you don't specify the callback, confirmation wil be done. When false. it won't be done.
     *
     * @param onlyConfirmIfTrueCallback
     */
    setOnlyConfirmIfTrueCallback(onlyConfirmIfTrueCallback) {
        this.onlyConfirmIfTrueCallback = onlyConfirmIfTrueCallback;
    }

    /**
     * Add or remove listeners to / from the modal buttons elements.
     * Usually the yes no button elements.
     */
    addListenersToModalButtons(add = true, originalNavigatableElement) {
        if (!this.promptElement) console.error('First create the modal with the createPrompt method');

        let confirmButton = this.promptElement.querySelector('button.confirm');
        let cancelButton = this.promptElement.querySelector('button.cancel');
        let shader = this.promptElement.querySelector('div.shader');

        confirmButton.removeEventListener('click', this.confirmClicked.bind(this));
        cancelButton.removeEventListener('click', this.cancelClicked.bind(this));
        shader.removeEventListener('click', this.cancelClicked.bind(this));

        if(add) {
            confirmButton.addEventListener('click', this.confirmClicked.bind(this));
            cancelButton.addEventListener('click', this.cancelClicked.bind(this));
            shader.addEventListener('click', this.cancelClicked.bind(this));
        }
    }

    /**
     * Sets an optional callback that is triggered when the user confirmed the action.
     * If you don't specify it, the nearest form that is found by traversing up into the dom is submitted
     *
     * @param callback
     */
    setConfirmCallback(callback)
    {
        this.confirmCallback = callback;
        return this;
    }

    /**
     * Triggered when the user clicks the confirm button
     *
     * @param mouseEvent
     */
    confirmClicked(mouseEvent) {
        mouseEvent.preventDefault();

        if(this.confirmCallback) {
            this.confirmCallback.call();
        } else {
            //Find the nearest form by traversing up into the dom
            this.submitNearestForm(false);
        }

        this.showConfirmationPrompt(false);
    }

    /**
     * Submit the nearest form the navigatableElement is in,
     * by traversing up into the dome as long as no form is found
     */
    submitNearestForm()
    {
        let form = this.findForm(this.navigatableElement);
        if (form) {
            form.submit();
            return true;
        } else {
            console.error('Could not submit the nearest form this navigatableElement should be in, because it isn\'t in a form.');
            return false;
        }
    }

    /**
     * Triggered when the user clicks the cancel button
     *
     * @param mouseEvent
     */
    cancelClicked(mouseEvent) {
        mouseEvent.preventDefault();
        this.showConfirmationPrompt(false);
    }

    /**
     * Retrieves an HTML element and starts traversing up into the dom to find the first form the element is in.
     * Returns the form or false if it cannot be found
     * @param element
     */
    findForm(element) {
        if (!element.parentNode) return false;
        if (element.parentNode.tagName === 'FORM') return element.parentNode;
        return this.findForm(element.parentNode);
    }

    /**
     * Create a div that represents a prompt
     *
     * @returns {HTMLDivElement}
     */
    createPrompt() {
        let html = '<div class="modal">' +
                        '<div class="header"><h4>' + this.headerText + '</h4></div>' +
                            '<div class="body">' +
                                '<p class="message">' + this.message + '</p>' +
                                '<div class="buttons">' +
                                    '<button class="confirm">' + this.confirmText + '</button>' +
                                    '<button class="cancel">' + this.cancelText + '</button>' +
                                '</div>' +
                            '</div>' +
                        '</div>' +
                    '</div>' +
                    '<div class="shader"></div>';

        let promptElement = document.createElement("div");
        promptElement.setAttribute('id', 'confirmBox');
        promptElement.innerHTML = html;

        return promptElement;
    }


    /**
     * Show or hides the confirmation prompt by adding a hidden class to it.
     */
    showConfirmationPrompt(show, originalNavigatableElement) {
        if(!this.promptElement) {
            this.promptElement = this.createPrompt();
            this.addListenersToModalButtons(true, originalNavigatableElement);
        }
        if(show) {
            this.promptElement.classList.add('show');
            document.body.appendChild(this.promptElement);
        } else {
            this.promptElement.classList.remove('show');
            if(this.promptElement.parentElement) {
                this.promptElement.parentElement.removeChild(this.promptElement);
            }
            this.promptElement = null;
        }

    }

    /**
     * Returns true when the navigatableElement is a navigatableElement tag or an input tag with type navigatableElement.
     * false if not
     *
     * @param navigatableElement {HTMLElement}
     * @returns {boolean}
     */
     validateElement(navigatableElement) {
        if (!navigatableElement) return false;
        if (navigatableElement.tagName !== 'BUTTON' && navigatableElement.tagName !== 'INPUT' && navigatableElement.tagName !== 'A') return false;
        if (navigatableElement.tagName === "INPUT") {
            if (navigatableElement.getAttribute('type').toLowerCase() !== 'navigatableElement' && navigatableElement.getAttribute('type').toLowerCase() !== 'submit') return false;
        }

        return true;
    }

    /**
     * @param text
     * @returns {ConfirmationController}
     */
    setHeaderText(text) {
        this.headerText = text;
        return this;
    }

    /**
     * @param text
     * @returns {ConfirmationController}
     */
    setMessage(text) {
        this.message = text;
        return this;
    }

    /**
     * @param text
     * @returns {ConfirmationController}
     */
    setConfirmText(text) {
        this.confirmText= text;
        return this;
    }

    /**
     * @param text
     * @returns {ConfirmationController}
     */
    setCancelText(text) {
        this.cancelText= text;
        return this;
    }
}