- npm build does now also include building css files. - Source javascript and css are now defined in the source directories (eveai_app or eveai_chat_client), and automatically built for use with nginx - eveai.css is now split into several more manageable files (per control type)
302 lines
13 KiB
HTML
302 lines
13 KiB
HTML
<script type="module">
|
|
window.EveAI = window.EveAI || {};
|
|
window.EveAI.ListView = {
|
|
instances: {},
|
|
|
|
initialize: function(containerId, options = {}) {
|
|
const container = document.getElementById(containerId);
|
|
if (!container) {
|
|
console.error(`Container ${containerId} not found`);
|
|
return null;
|
|
}
|
|
|
|
// Default configuration
|
|
const config = {
|
|
data: [],
|
|
columns: [],
|
|
initialSort: [],
|
|
initialFilters: [],
|
|
filterableColumns: [],
|
|
selectable: true,
|
|
actions: [],
|
|
usePagination: true, // Nieuwe optie om paginering aan/uit te zetten
|
|
tableHeight: 700, // Standaard tabelhoogte als deze niet wordt gespecificeerd
|
|
...options
|
|
};
|
|
|
|
// Check if Tabulator is available
|
|
if (typeof window.Tabulator !== 'function') {
|
|
console.error('Tabulator not loaded (window.Tabulator missing).');
|
|
container.innerHTML = `<div class="alert alert-danger">
|
|
<strong>Error:</strong> Tabulator not loaded
|
|
</div>`;
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
|
|
// Create Tabulator table
|
|
const tableContainer = document.createElement('div');
|
|
tableContainer.className = 'tabulator-container tabulator-list-view mt-3';
|
|
container.appendChild(tableContainer);
|
|
|
|
// Basisinstellingen voor tabel configuratie
|
|
const tableConfig = {
|
|
data: config.data,
|
|
columns: this._buildColumns(config.columns, config.selectable),
|
|
layout: "fitColumns",
|
|
|
|
// Conditionele paginatie of progressieve lading
|
|
...(config.usePagination ? {
|
|
pagination: "local",
|
|
paginationSize: 25,
|
|
paginationSizeSelector: [10, 25, 50, 100]
|
|
} : {
|
|
progressiveLoad: "scroll" // Gebruik progressieve lading voor grote datasets wanneer paginatie uitstaat
|
|
}),
|
|
|
|
// Gemeenschappelijke configuratie voor beide modi
|
|
movableColumns: true,
|
|
resizableRows: false, // Schakel dit uit om prestatieproblemen te voorkomen
|
|
initialSort: config.initialSort,
|
|
initialFilter: config.initialFilters,
|
|
selectable: 1, // Beperk tot maximaal 1 rij selectie
|
|
selectableRangeMode: "click",
|
|
selectableCheck: function() { return true; }, // Zorg ervoor dat alle cellen selecteerbaar zijn
|
|
rowClick: function(e, row) {
|
|
// Selecteer de rij bij klikken op willekeurige cel
|
|
if (config.selectable) {
|
|
console.log('Row clicked!', row.getData());
|
|
row.getTable().deselectRow();
|
|
row.select();
|
|
// Handmatig de rowSelectionChanged event aanroepen als extra maatregel
|
|
const instance = EveAI.ListView.instances[containerId];
|
|
if (instance) {
|
|
instance.selectedRow = row.getData();
|
|
EveAI.ListView._updateActionButtons(containerId);
|
|
}
|
|
}
|
|
},
|
|
cellClick: function(e, cell) {
|
|
// Gebruik ook cellClick om ervoor te zorgen dat klikken op een cel de rij selecteert
|
|
if (config.selectable && !e.target.matches('a, input, button, select, .tabulator-cell-editing')) {
|
|
console.log('Cell clicked!', cell.getData());
|
|
const row = cell.getRow();
|
|
row.getTable().deselectRow();
|
|
row.select();
|
|
// Handmatig de rowSelectionChanged event aanroepen als extra maatregel
|
|
const instance = EveAI.ListView.instances[containerId];
|
|
if (instance) {
|
|
instance.selectedRow = row.getData();
|
|
EveAI.ListView._updateActionButtons(containerId);
|
|
}
|
|
}
|
|
},
|
|
cellTap: function(e, cell) {
|
|
// Extra handler voor touch devices
|
|
if (config.selectable && !e.target.matches('a, input, button, select, .tabulator-cell-editing')) {
|
|
console.log('Cell tapped!', cell.getData());
|
|
const row = cell.getRow();
|
|
row.getTable().deselectRow();
|
|
row.select();
|
|
// Handmatig de rowSelectionChanged event aanroepen
|
|
const instance = EveAI.ListView.instances[containerId];
|
|
if (instance) {
|
|
instance.selectedRow = row.getData();
|
|
EveAI.ListView._updateActionButtons(containerId);
|
|
}
|
|
}
|
|
},
|
|
rowSelectionChanged: function(data, rows) {
|
|
console.log("Aantal geselecteerde rijen:", rows.length);
|
|
console.log("Geselecteerde rijen:", rows.map(r => r.getData()));
|
|
|
|
// Update de geselecteerde rij (enkelvoud)
|
|
EveAI.ListView.instances[containerId].selectedRow = rows.length > 0 ? rows[0].getData() : null;
|
|
EveAI.ListView._updateActionButtons(containerId);
|
|
},
|
|
rowFormatter: function(row) {
|
|
// Voeg cursor-style toe om aan te geven dat rijen klikbaar zijn
|
|
if (config.selectable) {
|
|
row.getElement().style.cursor = 'pointer';
|
|
}
|
|
},
|
|
placeholder: "No data available",
|
|
tooltips: false, // Schakel tooltips uit voor betere prestaties
|
|
responsiveLayout: false, // Schakel responsiveLayout uit om recursieve problemen te voorkomen
|
|
renderVerticalBuffer: 20, // Optimaliseer virtuele rendering
|
|
virtualDomBuffer: 80, // Optimaliseer virtuele DOM buffer
|
|
height: config.tableHeight // Gebruik de geconfigureerde tabel hoogte
|
|
};
|
|
|
|
// Maak Tabulator instantie met de geconfigureerde instellingen
|
|
const table = new Tabulator(tableContainer, tableConfig);
|
|
|
|
// Create action buttons
|
|
if (config.actions.length > 0) {
|
|
this._createActionButtons(container, config.actions, table);
|
|
}
|
|
|
|
// Store instance
|
|
this.instances[containerId] = {
|
|
table: table,
|
|
config: config,
|
|
selectedRow: null
|
|
};
|
|
|
|
// Registreer events met de Tabulator API voor betere compatibiliteit
|
|
table.on("rowClick", function(e, row){
|
|
console.log("Tabulator API: Row clicked!", row.getData());
|
|
if (config.selectable) {
|
|
// Stop event propagation om te voorkomen dat andere handlers interfereren
|
|
e.stopPropagation();
|
|
row.getTable().deselectRow();
|
|
row.select();
|
|
}
|
|
});
|
|
|
|
// Row selection event met de Tabulator API
|
|
table.on("rowSelectionChanged", function(data, rows){
|
|
console.log("Tabulator API: Aantal geselecteerde rijen:", rows.length);
|
|
console.log("Tabulator API: Geselecteerde rijen:", rows.map(r => r.getData()));
|
|
|
|
// Update de geselecteerde rij (enkelvoud)
|
|
EveAI.ListView.instances[containerId].selectedRow = rows.length > 0 ? rows[0].getData() : null;
|
|
EveAI.ListView._updateActionButtons(containerId);
|
|
});
|
|
|
|
// Opmerking: row selection event wordt nu afgehandeld via de Tabulator API
|
|
|
|
return table;
|
|
} catch (error) {
|
|
console.error('Error initializing ListView:', error);
|
|
container.innerHTML = `<div class="alert alert-danger">
|
|
<strong>Error loading data:</strong> ${error.message}
|
|
</div>`;
|
|
return null;
|
|
}
|
|
},
|
|
|
|
|
|
_buildColumns: function(columns, selectable) {
|
|
const tabulatorColumns = [];
|
|
|
|
// Add selection column if needed
|
|
{#if (selectable) {#}
|
|
{# tabulatorColumns.push({#}
|
|
{# formatter: "rowSelection", #}
|
|
{# titleFormatter: "rowSelection", #}
|
|
{# hozAlign: "center", #}
|
|
{# headerSort: false, #}
|
|
{# width: 60#}
|
|
{# });#}
|
|
{#}#}
|
|
|
|
// Add data columns
|
|
columns.forEach(col => {
|
|
// Maak een nieuwe schone kolom met alleen geldige Tabulator-eigenschappen
|
|
const column = {
|
|
title: col.title,
|
|
field: col.field,
|
|
headerSort: col.sortable !== false,
|
|
headerFilter: col.filterable !== false,
|
|
formatter: col.formatter,
|
|
width: col.width,
|
|
hozAlign: col.hozAlign,
|
|
vertAlign: col.vertAlign
|
|
};
|
|
|
|
// Zorg voor juiste numerieke sortering voor ID velden
|
|
if (col.field === 'id' || col.field.endsWith('_id') || col.type === 'number') {
|
|
column.sorter = 'number';
|
|
}
|
|
|
|
// Set appropriate header filter based on the data type
|
|
if (col.type === 'date') {
|
|
column.headerFilter = "input";
|
|
column.headerFilterParams = {type: "date"};
|
|
} else if (col.type === 'number') {
|
|
column.headerFilter = "number";
|
|
} else if (col.filterValues) {
|
|
column.headerFilter = "select";
|
|
column.headerFilterParams = {values: col.filterValues};
|
|
} else {
|
|
column.headerFilter = "input";
|
|
}
|
|
|
|
tabulatorColumns.push(column);
|
|
});
|
|
|
|
return tabulatorColumns;
|
|
},
|
|
|
|
_createActionButtons: function(container, actions, table) {
|
|
const actionSection = document.createElement('div');
|
|
actionSection.className = 'mt-3 d-flex justify-content-between';
|
|
|
|
const leftActions = document.createElement('div');
|
|
const rightActions = document.createElement('div');
|
|
|
|
actions.forEach(action => {
|
|
const button = document.createElement('button');
|
|
button.type = 'submit';
|
|
button.name = 'action';
|
|
button.value = action.value;
|
|
button.className = `btn ${action.class || 'btn-primary'} me-2`;
|
|
button.textContent = action.text;
|
|
button.disabled = action.requiresSelection !== false; // Disabled by default if requires selection
|
|
|
|
if (action.position === 'right') {
|
|
rightActions.appendChild(button);
|
|
} else {
|
|
leftActions.appendChild(button);
|
|
}
|
|
});
|
|
|
|
actionSection.appendChild(leftActions);
|
|
actionSection.appendChild(rightActions);
|
|
container.appendChild(actionSection);
|
|
},
|
|
|
|
|
|
_updateActionButtons: function(containerId) {
|
|
const instance = this.instances[containerId];
|
|
const container = document.getElementById(containerId);
|
|
const buttons = container.querySelectorAll('button[name="action"]');
|
|
|
|
buttons.forEach(button => {
|
|
// Enable/disable based on selection requirement
|
|
const action = instance.config.actions.find(a => a.value === button.value);
|
|
if (action && action.requiresSelection !== false) {
|
|
// Controleer of er een geselecteerde rij is
|
|
button.disabled = !instance.selectedRow;
|
|
}
|
|
});
|
|
|
|
// Update hidden input with selected row data
|
|
this._updateSelectedRowInput(containerId);
|
|
},
|
|
|
|
_updateSelectedRowInput: function(containerId) {
|
|
const instance = this.instances[containerId];
|
|
let hiddenInput = document.getElementById(`${containerId}-selected-row`);
|
|
|
|
if (!hiddenInput) {
|
|
hiddenInput = document.createElement('input');
|
|
hiddenInput.type = 'hidden';
|
|
hiddenInput.name = 'selected_row';
|
|
hiddenInput.id = `${containerId}-selected-row`;
|
|
document.getElementById(containerId).appendChild(hiddenInput);
|
|
}
|
|
|
|
if (instance.selectedRow) {
|
|
// Bewaar de geselecteerde rij-ID
|
|
hiddenInput.value = JSON.stringify({value: instance.selectedRow.id});
|
|
} else {
|
|
hiddenInput.value = '';
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|