- Changes to the list views - now using tabulator with filtering and sorting, client-side pagination, ...
- Adaptation of all list views in the app
This commit is contained in:
@@ -1,301 +1,493 @@
|
||||
<script type="module">
|
||||
window.EveAI = window.EveAI || {};
|
||||
window.EveAI.ListView = {
|
||||
instances: {},
|
||||
<style>
|
||||
button.disabled, button:disabled {
|
||||
opacity: 0.65;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
<div class="container">
|
||||
<input type="hidden" id="{{ table_id }}-selected-row" name="selected_row" value="">
|
||||
<input type="hidden" id="{{ table_id }}-action" name="action" value="">
|
||||
|
||||
initialize: function(containerId, options = {}) {
|
||||
const container = document.getElementById(containerId);
|
||||
if (!container) {
|
||||
console.error(`Container ${containerId} not found`);
|
||||
return null;
|
||||
<div id="{{ table_id }}" class="tabulator-list-view"></div>
|
||||
|
||||
<div class="row mt-3">
|
||||
{% set right_actions = actions|selectattr('position', 'equalto', 'right')|list %}
|
||||
<div class="{% if right_actions %}col{% else %}col-12{% endif %}">
|
||||
{% for action in actions if action.position != 'right' %}
|
||||
<button type="button"
|
||||
onclick="handleListViewAction('{{ action.value }}', {{ action.requiresSelection|tojson }})"
|
||||
class="btn {{ action.class|default('btn-primary') }} me-2 {% if action.requiresSelection %}requires-selection{% endif %}"
|
||||
{% if action.requiresSelection %}disabled{% endif %}>
|
||||
{{ action.text }}
|
||||
</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if right_actions %}
|
||||
<div class="col-auto text-end">
|
||||
{% for action in actions if action.position == 'right' %}
|
||||
<button type="button"
|
||||
onclick="handleListViewAction('{{ action.value }}', {{ action.requiresSelection|tojson }})"
|
||||
class="btn {{ action.class|default('btn-primary') }} ms-2 {% if action.requiresSelection %}requires-selection{% endif %}"
|
||||
{% if action.requiresSelection %}disabled{% endif %}>
|
||||
{{ action.text }}
|
||||
</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Zorg ervoor dat de ListView-module beschikbaar is
|
||||
window.EveAI = window.EveAI || {};
|
||||
window.EveAI.ListView = window.EveAI.ListView || {};
|
||||
|
||||
/* ListView-module functionaliteit:
|
||||
* - Initialiseert een Tabulator tabel met de gegeven configuratie
|
||||
* - Beheert rijselectie (maximaal 1 rij tegelijk)
|
||||
* - Zorgt ervoor dat knoppen met requiresSelection=true inactief zijn wanneer er geen rij is geselecteerd
|
||||
* - Ondersteunt verschillende Tabulator versies (5.x en 6.x)
|
||||
*/
|
||||
|
||||
// Direct alle buttons met requiresSelection uitschakelen bij laden pagina
|
||||
document.querySelectorAll('button[onclick*="handleListViewAction"]').forEach(button => {
|
||||
const onclickAttr = button.getAttribute('onclick');
|
||||
const match = onclickAttr.match(/handleListViewAction\('([^']+)',\s*(true|false)\)/i);
|
||||
if (match && match[2].toLowerCase() === 'true') {
|
||||
button.disabled = true;
|
||||
button.classList.add('disabled');
|
||||
}
|
||||
});
|
||||
|
||||
// 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
|
||||
};
|
||||
// Voeg de benodigde functies toe als ze nog niet bestaan
|
||||
if (!window.EveAI.ListView.initialize) {
|
||||
window.EveAI.ListView.instances = {};
|
||||
|
||||
// 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;
|
||||
}
|
||||
// Initialize functie
|
||||
window.EveAI.ListView.initialize = function(containerId, options = {}) {
|
||||
const container = document.getElementById(containerId);
|
||||
if (!container) {
|
||||
console.error(`Container ${containerId} not found`);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// Default configuration
|
||||
const config = {
|
||||
data: [],
|
||||
columns: [],
|
||||
initialSort: [],
|
||||
initialFilters: [],
|
||||
filterableColumns: [],
|
||||
selectable: true,
|
||||
actions: [],
|
||||
usePagination: true,
|
||||
tableHeight: 700,
|
||||
...options
|
||||
};
|
||||
|
||||
// Create Tabulator table
|
||||
const tableContainer = document.createElement('div');
|
||||
tableContainer.className = 'tabulator-container tabulator-list-view mt-3';
|
||||
container.appendChild(tableContainer);
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Basisinstellingen voor tabel configuratie
|
||||
const tableConfig = {
|
||||
data: config.data,
|
||||
columns: this._buildColumns(config.columns, config.selectable),
|
||||
layout: "fitColumns",
|
||||
try {
|
||||
// Create Tabulator table
|
||||
const tableContainer = document.createElement('div');
|
||||
tableContainer.className = 'tabulator-container tabulator-list-view mt-3';
|
||||
container.appendChild(tableContainer);
|
||||
|
||||
// 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
|
||||
}),
|
||||
// Basisinstellingen voor tabel configuratie
|
||||
const tableConfig = {
|
||||
data: config.data,
|
||||
columns: this._buildColumns(config.columns, config.selectable),
|
||||
layout: "fitColumns",
|
||||
|
||||
// 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
|
||||
// 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: config.selectable ? 1 : false, // Beperk tot maximaal 1 rij selectie of schakel uit
|
||||
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) {
|
||||
// Expliciet de geselecteerde rij instellen
|
||||
instance.selectedRow = row.getData();
|
||||
// Direct UI updaten voor betere gebruikerservaring
|
||||
console.log('Updating buttons from rowClick handler');
|
||||
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();
|
||||
// Direct forceer een update van de buttons - ook als de rowSelectionChanged niet triggert
|
||||
console.log('Updating buttons from cellClick handler');
|
||||
setTimeout(() => EveAI.ListView._updateActionButtons(containerId), 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
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)
|
||||
const selectedData = rows.length > 0 ? rows[0].getData() : null;
|
||||
console.log('rowSelectionChanged met data:', selectedData);
|
||||
|
||||
// Controleer of de instance bestaat
|
||||
if (EveAI.ListView.instances[containerId]) {
|
||||
EveAI.ListView.instances[containerId].selectedRow = selectedData;
|
||||
// Met kleine timeout om zeker te zijn dat alles is bijgewerkt
|
||||
setTimeout(() => {
|
||||
console.log('Updating buttons from rowSelectionChanged handler');
|
||||
EveAI.ListView._updateActionButtons(containerId);
|
||||
}, 10);
|
||||
} else {
|
||||
console.warn(`Instance voor ${containerId} niet gevonden in rowSelectionChanged`);
|
||||
}
|
||||
},
|
||||
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);
|
||||
|
||||
// Store instance - maar maak GEEN action buttons meer in JavaScript
|
||||
this.instances[containerId] = {
|
||||
table: table,
|
||||
config: config,
|
||||
selectedRow: null
|
||||
};
|
||||
|
||||
// Direct bij initialisatie: zorg ervoor dat knoppen met requiresSelection=True inactief zijn
|
||||
// Gebruik een groter timeout om te zorgen dat alle componenten zijn geladen
|
||||
setTimeout(() => {
|
||||
console.log('Initialiseren van action buttons...');
|
||||
this._updateActionButtons(containerId);
|
||||
}, 100);
|
||||
|
||||
// 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) {
|
||||
console.log('Row clicked!', row.getData());
|
||||
// Stop event propagation om te voorkomen dat andere handlers interfereren
|
||||
e.stopPropagation();
|
||||
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()));
|
||||
});
|
||||
|
||||
// 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);
|
||||
},
|
||||
rowFormatter: function(row) {
|
||||
// Voeg cursor-style toe om aan te geven dat rijen klikbaar zijn
|
||||
if (config.selectable) {
|
||||
row.getElement().style.cursor = 'pointer';
|
||||
});
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
// Bouw kolommen functie
|
||||
window.EveAI.ListView._buildColumns = function(columns, selectable) {
|
||||
const tabulatorColumns = [];
|
||||
|
||||
// Detecteer Tabulator versie (6.x heeft een andere aanpak voor column definities)
|
||||
const isTabulator6Plus = typeof Tabulator === 'function' && Tabulator.version &&
|
||||
parseInt(Tabulator.version.split('.')[0]) >= 6;
|
||||
|
||||
console.log('Tabulator versie detectie:', isTabulator6Plus ? '6+' : 'Pre-6');
|
||||
|
||||
// Add data columns
|
||||
columns.forEach(col => {
|
||||
// Maak een nieuwe schone kolom met alleen geldige Tabulator-eigenschappen
|
||||
// voor de gedetecteerde versie
|
||||
const column = {
|
||||
title: col.title,
|
||||
field: col.field,
|
||||
width: col.width,
|
||||
hozAlign: col.hozAlign || 'left',
|
||||
vertAlign: col.vertAlign || 'middle'
|
||||
};
|
||||
|
||||
// Voeg sorteren toe volgens de juiste manier per versie
|
||||
if (isTabulator6Plus) {
|
||||
// Tabulator 6+ gebruikt sorteerbaarheid via kolom-opties
|
||||
column.sorter = col.field === 'id' || col.field.endsWith('_id') || col.type === 'number' ?
|
||||
'number' : 'string';
|
||||
column.sorterParams = {};
|
||||
column.sorteringActive = col.sortable !== false;
|
||||
} else {
|
||||
// Pre-6 versies gebruiken headerSort
|
||||
column.headerSort = col.sortable !== false;
|
||||
// Zorg voor juiste numerieke sortering voor ID velden
|
||||
if (col.field === 'id' || col.field.endsWith('_id') || col.type === 'number') {
|
||||
column.sorter = 'number';
|
||||
}
|
||||
},
|
||||
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);
|
||||
// Voeg formattering toe volgens de juiste manier per versie
|
||||
if (col.formatter) {
|
||||
if (isTabulator6Plus) {
|
||||
column.formatterParams = { formatter: col.formatter };
|
||||
} else {
|
||||
column.formatter = col.formatter;
|
||||
}
|
||||
}
|
||||
|
||||
// Create action buttons
|
||||
if (config.actions.length > 0) {
|
||||
this._createActionButtons(container, config.actions, table);
|
||||
// Voeg filtering toe volgens de juiste manier per versie
|
||||
if (isTabulator6Plus) {
|
||||
// Tabulator 6+ gebruikt verschillende eigenschappen voor filtering
|
||||
column.filterable = col.filterable !== false;
|
||||
column.filterParams = {};
|
||||
|
||||
if (col.type === 'date') {
|
||||
column.filterParams.type = 'date';
|
||||
} else if (col.type === 'number') {
|
||||
column.filterParams.type = 'number';
|
||||
} else if (col.filterValues) {
|
||||
column.filterParams.values = col.filterValues;
|
||||
}
|
||||
} else {
|
||||
// Pre-6 versies gebruiken headerFilter
|
||||
column.headerFilter = col.filterable !== false ? 'input' : false;
|
||||
|
||||
// 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};
|
||||
}
|
||||
}
|
||||
|
||||
tabulatorColumns.push(column);
|
||||
});
|
||||
|
||||
return tabulatorColumns;
|
||||
};
|
||||
|
||||
// Update action buttons functie
|
||||
window.EveAI.ListView._updateActionButtons = function(containerId) {
|
||||
const instance = this.instances[containerId];
|
||||
if (!instance) {
|
||||
console.warn(`Kan buttons niet updaten: geen instance voor ${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Store instance
|
||||
this.instances[containerId] = {
|
||||
table: table,
|
||||
config: config,
|
||||
selectedRow: null
|
||||
};
|
||||
// Zoek buttons in de volledige formulier context (niet alleen de container)
|
||||
const form = document.getElementById(`${containerId}-form`) || document.querySelector('form');
|
||||
const buttons = form ? form.querySelectorAll('button[onclick*="handleListViewAction"]') :
|
||||
document.querySelectorAll('button[onclick*="handleListViewAction"]');
|
||||
|
||||
// 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();
|
||||
console.log(`Updating buttons voor ${containerId}, ${buttons.length} buttons gevonden, selectedRow:`, instance.selectedRow);
|
||||
|
||||
buttons.forEach(button => {
|
||||
// Parse the onclick attribute to get the action value and requiresSelection parameter
|
||||
const onclickAttr = button.getAttribute('onclick');
|
||||
const match = onclickAttr.match(/handleListViewAction\('([^']+)',\s*(true|false)\)/i);
|
||||
if (match) {
|
||||
const actionValue = match[1];
|
||||
const requiresSelection = match[2].toLowerCase() === 'true';
|
||||
|
||||
// Direct toepassen van requiresSelection-check
|
||||
if (requiresSelection) {
|
||||
// Controleer of er een geselecteerde rij is
|
||||
const isDisabled = !instance.selectedRow;
|
||||
button.disabled = isDisabled;
|
||||
|
||||
// Voeg/verwijder disabled class voor styling
|
||||
if (isDisabled) {
|
||||
button.classList.add('disabled');
|
||||
} else {
|
||||
button.classList.remove('disabled');
|
||||
}
|
||||
|
||||
console.log(`Button ${actionValue} updated: disabled=${isDisabled}`);
|
||||
}
|
||||
|
||||
// Backup check op basis van actions in config (voor achterwaartse compatibiliteit)
|
||||
const action = instance.config.actions.find(a => a.value === actionValue);
|
||||
if (action && action.requiresSelection === true && !requiresSelection) {
|
||||
// Ook controleren op basis van action config
|
||||
const isDisabled = !instance.selectedRow;
|
||||
button.disabled = isDisabled;
|
||||
|
||||
// Voeg/verwijder disabled class voor styling
|
||||
if (isDisabled) {
|
||||
button.classList.add('disabled');
|
||||
} else {
|
||||
button.classList.remove('disabled');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 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 hidden input with selected row data
|
||||
this._updateSelectedRowInput(containerId);
|
||||
};
|
||||
|
||||
// Update de geselecteerde rij (enkelvoud)
|
||||
EveAI.ListView.instances[containerId].selectedRow = rows.length > 0 ? rows[0].getData() : null;
|
||||
EveAI.ListView._updateActionButtons(containerId);
|
||||
});
|
||||
// Update selected row input functie
|
||||
window.EveAI.ListView._updateSelectedRowInput = function(containerId) {
|
||||
const instance = this.instances[containerId];
|
||||
let hiddenInput = document.getElementById(`${containerId}-selected-row`);
|
||||
|
||||
// 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';
|
||||
if (!hiddenInput) {
|
||||
hiddenInput = document.createElement('input');
|
||||
hiddenInput.type = 'hidden';
|
||||
hiddenInput.name = 'selected_row';
|
||||
hiddenInput.id = `${containerId}-selected-row`;
|
||||
document.getElementById(containerId).appendChild(hiddenInput);
|
||||
}
|
||||
|
||||
// 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};
|
||||
if (instance.selectedRow) {
|
||||
// Bewaar de geselecteerde rij-ID
|
||||
hiddenInput.value = JSON.stringify({value: instance.selectedRow.id});
|
||||
} else {
|
||||
column.headerFilter = "input";
|
||||
hiddenInput.value = '';
|
||||
}
|
||||
|
||||
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>
|
||||
|
||||
// Definieer de handleListViewAction functie als deze nog niet bestaat
|
||||
if (typeof window.handleListViewAction !== 'function') {
|
||||
window.handleListViewAction = function(action, requiresSelection, e) {
|
||||
// Gebruik explicit de event parameter om de browser event warning te vermijden
|
||||
const evt = e || window.event;
|
||||
const target = evt?.target || evt?.srcElement;
|
||||
|
||||
// Voorkom acties vanuit gedisabled buttons
|
||||
if (target && (target.disabled || target.classList.contains('disabled'))) {
|
||||
console.log('Button actie geblokkeerd: button is disabled');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Vind het tableId op basis van het formulier waarin we zitten
|
||||
const form = target ? target.closest('form') : null;
|
||||
const tableId = form ? form.id.replace('-form', '') : document.querySelector('.tabulator-list-view')?.id;
|
||||
|
||||
if (!tableId) {
|
||||
console.error('Kan tableId niet bepalen voor action:', action);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Controleer direct of de button disabled zou moeten zijn
|
||||
if (requiresSelection === true) {
|
||||
const instance = window.EveAI.ListView.instances[tableId];
|
||||
if (!instance || !instance.selectedRow) {
|
||||
console.log('Button actie geblokkeerd: geen rij geselecteerd');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Als EveAI.ListView beschikbaar is, gebruik dan de handleAction functie
|
||||
if (window.EveAI && window.EveAI.ListView && typeof window.EveAI.ListView.handleAction === 'function') {
|
||||
return window.EveAI.ListView.handleAction(action, requiresSelection, tableId);
|
||||
}
|
||||
|
||||
// Fallback naar de originele implementatie
|
||||
const actionInput = document.getElementById(`${tableId}-action`);
|
||||
if (actionInput) {
|
||||
actionInput.value = action;
|
||||
}
|
||||
|
||||
// Controleer of er een rij geselecteerd is indien nodig
|
||||
if (requiresSelection) {
|
||||
const selectedRowInput = document.getElementById(`${tableId}-selected-row`);
|
||||
if (!selectedRowInput || !selectedRowInput.value) {
|
||||
alert('Selecteer eerst een item uit de lijst.');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Verstuur het formulier met behoud van de originele form action
|
||||
if (form) {
|
||||
// Controleer of de form action correct is ingesteld
|
||||
if (!form.action || form.action === '' || form.action === window.location.href || form.action === window.location.pathname) {
|
||||
console.warn('Form action is mogelijk niet correct ingesteld:', form.action);
|
||||
// Als er geen action is ingesteld, gebruik dan de huidige URL
|
||||
form.action = window.location.href;
|
||||
}
|
||||
console.log(`Form action is: ${form.action}`);
|
||||
form.submit();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
console.log('EveAI List View component geladen');
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user