Dieser Commit ist enthalten in:
2025-06-08 22:37:03 +02:00
Ursprung fb83559d58
Commit 472998d16b
11 geänderte Dateien mit 499 neuen und 85 gelöschten Zeilen

Datei anzeigen

@@ -162,6 +162,61 @@
width: 1.2em;
height: 1.2em;
}
/* Sortable Table Styles */
.sortable-table th.sortable {
cursor: pointer;
user-select: none;
position: relative;
padding-right: 25px;
}
.sortable-table th.sortable:hover {
background-color: #e9ecef;
}
.sortable-table th.sortable::after {
content: '↕';
position: absolute;
right: 8px;
opacity: 0.3;
}
.sortable-table th.sortable.asc::after {
content: '↑';
opacity: 1;
color: var(--status-active);
}
.sortable-table th.sortable.desc::after {
content: '↓';
opacity: 1;
color: var(--status-active);
}
/* Server-side sortable styles */
.server-sortable {
cursor: pointer;
text-decoration: none;
color: inherit;
display: flex;
align-items: center;
justify-content: space-between;
}
.server-sortable:hover {
color: var(--bs-primary);
text-decoration: none;
}
.sort-indicator {
margin-left: 5px;
font-size: 0.8em;
}
.sort-indicator.active {
color: var(--bs-primary);
}
</style>
</head>
<body class="bg-light">
@@ -314,6 +369,81 @@
// Initial Heartbeat
extendSession();
// Client-side table sorting
document.addEventListener('DOMContentLoaded', function() {
// Initialize all sortable tables
const sortableTables = document.querySelectorAll('.sortable-table');
sortableTables.forEach(table => {
const headers = table.querySelectorAll('th.sortable');
headers.forEach((header, index) => {
header.addEventListener('click', function() {
sortTable(table, index, header);
});
});
});
});
function sortTable(table, columnIndex, header) {
const tbody = table.querySelector('tbody');
const rows = Array.from(tbody.querySelectorAll('tr'));
const isNumeric = header.dataset.type === 'numeric';
const isDate = header.dataset.type === 'date';
// Determine sort direction
let direction = 'asc';
if (header.classList.contains('asc')) {
direction = 'desc';
}
// Remove all sort classes from headers
table.querySelectorAll('th.sortable').forEach(th => {
th.classList.remove('asc', 'desc');
});
// Add appropriate class to clicked header
header.classList.add(direction);
// Sort rows
rows.sort((a, b) => {
let aValue = a.cells[columnIndex].textContent.trim();
let bValue = b.cells[columnIndex].textContent.trim();
// Handle different data types
if (isNumeric) {
aValue = parseFloat(aValue.replace(/[^0-9.-]/g, '')) || 0;
bValue = parseFloat(bValue.replace(/[^0-9.-]/g, '')) || 0;
} else if (isDate) {
// Parse German date format (DD.MM.YYYY HH:MM)
aValue = parseGermanDate(aValue);
bValue = parseGermanDate(bValue);
} else {
// Text comparison with locale support for umlauts
aValue = aValue.toLowerCase();
bValue = bValue.toLowerCase();
}
if (aValue < bValue) return direction === 'asc' ? -1 : 1;
if (aValue > bValue) return direction === 'asc' ? 1 : -1;
return 0;
});
// Reorder rows in DOM
rows.forEach(row => tbody.appendChild(row));
}
function parseGermanDate(dateStr) {
// Handle DD.MM.YYYY HH:MM format
const parts = dateStr.match(/(\d{2})\.(\d{2})\.(\d{4})\s*(\d{2}:\d{2})?/);
if (parts) {
const [_, day, month, year, time] = parts;
const timeStr = time || '00:00';
return new Date(`${year}-${month}-${day}T${timeStr}`);
}
return new Date(0);
}
</script>
{% block extra_js %}{% endblock %}