diff --git a/js/paginator.js b/js/paginator.js index 378174b..c267f9c 100644 --- a/js/paginator.js +++ b/js/paginator.js @@ -1,27 +1,228 @@ -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'); +(function () { + 'use strict'; - pageButtons.forEach(button => { - button.addEventListener('click', function() { - if (this.disabled) return; + const state = { + items: [], + sorted: [], + category: 'all', + sort: 'alphabet', + limit: 10, + page: 1, + }; - const targetPage = this.getAttribute('data-page'); + function loadData() { + const el = document.getElementById('s-res-data'); + if (!el) return []; + try { + return JSON.parse(el.textContent); + } catch (e) { + console.error('Suchergebnis-Daten konnten nicht gelesen werden', e); + return []; + } + } - if (targetPage && form && pageInput) { - pageInput.value = targetPage; - form.submit(); - } + function applyFilterAndSort() { + let list = state.items.slice(); + + if (state.category && state.category !== 'all') { + list = list.filter(item => (item.category || '') === state.category); + } + + switch (state.sort) { + case 'likes': + list.sort((a, b) => (b.likes || 0) - (a.likes || 0)); + break; + case 'newest': + list.sort((a, b) => (b.creationDate || '').localeCompare(a.creationDate || '')); + break; + case 'oldest': + list.sort((a, b) => (a.creationDate || '').localeCompare(b.creationDate || '')); + break; + default: + list.sort((a, b) => (a.title || '').localeCompare(b.title || '', 'de', { sensitivity: 'base' })); + } + + state.sorted = list; + const totalPages = Math.max(1, Math.ceil(state.sorted.length / state.limit)); + state.page = Math.min(Math.max(state.page, 1), totalPages); + } + + function el(tag, className, text) { + const e = document.createElement(tag); + if (className) e.className = className; + if (text !== undefined) e.textContent = text; + return e; + } + + function renderList() { + const container = document.querySelector('.s-res-list'); + if (!container) return; + + const start = (state.page - 1) * state.limit; + const pageItems = state.sorted.slice(start, start + state.limit); + + container.innerHTML = ''; + + if (pageItems.length === 0) { + container.appendChild(el('p', null, 'Keine Beiträge zu diesem Suchbegriff gefunden.')); + return; + } + + pageItems.forEach(item => { + const item_el = el('div', 's-res-item'); + item_el.dataset.likes = item.likes; + item_el.dataset.category = item.category; + + const link = el('a', 's-res-link', item.title); + link.href = 'index.php?pfad=showArticle&id=' + encodeURIComponent(item.id); + + const title = el('h2', 's-res-item-title'); + title.appendChild(link); + + const authorName = el('span', 's-res-author-name', item.author); + const author = el('p', 's-res-author', 'Von: '); + author.appendChild(authorName); + + const likes = el('span', 's-res-likes', '❤️ ' + item.likes); + + const metaRow = el('div', 's-res-meta-row'); + metaRow.appendChild(author); + metaRow.appendChild(likes); + + const content = el('div', 's-res-content'); + content.appendChild(title); + content.appendChild(metaRow); + + item_el.appendChild(content); + item_el.appendChild(el('div', 's-res-arrow', '→')); + + container.appendChild(item_el); }); - }); -} + } -// 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(); -} \ No newline at end of file + function renderMeta() { + const metaEl = document.querySelector('.s-res-meta'); + const queryInput = document.getElementById('site-search'); + if (metaEl) { + const q = queryInput ? queryInput.value : ''; + metaEl.textContent = state.sorted.length + ' Treffer für Ihre Suchanfrage "' + q + '"'; + } + } + + function renderPagination() { + const nav = document.querySelector('.s-res-page-navigation'); + if (!nav) return; + + const totalPages = Math.max(1, Math.ceil(state.sorted.length / state.limit)); + nav.innerHTML = ''; + + const makeBtn = (label, page, disabled, active) => { + const btn = el('button', 's-res-page-btn' + (active ? ' is-active' : ''), label); + btn.type = 'button'; + btn.disabled = !!disabled; + btn.addEventListener('click', () => goToPage(page)); + return btn; + }; + + nav.appendChild(makeBtn('«', state.page - 1, state.page <= 1)); + + const windowSize = 2; + for (let p = 1; p <= totalPages; p++) { + const edge = p === 1 || p === totalPages; + const near = Math.abs(p - state.page) <= windowSize; + if (!edge && !near) { + if (p === 2 || p === totalPages - 1) nav.appendChild(el('span', 's-res-page-dots', '…')); + continue; + } + nav.appendChild(makeBtn(String(p), p, false, p === state.page)); + } + + nav.appendChild(makeBtn('»', state.page + 1, state.page >= totalPages)); + } + + function updateUrl() { + const url = new URL(window.location.href); + url.searchParams.set('sort', state.sort); + url.searchParams.set('category', state.category); + url.searchParams.set('limit', state.limit); + url.searchParams.set('page', state.page); + window.history.replaceState(null, '', url); + } + + function rerender() { + applyFilterAndSort(); + renderList(); + renderMeta(); + renderPagination(); + updateUrl(); + } + + function goToPage(page) { + const totalPages = Math.max(1, Math.ceil(state.sorted.length / state.limit)); + state.page = Math.min(Math.max(page, 1), totalPages); + renderList(); + renderPagination(); + updateUrl(); + } + + function initPaginator() { + state.items = loadData(); + + const checkedSort = document.querySelector('.sort-radio:checked'); + state.sort = checkedSort ? checkedSort.value : 'alphabet'; + + const categorySelect = document.getElementById('category-filter'); + state.category = categorySelect ? categorySelect.value.toLowerCase() : 'all'; + + const limitSelect = document.getElementById('s-res-per-page'); + state.limit = limitSelect ? parseInt(limitSelect.value, 10) || 10 : 10; + + const params = new URLSearchParams(window.location.search); + state.page = parseInt(params.get('page') || '1', 10) || 1; + + document.querySelectorAll('.sort-radio').forEach(radio => { + radio.addEventListener('change', function () { + state.sort = this.value; + state.page = 1; + rerender(); + }); + }); + + if (categorySelect) { + categorySelect.addEventListener('change', function () { + state.category = this.value.toLowerCase(); + state.page = 1; + rerender(); + }); + } + + if (limitSelect) { + limitSelect.addEventListener('change', function () { + state.limit = parseInt(this.value, 10) || 10; + state.page = 1; + rerender(); + }); + } + + // "Filter anwenden"-Button wird bei aktivem JS nicht gebraucht + const applyBtn = document.querySelector('.s-res-apply-btn'); + if (applyBtn) applyBtn.style.display = 'none'; + + // Server-gerenderte Pagination-Links durch clientseitige Steuerung ersetzen + document.querySelectorAll('.s-res-page-navigation .s-res-page-btn').forEach(link => { + link.addEventListener('click', function (evt) { + evt.preventDefault(); + const target = parseInt(this.getAttribute('data-page'), 10); + if (!isNaN(target)) goToPage(target); + }); + }); + + rerender(); + } + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', initPaginator); + } else { + initPaginator(); + } +})(); \ No newline at end of file diff --git a/php/controller/search-results-controller.php b/php/controller/search-results-controller.php index 976685d..1ee24b3 100644 --- a/php/controller/search-results-controller.php +++ b/php/controller/search-results-controller.php @@ -16,37 +16,11 @@ if ($_SERVER["REQUEST_METHOD"] === "GET" && isset($_GET["q"])) { $_SESSION["message"] = "invalid_search_query"; } else { try { - $articleManager = ArticleManager::getInstance(); $userManager = UserManager::getInstance(); $results = $articleManager->search($search); - $sortStyle = $_GET['sort'] ?? 'alphabet'; - $_SESSION['search_sort'] = $sortStyle; - - if ($sortStyle === 'alphabet') { - // Titel aufsteigend alphabetiisch sortiert - usort($results, function ($a, $b) { - return strcasecmp($a->getTitle(), $b->getTitle()); - }); - } elseif ($sortStyle === 'likes') { - usort($results, function($a, $b) { - return $b->getLikeCount() <=> $a->getLikeCount(); - }); - } elseif ($sortStyle === 'newest') { - // Datum neu zu alt sortiert - usort($results, function($a, $b) { - return strcmp($b->getCreationDate(), $a->getCreationDate()); - }); - } elseif ($sortStyle === 'oldest') { - // Datum alt zu neu sortiert - usort($results, function($a, $b) { - return strcmp($a->getCreationDate(), $b->getCreationDate()); - }); - } - - // Ergebnisse werden in ein flaches array umgewandelt, da sont incomplete-PHP error im Ergebnis $safeArrayResults = []; foreach ($results as $obj) { $safeArrayResults[] = [ @@ -65,20 +39,16 @@ if ($_SERVER["REQUEST_METHOD"] === "GET" && isset($_GET["q"])) { $_SESSION["search_query"] = $search; $_SESSION["message"] = "new_search_results"; - } catch (Exception $e){ + // Bei einer neuen Suche Anzeige-Filter zurücksetzen + $_SESSION['search_sort'] = 'alphabet'; + $_SESSION['search_category'] = 'all'; + $_SESSION['search_limit'] = 10; + + } catch (Exception $e) { $_SESSION["message"] = "internal_error"; } } - $sort = $_GET['sort'] ?? 'alphabet'; - $limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 10; - if (!searchLimitValidator($limit)) { - $limit = 10; - } - $page = isset($_GET['page']) ? (int)$_GET['page'] : 1; - header("Location: ../../index.php?pfad=search-results&q=" . urlencode($search) . "&sort=" . urlencode($sort) . "&limit=" . $limit . "&page=" . $page); + header("Location: ../../index.php?pfad=search-results&q=" . urlencode($search)); exit(); - -} - -?> \ No newline at end of file +} \ No newline at end of file