File: D:/HostingSpaces/SBogers10/inzigd.komma.pro/resources/js/kms/entity/preventNavigationController.js
/**
* Tracks all inputs, selects and textareas in the given wrapper element for changes.
* If the user clicked an button, submit input or an anchor the user fist must confirm that he's going to lose changes.
*/
class PreventNavigationController
{
/**
* inputs in the wrapper element will be tracked for changes
*
* @param WrapperElement {Element}
*/
constructor(WrapperElement) {
//Create properties
this.inputs = []; //Inputs, textareas, selects
this.wrapperElement = null;
this.translation = {
headerText: '',
message: '',
confirmText: '',
cancelText: '',
};
this.changed = false; //Automatically set to true when one of the inputs was changed
//validate stuff
if(!WrapperElement) {
console.warn('No wrapper element given. Not preventing navigation.');
return;
}
if(!WrapperElement.dataset.translation) {
console.warn('No translation present. Not preventing navigation when not all changes have been saved.');
return;
}
this.wrapperElement = WrapperElement;
//Delegate control to specialist parts of the class
this.loadTranslation();
this.inputs = this.findAllInputsIn(WrapperElement);
this.interceptClicksOnNavigatableElements();
this.addListenersToInputs(this.inputs)
}
/**
* Returns true if the given input element is an HTMLElement of tag Input.
*
* @param InputElement {HTMLElement}
* @returns {boolean}
*/
isTrackableElement(InputElement) {
return (InputElement.tagName === "INPUT" || InputElement.tagName === "SELECT" || InputElement.tagName === "TEXTAREA")
}
/**
* Add listeners to inputs
*
* @param inputs {array}
* @param add {boolean}
*/
addListenersToInputs(inputs, add = true)
{
let nInputs = inputs.length;
for(let currentInputNumber = 0; currentInputNumber < nInputs; currentInputNumber++)
{
if(add) {
inputs[currentInputNumber].addEventListener('change', this.inputChanged.bind(this));
} else {
inputs[currentInputNumber].removeEventListener('change', this.inputChanged.bind(this));
}
}
}
/**
* Triggered in response to a changed input
*
* @param event
*/
inputChanged(event) {
this.changed = true;
console.log(this.changed);
}
/**
* Loads the translations. They are defined on the wrapper element
*/
loadTranslation()
{
this.translation = JSON.parse(this.wrapperElement.dataset.translation);
}
/**
* Makes sure that clicks on links are intercepted and need to be confirmed first
*
* @param enable {boolean}
*/
interceptClicksOnNavigatableElements(enable = true)
{
let links = document.getElementsByTagName('A');
let nLinks = links.length;
for(let linkNumber = 0; linkNumber < nLinks; linkNumber++)
{
let currentLink = links[linkNumber];
let linkHref = currentLink.getAttribute('href');
if(linkHref && linkHref.substr(0,1) !== "#") {
new ConfirmationController(currentLink)
.setHeaderText(this.translation.headerText)
.setMessage(this.translation.message)
.setConfirmText(this.translation.confirmText)
.setCancelText(this.translation.cancelText)
.setConfirmCallback(function() {
window.location = linkHref;
})
.setOnlyConfirmIfTrueCallback((function (controller) {
return function()
{
return controller.hasChanged();
}
})(this))
}
}
}
/**
* Returns true if one of the input has changed
* @returns {boolean}
*/
hasChanged()
{
return this.changed;
}
/**
* Finds all html elements witch match elements specified in the isTrackableElement method
*
* @param WrapperElement {Element}
* @param inputs
* @returns {Array}
*/
findAllInputsIn(WrapperElement, inputs = []) {
let nChildren = WrapperElement.children.length;
if(nChildren === 0) return inputs;
for(let index = 0; index < nChildren; index++)
{
let currentChild = WrapperElement.children[index];
if(this.isTrackableElement(currentChild)) {
inputs.push(currentChild);
}
if(currentChild.children.length > 0) {
let childInputs = this.findAllInputsIn(currentChild, inputs);
inputs.concat(childInputs);
}
}
return inputs;
}
}