File: D:/HostingSpaces/SBogers10/boldt.komma.pro/resources/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.addNavigatableElementValueToForm();
this.submitNearestForm(false);
}
this.showConfirmationPrompt(false);
}
/**
* If the navigatable element contains a value,
* we add a hidden input to the form with the same name and value
* as the navigatable. Making sure that its value is passed as expected.
*/
addNavigatableElementValueToForm()
{
if(this.navigatableElement.hasAttribute('value') && this.navigatableElement.hasAttribute('name')) {
let form = this.findForm(this.navigatableElement);
if(!form) return;
let input = document.createElement('INPUT');
input.setAttribute('type', 'hidden');
input.setAttribute('name', this.navigatableElement.getAttribute('name'));
input.setAttribute('value', this.navigatableElement.getAttribute('value'));
form.appendChild(input);
}
}
/**
* 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="navigatableElements">' +
'<button class="confirm" dusk="confirmation_confirm">' + this.confirmText + '</button>' +
'<button class="cancel" dusk="confirmation_cancel">' + this.cancelText + '</button>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="shader"></div>';
let promptElement = document.createElement("div");
promptElement.setAttribute('id', 'confirmBox');
promptElement.setAttribute('dusk', '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;
}
}