254 lines
8.5 KiB
JavaScript
254 lines
8.5 KiB
JavaScript
(function () {
|
|
var minimumPaginationCardHeight = 20 * 16;
|
|
|
|
function rebindTableContainer(container) {
|
|
if (!container) {
|
|
return;
|
|
}
|
|
|
|
if (typeof window.initSortableTables === 'function') {
|
|
window.initSortableTables(container);
|
|
}
|
|
|
|
if (typeof window.initTableSearches === 'function') {
|
|
window.initTableSearches(container);
|
|
}
|
|
|
|
if (typeof window.initLocalDateTimes === 'function') {
|
|
window.initLocalDateTimes(container);
|
|
}
|
|
|
|
syncTablePaginationCards(container);
|
|
syncTablePaginationPageClass();
|
|
}
|
|
|
|
function syncTablePaginationCards(root) {
|
|
if (!root || !root.querySelectorAll) {
|
|
return;
|
|
}
|
|
|
|
Array.prototype.forEach.call(root.querySelectorAll('[data-table-pagination-card]'), function (card) {
|
|
if (!card || !card.getBoundingClientRect) {
|
|
return;
|
|
}
|
|
|
|
var cardRect = card.getBoundingClientRect();
|
|
var bottomInset = 16;
|
|
var availableHeight = Math.max(0, window.innerHeight - cardRect.top - bottomInset);
|
|
var contentHeight = Math.max(0, card.scrollHeight || 0);
|
|
var shouldApplyMinimum = contentHeight > minimumPaginationCardHeight;
|
|
var cardHeight = Math.max(minimumPaginationCardHeight, availableHeight);
|
|
|
|
if (shouldApplyMinimum) {
|
|
card.style.setProperty('--table-pagination-card-min-height', minimumPaginationCardHeight + 'px');
|
|
} else {
|
|
card.style.removeProperty('--table-pagination-card-min-height');
|
|
}
|
|
|
|
card.style.removeProperty('--table-pagination-card-height');
|
|
card.style.setProperty('--table-pagination-card-max-height', cardHeight + 'px');
|
|
});
|
|
}
|
|
|
|
function syncTablePaginationPageClass() {
|
|
if (!document || !document.body || !document.body.classList) {
|
|
return;
|
|
}
|
|
|
|
document.body.classList.toggle('table-pagination-page', !!document.querySelector('[data-table-pagination-card]'));
|
|
}
|
|
|
|
function focusSearchInput(input) {
|
|
if (!input || !input.focus) {
|
|
return;
|
|
}
|
|
|
|
input.focus();
|
|
|
|
if (typeof input.setSelectionRange === 'function') {
|
|
var valueLength = String(input.value || '').length;
|
|
try {
|
|
input.setSelectionRange(valueLength, valueLength);
|
|
} catch (_error) {
|
|
// Ignore selection failures on unsupported input types.
|
|
}
|
|
}
|
|
}
|
|
|
|
function replaceTableResults(container, responseDocument) {
|
|
if (!container || !responseDocument || !responseDocument.querySelector) {
|
|
return false;
|
|
}
|
|
|
|
var currentTable = container.querySelector('[data-table-searchable]');
|
|
var nextContainer = responseDocument.querySelector('[data-table-search-container]') || responseDocument.querySelector('.card');
|
|
var nextTable = nextContainer ? nextContainer.querySelector('[data-table-searchable]') : null;
|
|
var currentFooter = container.querySelector('.card-footer');
|
|
var nextFooter = nextContainer ? nextContainer.querySelector('.card-footer') : null;
|
|
|
|
if (!currentTable || !nextTable) {
|
|
return false;
|
|
}
|
|
|
|
var currentBody = currentTable.tBodies && currentTable.tBodies[0] ? currentTable.tBodies[0] : null;
|
|
var nextBody = nextTable.tBodies && nextTable.tBodies[0] ? nextTable.tBodies[0] : null;
|
|
|
|
if (!currentBody || !nextBody) {
|
|
return false;
|
|
}
|
|
|
|
currentBody.outerHTML = nextBody.outerHTML;
|
|
|
|
if (currentFooter && nextFooter) {
|
|
currentFooter.outerHTML = nextFooter.outerHTML;
|
|
} else if (currentFooter && !nextFooter) {
|
|
currentFooter.parentNode.removeChild(currentFooter);
|
|
} else if (!currentFooter && nextFooter) {
|
|
currentTable.parentNode.appendChild(nextFooter.cloneNode(true));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function initTableSearches(root) {
|
|
var scope = root && root.querySelectorAll ? root : document;
|
|
|
|
Array.prototype.forEach.call(scope.querySelectorAll('[data-table-search]'), function (input) {
|
|
if (input.getAttribute('data-table-search-bound') === 'true') {
|
|
return;
|
|
}
|
|
|
|
input.setAttribute('data-table-search-bound', 'true');
|
|
|
|
var searchParam = String(input.getAttribute('data-table-search-param') || 'search').trim() || 'search';
|
|
var currentUrl = new URL(window.location.href);
|
|
var pendingSearchTimer = null;
|
|
var requestSequence = 0;
|
|
var pendingSearchRequests = 0;
|
|
var container = input.closest('[data-table-search-container]') || input.closest('.card') || null;
|
|
|
|
input.value = String(currentUrl.searchParams.get(searchParam) || '').trim();
|
|
|
|
var searchGroup = input.closest('.table-search-group');
|
|
if (searchGroup) {
|
|
var actionButton = searchGroup.parentNode ? searchGroup.parentNode.querySelector('.btn:not(.table-search-group .btn)') : null;
|
|
if (actionButton && actionButton.getBoundingClientRect) {
|
|
searchGroup.style.setProperty('--table-search-action-offset', (actionButton.getBoundingClientRect().width + 8) + 'px');
|
|
}
|
|
var searchToggle = searchGroup.querySelector('[data-table-search-toggle]');
|
|
if (searchToggle) {
|
|
searchToggle.addEventListener('click', function () {
|
|
focusSearchInput(input);
|
|
});
|
|
searchToggle.addEventListener('keydown', function (event) {
|
|
if (event.key === 'Enter' || event.key === ' ') {
|
|
event.preventDefault();
|
|
focusSearchInput(input);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function updateSearch() {
|
|
var query = String(input.value || '').trim();
|
|
var nextUrl = new URL(window.location.href);
|
|
|
|
if (query) {
|
|
nextUrl.searchParams.set(searchParam, query);
|
|
} else {
|
|
nextUrl.searchParams.delete(searchParam);
|
|
}
|
|
nextUrl.searchParams.delete('page');
|
|
|
|
if (nextUrl.toString() === currentUrl.toString()) {
|
|
return;
|
|
}
|
|
|
|
requestSequence += 1;
|
|
var sequenceId = requestSequence;
|
|
pendingSearchRequests += 1;
|
|
if (container) {
|
|
container.setAttribute('data-table-search-loading', 'true');
|
|
}
|
|
|
|
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 search results.');
|
|
}
|
|
return response.text();
|
|
}).then(function (text) {
|
|
if (sequenceId !== requestSequence) {
|
|
return;
|
|
}
|
|
|
|
var responseDocument = new DOMParser().parseFromString(text || '', 'text/html');
|
|
|
|
if (window.history && window.history.replaceState) {
|
|
window.history.replaceState({}, document.title, nextUrl.pathname + nextUrl.search + nextUrl.hash);
|
|
}
|
|
|
|
if (replaceTableResults(container, responseDocument)) {
|
|
currentUrl = nextUrl;
|
|
rebindTableContainer(container || document);
|
|
focusSearchInput(input);
|
|
}
|
|
}).catch(function () {
|
|
window.location.assign(nextUrl.toString());
|
|
}).finally(function () {
|
|
pendingSearchRequests = Math.max(0, pendingSearchRequests - 1);
|
|
if (container && pendingSearchRequests === 0) {
|
|
container.removeAttribute('data-table-search-loading');
|
|
}
|
|
});
|
|
}
|
|
|
|
function scheduleSearchUpdate() {
|
|
if (pendingSearchTimer) {
|
|
window.clearTimeout(pendingSearchTimer);
|
|
}
|
|
pendingSearchTimer = window.setTimeout(function () {
|
|
pendingSearchTimer = null;
|
|
updateSearch();
|
|
}, 300);
|
|
}
|
|
|
|
input.addEventListener('input', scheduleSearchUpdate);
|
|
input.addEventListener('search', scheduleSearchUpdate);
|
|
input.addEventListener('change', updateSearch);
|
|
input.addEventListener('keydown', function (event) {
|
|
if (event.key === 'Enter') {
|
|
event.preventDefault();
|
|
if (pendingSearchTimer) {
|
|
window.clearTimeout(pendingSearchTimer);
|
|
pendingSearchTimer = null;
|
|
}
|
|
updateSearch();
|
|
}
|
|
});
|
|
});
|
|
|
|
syncTablePaginationCards(scope);
|
|
}
|
|
|
|
if (window.addEventListener) {
|
|
window.addEventListener('resize', function () {
|
|
syncTablePaginationCards(document);
|
|
});
|
|
window.addEventListener('orientationchange', function () {
|
|
syncTablePaginationCards(document);
|
|
});
|
|
}
|
|
|
|
window.initTableSearches = initTableSearches;
|
|
window.replaceTableResults = replaceTableResults;
|
|
syncTablePaginationCards(document);
|
|
syncTablePaginationPageClass();
|
|
}()); |