(function () { function getTableSortState(table) { if (!table._tableSortState) { table._tableSortState = { sortKey: '', direction: 'asc' }; } return table._tableSortState; } function ensureSortableHeaderIndicator(headerCell) { var indicator = headerCell.querySelector && headerCell.querySelector('.table-sort-indicator'); if (indicator) { return indicator; } indicator = document.createElement('i'); indicator.className = 'table-sort-indicator bi bi-arrow-down-up ms-1'; indicator.setAttribute('aria-hidden', 'true'); headerCell.appendChild(indicator); return indicator; } function updateSortableHeaderState(table) { var state = getTableSortState(table); var currentUrl = new URL(window.location.href); var activeSortKey = String(currentUrl.searchParams.get('sort') || '').trim(); var activeDirection = String(currentUrl.searchParams.get('direction') || '').trim().toLowerCase() === 'desc' ? 'desc' : 'asc'; var headerCells = table.tHead && table.tHead.rows && table.tHead.rows.length ? Array.prototype.slice.call(table.tHead.rows[0].cells || []) : []; state.sortKey = activeSortKey; state.direction = activeDirection; headerCells.forEach(function (headerCell) { if (!headerCell) { return; } var sortKey = String(headerCell.getAttribute && headerCell.getAttribute('data-table-sort-key') || '').trim(); var sortable = Boolean(sortKey) && String(headerCell.getAttribute('data-sortable') || '').toLowerCase() !== 'false'; headerCell.classList.remove('sort-asc', 'sort-desc', 'sortable', 'unsortable'); headerCell.removeAttribute('aria-sort'); if (!sortable) { headerCell.classList.add('unsortable'); var hiddenIndicator = headerCell.querySelector && headerCell.querySelector('.table-sort-indicator'); if (hiddenIndicator) { hiddenIndicator.style.display = 'none'; } return; } var indicator = ensureSortableHeaderIndicator(headerCell); indicator.style.display = ''; indicator.className = 'table-sort-indicator bi ms-1'; headerCell.classList.add('sortable'); headerCell.setAttribute('role', 'button'); headerCell.setAttribute('tabindex', '0'); if (sortKey === activeSortKey) { headerCell.classList.add(activeDirection === 'desc' ? 'sort-desc' : 'sort-asc'); headerCell.setAttribute('aria-sort', activeDirection === 'desc' ? 'descending' : 'ascending'); if (activeDirection === 'desc') { indicator.classList.add('bi-caret-down-fill'); } else { indicator.classList.add('bi-caret-up-fill'); } return; } headerCell.setAttribute('aria-sort', 'none'); indicator.classList.add('bi-arrow-down-up'); }); } function buildSortedUrl(sortKey) { var currentUrl = new URL(window.location.href); var nextUrl = new URL(window.location.href); var currentSortKey = String(currentUrl.searchParams.get('sort') || '').trim(); var currentDirection = String(currentUrl.searchParams.get('direction') || '').trim().toLowerCase() === 'desc' ? 'desc' : 'asc'; if (currentSortKey === sortKey) { nextUrl.searchParams.set('direction', currentDirection === 'asc' ? 'desc' : 'asc'); } else { nextUrl.searchParams.set('sort', sortKey); nextUrl.searchParams.set('direction', 'asc'); } nextUrl.searchParams.delete('page'); return nextUrl; } function updateUrlState(nextUrl) { if (window.history && window.history.replaceState) { window.history.replaceState({}, document.title, nextUrl.pathname + nextUrl.search + nextUrl.hash); } } function refreshSortedTable(table, nextUrl, requestSequence, sequenceId) { var container = table ? (table.closest('[data-table-search-container]') || table.closest('.card') || null) : null; fetch(nextUrl.toString(), { method: 'GET', headers: { 'Accept': 'text/html, application/xhtml+xml', 'X-Requested-With': 'XMLHttpRequest' }, credentials: 'same-origin', cache: 'no-store' }).then(function (response) { if (!response.ok) { throw new Error('Unable to load sorted results.'); } return response.text(); }).then(function (text) { if (sequenceId !== requestSequence.value) { return; } var responseDocument = new DOMParser().parseFromString(text || '', 'text/html'); updateUrlState(nextUrl); if (window.replaceTableResults && replaceTableResults(container, responseDocument)) { if (typeof window.initSortableTables === 'function') { window.initSortableTables(container || document); } if (typeof window.initTableSearches === 'function') { window.initTableSearches(container || document); } if (typeof window.initLocalDateTimes === 'function') { window.initLocalDateTimes(container || document); } } }).catch(function () { window.location.assign(nextUrl.toString()); }); } function initSortableTables(root) { var scope = root && root.querySelectorAll ? root : document; Array.prototype.forEach.call(scope.querySelectorAll('table[data-table-searchable]'), function (table) { var headerRow = table.tHead && table.tHead.rows && table.tHead.rows.length ? table.tHead.rows[0] : null; if (!headerRow) { return; } if (table.getAttribute('data-table-sort-bound') === 'true') { updateSortableHeaderState(table); return; } table.setAttribute('data-table-sort-bound', 'true'); var requestSequence = { value: 0 }; Array.prototype.forEach.call(headerRow.cells, function (headerCell) { if (!headerCell) { return; } var sortKey = String(headerCell.getAttribute && headerCell.getAttribute('data-table-sort-key') || '').trim(); var isSortable = Boolean(sortKey) && String(headerCell.getAttribute('data-sortable') || '').toLowerCase() !== 'false'; if (!isSortable) { return; } if (headerCell.getAttribute('data-table-sort-bound') === 'true') { return; } headerCell.setAttribute('data-table-sort-bound', 'true'); ensureSortableHeaderIndicator(headerCell); headerCell.addEventListener('click', function () { var nextUrl = buildSortedUrl(sortKey); requestSequence.value += 1; var sequenceId = requestSequence.value; refreshSortedTable(table, nextUrl, requestSequence, sequenceId); }); headerCell.addEventListener('keydown', function (event) { if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); headerCell.click(); } }); }); updateSortableHeaderState(table); }); } window.initSortableTables = initSortableTables; initSortableTables(); }());