diff --git a/content/search-results.php b/content/search-results.php index c4793b5..8f0430c 100644 --- a/content/search-results.php +++ b/content/search-results.php @@ -4,6 +4,12 @@ if (session_status() === PHP_SESSION_NONE) { } $all_results = $_SESSION["search_results"] ?? []; +?> + + +
- - - - - + + 1): ?> + « + + « + + + + + + + + + + » + + » +
+ diff --git a/js/paginator.js b/js/paginator.js index 378174b..f9817f0 100644 --- a/js/paginator.js +++ b/js/paginator.js @@ -1,27 +1,218 @@ +// Globale Variablen für den JavaScript-Betrieb +let allItems = []; +let filteredItems = []; +let currentJsPage = 1; +let jsLimit = 10; + 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'); + const dataContainer = document.getElementById('search-data-json'); + if (!dataContainer) return; - pageButtons.forEach(button => { - button.addEventListener('click', function() { - if (this.disabled) return; + // 1. Daten aus PHP-JSON-Schnittstelle laden + try { + allItems = JSON.parse(dataContainer.textContent); + } catch (e) { + console.error("Fehler beim Laden der Suchdaten:", e); + return; + } - const targetPage = this.getAttribute('data-page'); + // 2. Event-Listener für Live-Interaktionen im Browser registrieren + const sortRadios = document.querySelectorAll('.sort-radio'); + const categorySelect = document.getElementById('category-filter'); + const limitSelect = document.getElementById('s-res-per-page'); - if (targetPage && form && pageInput) { - pageInput.value = targetPage; - form.submit(); + sortRadios.forEach(radio => radio.addEventListener('change', applyFiltersAndRender)); + if (categorySelect) categorySelect.addEventListener('change', applyFiltersAndRender); + if (limitSelect) { + limitSelect.addEventListener('change', function() { + jsLimit = parseInt(this.value) || 10; + currentJsPage = 1; // Zurück auf Seite 1 bei Limit-Wechsel + applyFiltersAndRender(); + }); + } + + // Pfeil-Navigation (Vor / Zurück) abfangen + const prevBtn = document.getElementById('prev-page-btn'); + const nextBtn = document.getElementById('next-page-btn'); + + if (prevBtn) { + prevBtn.addEventListener('click', function(e) { + e.preventDefault(); + if (currentJsPage > 1) { + currentJsPage--; + renderListAndPagination(); } }); - }); + } + + if (nextBtn) { + nextBtn.addEventListener('click', function(e) { + e.preventDefault(); + const totalPages = Math.max(1, Math.ceil(filteredItems.length / jsLimit)); + if (currentJsPage < totalPages) { + currentJsPage++; + renderListAndPagination(); + } + }); + } + + // Initialer Start: Daten verarbeiten und anzeigen + // Liest das vom Server übergebene Limit aus + if (limitSelect) jsLimit = parseInt(limitSelect.value) || 10; + applyFiltersAndRender(); } -// ist das DOM bereits vollständig aufgebaut? +// Verarbeitet Sortierung + Filterung komplett im Browser (Serverentlastung) +function applyFiltersAndRender() { + // KATEGORIE FILTERN + const categorySelect = document.getElementById('category-filter'); + const activeCategory = categorySelect ? categorySelect.value : 'all'; + + if (activeCategory === 'all') { + filteredItems = [...allItems]; + } else { + filteredItems = allItems.filter(item => + item.category && item.category.toLowerCase() === activeCategory.toLowerCase() + ); + } + + // SORTIERUNG ANWENDEN + const activeSortRadio = document.querySelector('.sort-radio:checked'); + const sortStyle = activeSortRadio ? activeSortRadio.value : 'alphabet'; + + if (sortStyle === 'alphabet') { + filteredItems.sort((a, b) => (a.title || '').localeCompare(b.title || '', 'de', { sensitivity: 'base' })); + } else if (sortStyle === 'likes') { + filteredItems.sort((a, b) => { + const countA = Array.isArray(a.likes) ? a.likes.length : (parseInt(a.likes) || 0); + const countB = Array.isArray(b.likes) ? b.likes.length : (parseInt(b.likes) || 0); + return countB - countA; + }); + } else if (sortStyle === 'newest') { + filteredItems.sort((a, b) => (b.creationDate || '').localeCompare(a.creationDate || '')); + } else if (sortStyle === 'oldest') { + filteredItems.sort((a, b) => (a.creationDate || '').localeCompare(b.creationDate || '')); + } + + // Nach dem Filtern/Sortieren springen wir zurück auf Seite 1 + currentJsPage = 1; + renderListAndPagination(); +} + +// HTML-Listenansicht und Paginierungs-Zahlen neu aufbauen +function renderListAndPagination() { + const listContainer = document.querySelector('.s-res-list'); + const pageNumbersContainer = document.getElementById('dynamic-page-numbers'); + if (!listContainer) return; + + // Gesamtseitenzahl berechnen + const totalPages = Math.max(1, Math.ceil(filteredItems.length / jsLimit)); + if (currentJsPage > totalPages) currentJsPage = totalPages; + + // Meta-Text aktualisieren (Trefferanzeige) + const metaText = document.querySelector('.s-res-meta'); + if (metaText) { + const queryText = metaText.textContent.split('"')[1] || ''; + metaText.innerHTML = `${filteredItems.length} Treffer für Ihre Suchanfrage "${queryText}"`; + } + + // 1. ERGEBNISLISTE IM DOM REINJECKTEN + listContainer.innerHTML = ''; // Vorherige Ergebnisse leeren + + if (filteredItems.length === 0) { + listContainer.innerHTML = '

Keine Beiträge zu diesem Suchbegriff gefunden.

'; + if (pageNumbersContainer) pageNumbersContainer.innerHTML = ''; + updateArrowButtons(totalPages); + return; + } + + // Ausschnitt für die aktuelle Seite berechnen (Offset) + const offset = (currentJsPage - 1) * jsLimit; + const pageItems = filteredItems.slice(offset, offset + jsLimit); + + // HTML für die Zeilen generieren + pageItems.forEach(item => { + const likesCount = Array.isArray(item.likes) ? item.likes.length : (parseInt(item.likes) || 0); + const itemHtml = ` +
+
+

+ ${escapeHtml(item.title)} +

+
+

Von: ${escapeHtml(item.author)}

+ ❤️ ${likesCount} +
+
+
+
+ `; + listContainer.insertAdjacentHTML('beforeend', itemHtml); + }); + + // 2. DYNAMISCHE SEITENZAHLEN GENERIEREN + if (pageNumbersContainer) { + pageNumbersContainer.innerHTML = ''; // Vorherige Zahlen leeren + + // Erzeugt Klickbare Seitenzahlen im JS-Modus + for (let i = 1; i <= totalPages; i++) { + const pageBtn = document.createElement('button'); + pageBtn.type = 'button'; + pageBtn.className = `s-res-page-btn ${i === currentJsPage ? 'active' : ''}`; + pageBtn.innerText = i; + + pageBtn.addEventListener('click', function() { + currentJsPage = i; + renderListAndPagination(); + }); + + pageNumbersContainer.appendChild(pageBtn); + } + } + + updateArrowButtons(totalPages); +} + +// Steuert die Aktivierung/Deaktivierung der Vor- und Zurück-Pfeile +function updateArrowButtons(totalPages) { + const prevBtn = document.getElementById('prev-page-btn'); + const nextBtn = document.getElementById('next-page-btn'); + + if (prevBtn) { + if (currentJsPage <= 1) { + prevBtn.classList.add('disabled'); + prevBtn.style.pointerEvents = 'none'; + } else { + prevBtn.classList.remove('disabled'); + prevBtn.style.pointerEvents = 'auto'; + } + } + + if (nextBtn) { + if (currentJsPage >= totalPages) { + nextBtn.classList.add('disabled'); + nextBtn.style.pointerEvents = 'none'; + } else { + nextBtn.classList.remove('disabled'); + nextBtn.style.pointerEvents = 'auto'; + } + } +} + +// Hilfsfunktion gegen XSS-Injections im Browser +function escapeHtml(text) { + if (!text) return ''; + return text.toString() + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} + +// DOM-Ready Check 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(); -} \ No newline at end of file +}