File: D:/HostingSpaces/SBogers95/rentman.io/resources/assets/js/kms/attributes/dataTable.js
class DataTable {
constructor(dataTableElement) {
this.addButtonClicked = this.addButtonClicked.bind(this);
this.inputFieldChanged = this.inputFieldChanged.bind(this);
this.removeButtonClicked = this.removeButtonClicked.bind(this);
this.element = dataTableElement;
this.structureElement = dataTableElement.querySelector('.js-data-table-structure');
this.content = dataTableElement.querySelector('.js-data-table-content');
this.rows = dataTableElement.querySelectorAll('.js-data-table-row');
this.hiddenInput = dataTableElement.querySelector('.js-data-table-hidden-input');
const addButton = dataTableElement.querySelector('.js-data-table-add-row');
if (isset(addButton)) {
addButton.addEventListener('click', this.addButtonClicked);
}
this.refreshEventListeners();
this.resizeTextareas();
this.emptyImage = document.createElement('img');
this.emptyImage.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
}
//=========== Listeners events ===========//
refreshEventListeners() {
this.rows = this.element.querySelectorAll('.js-data-table-row');
this.removeAndAddRemoveButtonListeners();
this.removeAndAddInputListeners();
this.addDragAndDropListeners();
}
removeAndAddRemoveButtonListeners() {
const self = this;
let removeButtons = this.content.querySelectorAll('.js-data-table-remove-row');
removeButtons.forEach(function (removeButton) {
removeButton.removeEventListener('click', self.removeButtonClicked);
removeButton.addEventListener('click', self.removeButtonClicked);
});
}
addDragAndDropListeners() {
const self = this;
// set draggable attribute and add event listeners to rows
const rows = Array.from(this.rows);
rows.forEach((row) => {
row.setAttribute('draggable', true);
row.removeEventListener("dragstart", self.handleDragStart);
row.removeEventListener("drag", self.handleDrag);
row.removeEventListener("dragend", self.handleDragEnd);
if (!row.classList.contains('dragListenersInitialized')) {
row.classList.add('dragListenersInitialized')
row.addEventListener("dragstart", (e) => self.handleDragStart(e));
row.addEventListener("drag", (e) => self.handleDrag(e));
row.addEventListener("dragend", (e) => self.handleDragEnd(e));
}
})
}
removeAndAddInputListeners() {
const self = this;
let inputFields = this.content.querySelectorAll('.js-data-table-input');
inputFields.forEach(function (inputField) {
inputField.removeEventListener('change', self.inputFieldChanged);
inputField.addEventListener('change', self.inputFieldChanged);
});
}
//=========== Events to corresponding function hooks ===========//
addButtonClicked(event) {
this.addStructureRow();
this.refreshEventListeners();
this.updateHiddenDataTableInput();
}
inputFieldChanged(event) {
this.updateHiddenDataTableInput();
this.resizeTextareas();
}
removeButtonClicked(event) {
const removeButton = event.currentTarget;
const dataTableRow = removeButton.parentElement;
this.removeRowFromTable(dataTableRow);
this.refreshEventListeners();
this.updateHiddenDataTableInput();
}
handleDragStart(e) {
e.dataTransfer.setDragImage(this.emptyImage, 0, 0)
const row = e.target;
this.copiedRow = row.cloneNode(true);
row.classList.add('is-dragging');
}
handleDrag(e) {
const y = e.clientY;
const x = e.clientX;
const row = e.target;
const table = row.parentNode;
let swapItem =
document.elementFromPoint(x, y) === null
? row
: document.elementFromPoint(x, y).parentNode; // elementFromPoint return TOPMOST element
if (table === swapItem.parentNode) {
swapItem =
swapItem !== row.nextSibling ? swapItem : swapItem.nextSibling;
table.insertBefore(row, swapItem);
}
}
handleDragEnd(e) {
const table = e.target.parentNode;
this.copiedRow.classList.remove('dragListenersInitialized');
// add copied dom node
table.insertBefore(this.copiedRow, e.target);
// remove original
document.querySelectorAll('.is-dragging').forEach(el => el.remove());
this.copiedRow.querySelectorAll('.entity-attribute-on-off').forEach(onOffWrapper => {
if (onOffWrapper.querySelector('.clickListenerInitialized')) {
onOffWrapper.querySelector('.clickListenerInitialized').classList.remove('clickListenerInitialized');
new OnOff(onOffWrapper);
}
});
// reinitialize event listeners
this.refreshEventListeners();
this.updateHiddenDataTableInput()
}
//=========== Class based functions ===========//
/**
* Adds a row to the data table.
*
* It will look up the structure element in the table,
* and modify it to append to the data table.
*/
addStructureRow() {
// Clone the structure node and reset the hidden and clone js selector
const structureNode = this.structureElement.cloneNode(true);
structureNode.classList.remove('js-data-table-structure');
structureNode.hidden = false;
// Append new element to content
this.content.appendChild(structureNode);
// add the drag event listeners
structureNode.classList.add('dragListenersInitialized')
structureNode.addEventListener("dragstart", (e) => this.handleDragStart(e));
structureNode.addEventListener("drag", (e) => this.handleDrag(e));
structureNode.addEventListener("dragend", (e) => this.handleDragEnd(e));
}
/**
* Remove a given row from the data table
*
* @param dataTableRow
*/
removeRowFromTable(dataTableRow) {
dataTableRow.remove();
}
/**
* Resize all the textareas so the content will fi
*/
resizeTextareas() {
const self = this;
let shouldReload = false;
const textareas = this.content.querySelectorAll('textarea');
textareas.forEach(function (textarea) {
const offset = textarea.offsetHeight - textarea.clientHeight;
textarea.style.height = 'auto';
let textareaHeight = textarea.scrollHeight + offset;
if(textareaHeight === 0) shouldReload = true;
// Add a row extra padding
textareaHeight += 20;
textarea.style.height = textareaHeight + 'px';
if(textareaHeight === 0) shouldReload = true;
});
if(shouldReload){
setTimeout(function () {
console.log('dataTable: Recall because a height was zero...');
self.resizeTextareas();
}, 250);
}
}
/**
* Update the hidden input.
*
* Will loop through the rows of the data table and inputs
* to create a array to covert into json for the hidden input of the table.
*/
updateHiddenDataTableInput() {
// Create input json
let hiddenInputJson = [];
// Loop through each row
const rows = this.content.querySelectorAll('.js-data-table-row');
rows.forEach(function (row) {
let rowInputs = [];
// Loop through the inputs
const inputs = row.querySelectorAll('.js-data-table-input');
inputs.forEach(function (input) {
// If we have different type of inputs we have to modify this
rowInputs.push(input.value);
});
hiddenInputJson.push(rowInputs);
});
this.hiddenInput.value = JSON.stringify(hiddenInputJson);
}
}