search-results.js
This commit is contained in:
+198
-22
@@ -1,27 +1,203 @@
|
||||
function initPaginator() {
|
||||
const form = document.getElementById('search-form-id');
|
||||
const pageInput = document.getElementById('s-res-page-input');
|
||||
const pageButtons = document.querySelectorAll('.s-res-page-navigation .s-res-page-btn');
|
||||
/**
|
||||
* Ü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;
|
||||
|
||||
pageButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
if (this.disabled) return;
|
||||
const state = {
|
||||
all: [],
|
||||
filtered: [],
|
||||
category: 'all',
|
||||
sort: 'alphabet',
|
||||
perPage: DEFAULT_PER_PAGE,
|
||||
page: 1,
|
||||
};
|
||||
|
||||
const targetPage = this.getAttribute('data-page');
|
||||
const els = {};
|
||||
|
||||
if (targetPage && form && pageInput) {
|
||||
pageInput.value = targetPage;
|
||||
form.submit();
|
||||
}
|
||||
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();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ist das DOM bereits vollständig aufgebaut?
|
||||
if (document.readyState === 'loading') {
|
||||
// Falls noch geladen wird, auf das Event warten
|
||||
document.addEventListener('DOMContentLoaded', initPaginator);
|
||||
} else {
|
||||
// Falls das HTML bereits komplett da ist, sofort ausführen
|
||||
initPaginator();
|
||||
}
|
||||
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">→</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();
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user