mirror of
https://github.com/calibrain/shelfmark.git
synced 2026-10-06 10:44:39 +01:00
[Feature] Sort results table by headers (#58)
Related to #53 This PR adds sorting to the results table. This can be done by clicking on the header of the table. For narrow columns, the arrow indicating the ordering is underneath the column title instead of next to the title - not sure how to solve that elegantly without a minor redesign of the table :D 
This commit is contained in:
@@ -146,6 +146,10 @@ tbody tr:hover {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
th[data-sort="index"] {
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
/* Loading Indicator */
|
||||
.loading-indicator {
|
||||
display: none;
|
||||
|
||||
@@ -85,6 +85,60 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
});
|
||||
return element;
|
||||
},
|
||||
|
||||
sortResultsTable(column, order = 'asc') {
|
||||
const rows = Array.from(elements.resultsTableBody.querySelectorAll('tr'));
|
||||
const headers = document.querySelectorAll('#results-table thead th');
|
||||
|
||||
const parseFileSize = (size) => {
|
||||
const match = size.match(/([\d.]+)([KMGT]B)/i);
|
||||
if (!match) return 0;
|
||||
const [_, value, unit] = match;
|
||||
const multiplier = { KB: 1, MB: 1024, GB: 1024 * 1024, TB: 1024 * 1024 * 1024 };
|
||||
return parseFloat(value) * (multiplier[unit.toUpperCase()] || 1);
|
||||
};
|
||||
|
||||
const parseTitle = (title) => {
|
||||
return title.replace(/^(The)\s+/i, '').trim();
|
||||
}
|
||||
|
||||
const columnName = headers[column].textContent.trim().toLowerCase();
|
||||
|
||||
const getCellValue = (row, column) => {
|
||||
const cell = row.querySelector(`td:nth-child(${column + 1})`);
|
||||
const text = cell ? cell.textContent.trim() : '';
|
||||
if (columnName === 'size') return parseFileSize(text);
|
||||
if (columnName === 'title') return parseTitle(text);
|
||||
};
|
||||
|
||||
rows.sort((a, b) => {
|
||||
const valA = getCellValue(a, column);
|
||||
const valB = getCellValue(b, column);
|
||||
|
||||
if (!isNaN(valA) && !isNaN(valB)) {
|
||||
return order === 'asc' ? valA - valB : valB - valA;
|
||||
}
|
||||
return order === 'asc'
|
||||
? valA.localeCompare(valB)
|
||||
: valB.localeCompare(valA);
|
||||
});
|
||||
|
||||
elements.resultsTableBody.innerHTML = '';
|
||||
rows.forEach(row => elements.resultsTableBody.appendChild(row));
|
||||
|
||||
headers.forEach(header => {
|
||||
const icon = header.querySelector('.sort-icon');
|
||||
if (icon) {
|
||||
icon.removeAttribute('uk-icon');
|
||||
}
|
||||
});
|
||||
|
||||
const currentHeader = headers[column];
|
||||
const icon = currentHeader.querySelector('.sort-icon');
|
||||
if (icon) {
|
||||
icon.setAttribute('uk-icon', `icon: ${order === 'asc' ? 'triangle-up' : 'triangle-down'}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -435,6 +489,19 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
modal.close();
|
||||
}
|
||||
});
|
||||
|
||||
function setupSorting() {
|
||||
const headers = document.querySelectorAll('#results-table thead th');
|
||||
headers.forEach((header, index) => {
|
||||
let sortOrder = 'asc';
|
||||
header.addEventListener('click', () => {
|
||||
utils.sortResultsTable(index, sortOrder);
|
||||
sortOrder = sortOrder === 'asc' ? 'desc' : 'asc';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setupSorting();
|
||||
}
|
||||
|
||||
// Initialize
|
||||
|
||||
@@ -47,15 +47,15 @@
|
||||
<table id="results-table" class="uk-table uk-table-hover uk-table-divider" role="grid">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col" data-sort="index"># <span class="sort-icon" uk-icon></span></th>
|
||||
<th scope="col">Preview</th>
|
||||
<th scope="col">Title</th>
|
||||
<th scope="col">Author</th>
|
||||
<th scope="col">Publisher</th>
|
||||
<th scope="col">Year</th>
|
||||
<th scope="col">Language</th>
|
||||
<th scope="col">Format</th>
|
||||
<th scope="col">Size</th>
|
||||
<th scope="col" data-sort="title">Title <span class="sort-icon" uk-icon></span></th>
|
||||
<th scope="col" data-sort="author">Author <span class="sort-icon" uk-icon></span></th>
|
||||
<th scope="col" data-sort="publisher">Publisher <span class="sort-icon" uk-icon></span></th>
|
||||
<th scope="col" data-sort="year">Year <span class="sort-icon" uk-icon></span></th>
|
||||
<th scope="col" data-sort="language">Language <span class="sort-icon" uk-icon></span></th>
|
||||
<th scope="col" data-sort="format">Format <span class="sort-icon" uk-icon></span></th>
|
||||
<th scope="col" data-sort="size">Size <span class="sort-icon" uk-icon></span></th>
|
||||
<th scope="col">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
Reference in New Issue
Block a user