Files
webprogrammierung/js/paginator.js
T
2026-07-18 15:05:22 +02:00

203 lines
7.5 KiB
JavaScript

/**
* Übernimmt Filterung (Kategorie), Sortierung und Pagination der
* Suchergebnisse vollständig clientseitig, ohne Neuladen der Seite.
*
* Voraussetzung: Im HTML liegt ein <script type="application/json" id="s-res-data">
* mit allen Treffern der aktuellen Suche (siehe content/search-results.php).
*
* Ist kein JavaScript aktiv, bleibt die serverseitig gerenderte Ausgabe
* (inkl. echter Pagination-Links und Formular-Submit) unverändert nutzbar.
*/
(function () {
const DEFAULT_PER_PAGE = 10;
const state = {
all: [],
filtered: [],
category: 'all',
sort: 'alphabet',
perPage: DEFAULT_PER_PAGE,
page: 1,
};
const els = {};
function init() {
const dataScript = document.getElementById('s-res-data');
const listContainer = document.querySelector('.s-res-list');
if (!dataScript || !listContainer) {
return; // keine Ergebnisliste auf dieser Seite vorhanden
}
try {
state.all = JSON.parse(dataScript.textContent);
} catch (e) {
console.error('Suchergebnis-Daten konnten nicht gelesen werden.', e);
return;
}
els.list = listContainer;
els.categorySelect = document.getElementById('category-filter');
els.perPageSelect = document.getElementById('s-res-per-page');
els.sortRadios = document.querySelectorAll('.sort-radio');
els.pagerContainer = document.querySelector('.s-res-page-navigation');
els.metaCount = document.querySelector('.s-res-meta');
// Ausgangszustand aus dem serverseitig gerenderten Markup übernehmen,
// damit Browser-zurück / geteilte Links konsistent bleiben.
if (els.categorySelect) state.category = els.categorySelect.value || 'all';
if (els.perPageSelect) state.perPage = parseInt(els.perPageSelect.value, 10) || DEFAULT_PER_PAGE;
const checkedSort = document.querySelector('.sort-radio:checked');
if (checkedSort) state.sort = checkedSort.value;
// Ab hier übernimmt JS: Formular-Steuerelemente lösen keinen
// Seiten-Reload mehr aus, sondern rendern direkt neu.
if (els.categorySelect) {
els.categorySelect.addEventListener('change', function () {
state.category = this.value;
state.page = 1;
render();
});
}
if (els.perPageSelect) {
els.perPageSelect.addEventListener('change', function () {
state.perPage = parseInt(this.value, 10) || DEFAULT_PER_PAGE;
state.page = 1;
render();
});
}
els.sortRadios.forEach(function (radio) {
radio.addEventListener('change', function () {
state.sort = this.value;
state.page = 1;
render();
});
});
render();
}
function sortItems(items, sortValue) {
const copy = items.slice();
switch (sortValue) {
case 'likes':
copy.sort(function (a, b) { return (b.likes || 0) - (a.likes || 0); });
break;
case 'newest':
copy.sort(function (a, b) { return (b.creationDate || '').localeCompare(a.creationDate || ''); });
break;
case 'oldest':
copy.sort(function (a, b) { return (a.creationDate || '').localeCompare(b.creationDate || ''); });
break;
case 'alphabet':
default:
copy.sort(function (a, b) { return a.title.localeCompare(b.title, 'de', { sensitivity: 'base' }); });
break;
}
return copy;
}
function render() {
let items = state.all;
if (state.category && state.category !== 'all') {
items = items.filter(function (it) {
return (it.category || '').toLowerCase() === state.category.toLowerCase();
});
}
state.filtered = sortItems(items, state.sort);
const totalResults = state.filtered.length;
const totalPages = Math.max(1, Math.ceil(totalResults / state.perPage));
if (state.page > totalPages) state.page = totalPages;
if (state.page < 1) state.page = 1;
const start = (state.page - 1) * state.perPage;
const pageItems = state.filtered.slice(start, start + state.perPage);
renderList(pageItems);
renderPager(totalPages);
renderMeta(totalResults);
}
function renderList(items) {
els.list.innerHTML = '';
if (items.length === 0) {
const p = document.createElement('p');
p.textContent = 'Keine Beiträge zu diesem Suchbegriff gefunden.';
els.list.appendChild(p);
return;
}
items.forEach(function (item) {
const div = document.createElement('div');
div.className = 's-res-item';
div.setAttribute('data-likes', item.likes || 0);
div.setAttribute('data-category', (item.category || '').toLowerCase());
div.innerHTML =
'<div class="s-res-content">' +
'<h2 class="s-res-item-title">' +
'<a class="s-res-link"></a>' +
'</h2>' +
'<div class="s-res-meta-row">' +
'<p class="s-res-author">Von: <span class="s-res-author-name"></span></p>' +
'<span class="s-res-likes"></span>' +
'</div>' +
'</div>' +
'<div class="s-res-arrow">&rarr;</div>';
const link = div.querySelector('.s-res-link');
link.href = 'index.php?pfad=showArticle&id=' + encodeURIComponent(item.id);
link.textContent = item.title;
div.querySelector('.s-res-author-name').textContent = item.author;
div.querySelector('.s-res-likes').textContent = item.likes || 0;
els.list.appendChild(div);
});
}
function renderPager(totalPages) {
if (!els.pagerContainer) return;
els.pagerContainer.innerHTML = '';
const prevBtn = document.createElement('button');
prevBtn.type = 'button';
prevBtn.className = 's-res-page-btn';
prevBtn.textContent = '\u00AB';
prevBtn.disabled = state.page <= 1;
prevBtn.addEventListener('click', function () { goToPage(state.page - 1); });
els.pagerContainer.appendChild(prevBtn);
const span = document.createElement('span');
span.id = 'dynamic-page-numbers';
span.textContent = 'Seite ' + state.page + ' von ' + totalPages;
els.pagerContainer.appendChild(span);
const nextBtn = document.createElement('button');
nextBtn.type = 'button';
nextBtn.className = 's-res-page-btn';
nextBtn.textContent = '\u00BB';
nextBtn.disabled = state.page >= totalPages;
nextBtn.addEventListener('click', function () { goToPage(state.page + 1); });
els.pagerContainer.appendChild(nextBtn);
}
function renderMeta(totalResults) {
if (!els.metaCount) return;
const query = els.metaCount.getAttribute('data-query') || '';
els.metaCount.textContent = totalResults + ' Treffer für Ihre Suchanfrage "' + query + '"';
}
function goToPage(page) {
state.page = page;
render();
els.list.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();