91 lines
No EOL
3.5 KiB
JavaScript
91 lines
No EOL
3.5 KiB
JavaScript
/**
|
|
* Simple table sorting script
|
|
* Enables sorting for all tables with the class 'sortable'
|
|
*/
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Get all tables with the class 'table'
|
|
const tables = document.querySelectorAll('table.table');
|
|
|
|
// Add sortable class to all tables
|
|
tables.forEach(table => {
|
|
table.classList.add('sortable');
|
|
});
|
|
|
|
// Get all sortable tables
|
|
const sortableTables = document.querySelectorAll('table.sortable');
|
|
|
|
sortableTables.forEach(table => {
|
|
const thead = table.querySelector('thead');
|
|
const tbody = table.querySelector('tbody');
|
|
const thList = thead ? thead.querySelectorAll('th') : [];
|
|
|
|
// Add click event to each header cell
|
|
thList.forEach((th, columnIndex) => {
|
|
// Skip if the header spans multiple rows or columns
|
|
if (th.hasAttribute('rowspan') || th.hasAttribute('colspan')) {
|
|
return;
|
|
}
|
|
|
|
// Add sort indicator and cursor style
|
|
th.style.cursor = 'pointer';
|
|
th.innerHTML = `${th.innerHTML} <span class="sort-indicator"></span>`;
|
|
|
|
// Add click event
|
|
th.addEventListener('click', () => {
|
|
const isAscending = th.classList.contains('sort-asc');
|
|
|
|
// Remove sort classes from all headers
|
|
thList.forEach(header => {
|
|
header.classList.remove('sort-asc', 'sort-desc');
|
|
const indicator = header.querySelector('.sort-indicator');
|
|
if (indicator) {
|
|
indicator.textContent = '';
|
|
}
|
|
});
|
|
|
|
// Set sort direction
|
|
if (isAscending) {
|
|
th.classList.add('sort-desc');
|
|
th.querySelector('.sort-indicator').textContent = ' ▼';
|
|
} else {
|
|
th.classList.add('sort-asc');
|
|
th.querySelector('.sort-indicator').textContent = ' ▲';
|
|
}
|
|
|
|
// Get all rows from tbody
|
|
const rows = Array.from(tbody.querySelectorAll('tr'));
|
|
|
|
// Sort rows
|
|
rows.sort((rowA, rowB) => {
|
|
const cellA = rowA.querySelectorAll('td')[columnIndex];
|
|
const cellB = rowB.querySelectorAll('td')[columnIndex];
|
|
|
|
if (!cellA || !cellB) {
|
|
return 0;
|
|
}
|
|
|
|
const valueA = cellA.textContent.trim();
|
|
const valueB = cellB.textContent.trim();
|
|
|
|
// Check if values are numbers
|
|
const numA = parseFloat(valueA);
|
|
const numB = parseFloat(valueB);
|
|
|
|
if (!isNaN(numA) && !isNaN(numB)) {
|
|
return isAscending ? numB - numA : numA - numB;
|
|
}
|
|
|
|
// Sort as strings
|
|
return isAscending
|
|
? valueB.localeCompare(valueA, undefined, {sensitivity: 'base'})
|
|
: valueA.localeCompare(valueB, undefined, {sensitivity: 'base'});
|
|
});
|
|
|
|
// Reorder rows in the table
|
|
rows.forEach(row => {
|
|
tbody.appendChild(row);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}); |