Compare commits

...

41 Commits

Author SHA1 Message Date
niklas.ortmann 36c47bb7a6 Update paginator.js 2026-07-18 14:19:12 +02:00
niklas.ortmann 6031fc0185 Update editor.js 2026-07-18 14:19:09 +02:00
niklas.ortmann e77c60d8c8 js übernimmt Sortierung + Fallback 2026-07-18 14:04:13 +02:00
niklas.ortmann 7f5cea8c1e revert 2026-07-18 13:33:15 +02:00
niklas.ortmann 71c213ef1e js sortiert die Ergebnisse 2026-07-18 13:18:04 +02:00
niklas.ortmann 0b4c5f988d Merge pull request 'Anzeigenamen' (#51) from AnzeigeNamen into dev
Reviewed-on: #51
2026-07-17 18:09:29 +02:00
niklas.ortmann 59eeb05e4b Update showCategory.php 2026-07-17 18:05:33 +02:00
niklas.ortmann 5d8239822a Update showCategory.php 2026-07-17 18:04:03 +02:00
niklas.ortmann 31585511d0 Update showCategory-controller.php 2026-07-17 18:01:59 +02:00
niklas.ortmann 2ec1b70c91 Update Article.php 2026-07-17 17:59:17 +02:00
niklas.ortmann 8f8b25249c Update showCategory-controller.php 2026-07-17 17:56:31 +02:00
niklas.ortmann 8be6e6d61c Update showCategory-controller.php 2026-07-17 17:55:37 +02:00
niklas.ortmann bad0c08e6f Update search-results-controller.php 2026-07-17 17:51:58 +02:00
niklas.ortmann 55695f3f82 Update showArticle-controller.php 2026-07-17 17:42:18 +02:00
niklas.ortmann 74cbc60cbe Update showArticle.php 2026-07-17 17:41:42 +02:00
niklas.ortmann c09c7ecfa3 Update showArticle-controller.php 2026-07-17 17:41:41 +02:00
niklas.ortmann 944e332b49 Merge pull request 'Kategorieseitenpaginator' (#50) from KategorieseitenPaginator into dev
Reviewed-on: #50
2026-07-17 17:36:10 +02:00
niklas.ortmann 4306785be9 Merge pull request 'Beitrag Bearbeiten Autorenprüfung' (#49) from Beitrag-bearbeiten-Autorenpruefung into dev
Reviewed-on: #49
2026-07-17 17:36:05 +02:00
niklas.ortmann 266b70a094 Update home.php 2026-07-17 17:32:25 +02:00
niklas.ortmann bd8593d212 Update 404.php 2026-07-17 17:29:50 +02:00
niklas.ortmann 0d009262b6 Update showCategory.php 2026-07-17 17:27:16 +02:00
niklas.ortmann bb2c368b1f Seitenleiste 2026-07-17 17:20:54 +02:00
niklas.ortmann a712f5a993 Update showCategory.css 2026-07-17 17:17:38 +02:00
niklas.ortmann 53bee08833 Update showCategory.php 2026-07-17 17:16:42 +02:00
niklas.ortmann 7a2a3ac1e9 Update showCategory.php 2026-07-17 17:13:41 +02:00
niklas.ortmann a5f02c9a6c Update showCategory.php 2026-07-17 17:13:07 +02:00
niklas.ortmann f77f09ec6f Update showCategory.php 2026-07-17 17:11:40 +02:00
niklas.ortmann 535df85cff neue showCategory.css 2026-07-17 17:11:38 +02:00
niklas.ortmann 82e8c8a1a3 Update showCategory.php 2026-07-17 17:08:02 +02:00
niklas.ortmann c0d8fdede6 Update showCategory.php 2026-07-17 17:04:54 +02:00
niklas.ortmann 958ee1c1f5 Update showCategory.php
css
2026-07-17 17:02:11 +02:00
niklas.ortmann 1dd128d480 Update showCategory.php 2026-07-17 16:59:36 +02:00
niklas.ortmann dca716ddc5 Update showCategory-controller.php 2026-07-17 16:59:34 +02:00
niklas.ortmann c1dd4fce2b Update showCategory.php 2026-07-17 16:41:09 +02:00
niklas.ortmann 16cfa92721 Update showCategory.php 2026-07-17 16:29:11 +02:00
niklas.ortmann 3b2ed78c1c Update showCategory.php 2026-07-17 16:16:14 +02:00
niklas.ortmann cebbe8869a Update showArticle-controller.php 2026-07-17 15:59:29 +02:00
niklas.ortmann e07051b356 Update showArticle-controller.php 2026-07-17 15:58:10 +02:00
niklas.ortmann 2d2bbeb39f Update showArticle-controller.php 2026-07-17 15:57:15 +02:00
niklas.ortmann c00443b6fa Update showArticle-controller.php 2026-07-17 15:56:34 +02:00
niklas.ortmann 1d541e285c Update showArticle-controller.php 2026-07-17 15:54:47 +02:00
13 changed files with 659 additions and 115 deletions
+1 -2
View File
@@ -14,7 +14,6 @@
?> ?>
<h1>404 - Seite nicht vorhanden</h1> <h1>404 - Seite nicht vorhanden</h1>
<p> <p>
Später im Projekt sollen über index.php?pfad= ... der Inhalt der index.php dynamisch gesetzt werden. Die Seite, nach der du suchst, existiert hier leider nicht. Entweder haben wir sie verlegt, ein hungriger Bug hat sie gefressen, oder du hast dich beim Tippen vertippt. (Wir schieben die Schuld einfach mal ganz unauffällig auf dich.)
Alle Content-Links der Navbar führen zunächst hier her. Exemplarisch wurden für die Fächer Informatik, Physik, Mathematik der Content als Seite erstellt und kann über die Navbar ausgekundschaftet werden.
</p> </p>
</main> </main>
+3 -6
View File
@@ -11,12 +11,9 @@ include_once 'php/controller/home-controller.php';
<h1>Home</h1> <h1>Home</h1>
<p> <p>
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et Schön, dass du da bist. EduForge ist deine digitale Werkstatt für Lernerfolg. Wir unterstützen Schüler und
dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet Studierende dabei, die passenden Lernmaterialien zu finden, Wissenslücken zu schließen und Gelerntes gezielt
clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, zu vertiefen.
consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no
sea takimata sanctus est Lorem ipsum dolor sit amet.
</p> </p>
<!-- Flexbox für aktive Kategorien --> <!-- Flexbox für aktive Kategorien -->
+12 -12
View File
@@ -45,9 +45,9 @@ $resultCount = count($results);
<!-- Links: Seitenleiste für Filter und Suche --> <!-- Links: Seitenleiste für Filter und Suche -->
<aside class="s-res-sidebar"> <aside class="s-res-sidebar">
<!-- Sortierfuntion Box und Such Box--> <!-- Sortierfuntion Box und Such Box-->
<form action="php/controller/search-results-controller.php" method="GET" id="search-form-id" class="s-res-sidebar-form"> <form action="php/controller/search-results-controller.php" method="GET" id="search-form-id" class="s-res-sidebar-form">
<input type="hidden" id="s-res-page-input" name="page" value="<?php echo $_GET['page'] ?? 1; ?>"> <input type="hidden" id="s-res-page-input" name="page" value="<?php echo $_GET['page'] ?? 1; ?>">
<div class="s-res-sidebar-box"> <div class="s-res-sidebar-box">
@@ -125,13 +125,13 @@ $resultCount = count($results);
<!-- Ergebnisliste --> <!-- Ergebnisliste -->
<div class="s-res-list"> <div class="s-res-list">
<?php <?php
if (!empty($results)): ?> if (!empty($results)): ?>
<?php foreach ($results as $item): <?php foreach ($results as $item):
// Anzahl der Likes ermitteln (falls es ein Array ist, zählen; falls Zahl, direkt nutzen) // Anzahl der Likes ermitteln (falls es ein Array ist, zählen; falls Zahl, direkt nutzen)
$likesCount = isset($item['likes']) && is_array($item['likes']) ? count($item['likes']) : ($item['likes'] ?? 0); $likesCount = isset($item['likes']) && is_array($item['likes']) ? count($item['likes']) : ($item['likes'] ?? 0);
?> ?>
<div class="s-res-item" data-likes="<?php echo $likesCount; ?>" data-category="<?php echo strtolower($item['category'] ?? ''); ?>"> <div class="s-res-item" data-likes="<?php echo $likesCount; ?>" data-category="<?php echo strtolower($item['category'] ?? ''); ?>">
<div class="s-res-content"> <div class="s-res-content">
<h2 class="s-res-item-title"> <h2 class="s-res-item-title">
@@ -151,13 +151,13 @@ $resultCount = count($results);
</div> </div>
<?php endforeach; ?> <?php endforeach; ?>
<?php <?php
elseif (isset($_SESSION["search_query"]) && $_SESSION["search_query"] !== "" && $resultCount === 0): ?> elseif (isset($_SESSION["search_query"]) && $_SESSION["search_query"] !== "" && $resultCount === 0): ?>
<p>Keine Beiträge zu diesem Suchbegriff gefunden.</p> <p>Keine Beiträge zu diesem Suchbegriff gefunden.</p>
<?php <?php
elseif (isset($_SESSION["message"]) && $_SESSION["message"] == "invalid_search_query"): ?> elseif (isset($_SESSION["message"]) && $_SESSION["message"] == "invalid_search_query"): ?>
<p>Unzulässige Suchanfrage</p> <p>Unzulässige Suchanfrage</p>
<?php endif; ?> <?php endif; ?>
<?php <?php
unset($_SESSION["message"]); unset($_SESSION["message"]);
@@ -179,9 +179,9 @@ $resultCount = count($results);
<div class="s-res-page-navigation"> <div class="s-res-page-navigation">
<button type="button" class="s-res-page-btn" id="prev-page-btn" data-page="0">«</button> <button type="button" class="s-res-page-btn" id="prev-page-btn" data-page="0">«</button>
<span id="dynamic-page-numbers"></span> <span id="dynamic-page-numbers"></span>
<button type="button" class="s-res-page-btn" id="next-page-btn" data-page="2">»</button> <button type="button" class="s-res-page-btn" id="next-page-btn" data-page="2">»</button>
</div> </div>
+2 -2
View File
@@ -45,8 +45,8 @@ include_once 'php/controller/showArticle-controller.php';
</h1> </h1>
<div class="article-view-meta"> <div class="article-view-meta">
<?php if (isset($author) && !empty($author)): ?> <?php if (isset($name) && !empty($name)): ?>
<span class="article-view-author">Von: <strong><?php echo htmlspecialchars($author); ?></strong></span> <span class="article-view-author">Von: <strong><?php echo htmlspecialchars($name); ?></strong></span>
<?php endif; ?> <?php endif; ?>
</div> </div>
+103 -24
View File
@@ -1,32 +1,111 @@
<?php <?php
include_once "php/controller/showCategory-controller.php"; include_once "php/controller/showCategory-controller.php";
$currentSort = isset($sortStyle) ? $sortStyle : 'alphabet';
$currentPage = isset($page) ? $page : 1;
?> ?>
<main> <noscript>
<?php include_once "includes/alertMessages.php"?> Bitte JavaScript aktivieren!
</noscript>
<h1><?php if (isset($category) && !empty($category)){ echo htmlspecialchars($category); } ?></h1> <!-- Das Formular umschließt jetzt das gesamte Layout -->
<form id="search-form-id" action="index.php" method="GET" style="display: contents;">
<input type="hidden" name="pfad" value="showCategory">
<input type="hidden" name="category" value="<?php echo (isset($category) && !empty($category)) ? htmlspecialchars($category) : ''; ?>">
<input type="hidden" id="s-res-page-input" name="page" value="<?php echo $currentPage; ?>">
<div class="s-res-list"> <div class="cat-view-container">
<?php
if (!empty($articles)): ?> <!-- LINKE SPALTE: SEITENLEISTE FÜR SORTIERUNG -->
<?php foreach ($articles as $article): ?> <aside class="cat-sidebar">
<div class="s-res-item"> <div class="cat-sidebar-box">
<div class="s-res-content"> <h3 class="cat-sidebar-title">Sortierung</h3>
<h2 class="s-res-item-title"> <div class="cat-filter-group">
<a href="index.php?pfad=showArticle&id=<?php echo $article->getId(); ?>" class="s-res-link"> <label class="cat-filter-option">
<?php echo htmlspecialchars($article->getTitle()); ?> <input type="radio" name="sort" value="alphabet" <?php echo ($currentSort === 'alphabet') ? 'checked' : ''; ?> onchange="this.form.submit();">
</a> Alphabetisch
</h2> </label>
<p class="s-res-author">Von: <span class="s-res-author-name"><?php echo htmlspecialchars($article->getAuthor()); ?></span></p> <label class="cat-filter-option">
</div> <input type="radio" name="sort" value="likes" <?php echo ($currentSort === 'likes') ? 'checked' : ''; ?> onchange="this.form.submit();">
<div class="s-res-arrow">&rarr;</div> Beliebtheit (Likes)
</label>
<label class="cat-filter-option">
<input type="radio" name="sort" value="newest" <?php echo ($currentSort === 'newest') ? 'checked' : ''; ?> onchange="this.form.submit();">
Neueste Beiträge
</label>
<label class="cat-filter-option">
<input type="radio" name="sort" value="oldest" <?php echo ($currentSort === 'oldest') ? 'checked' : ''; ?> onchange="this.form.submit();">
Älteste Beiträge
</label>
</div> </div>
<?php endforeach; ?> </div>
<?php </aside>
else: ?>
<p> Es sind noch keine Beiträge in dieser Kategorie enthalten.</p>
<?php endif; ?>
</div>
</main> <!-- RECHTE SPALTE: INHALT & PAGINATOR -->
<main class="cat-view-main">
<div class="cat-view-header">
<h1 class="cat-view-title">Kategorie: <?php echo (isset($category) && !empty($category)) ? htmlspecialchars($category) : 'Unbekannt'; ?></h1>
<p class="cat-view-meta-text">
<?php echo (isset($totalArticles)) ? $totalArticles : 0; ?> Treffer in dieser Kategorie
</p>
</div>
<!-- Beiträge -->
<div class="cat-view-list">
<?php if (isset($articles) && !empty($articles)): ?>
<?php foreach ($articles as $article): ?>
<div class="cat-view-item">
<div class="cat-view-content">
<h2 class="cat-view-item-title">
<a href="index.php?pfad=showArticle&id=<?php echo htmlspecialchars($article->getID()); ?>" class="cat-view-link">
<?php echo (isset($article) && !empty($article->getTitle())) ? htmlspecialchars($article->getTitle()) : 'Kein Titel'; ?>
</a>
</h2>
<div class="cat-view-meta-row">
<p class="cat-view-author">
von <span class="cat-view-author-name"><?php echo (isset($article) && !empty($article->getAuthor())) ? htmlspecialchars($article->getAuthor()) : 'Anonym'; ?></span>
</p>
<span class="cat-view-likes">
❤️ <?php echo (isset($article) && !empty($article->getLikes())) ? htmlspecialchars($article->getLikes()) : '0'; ?>
</span>
</div>
</div>
<div class="cat-view-arrow">&rarr;</div>
</div>
<?php endforeach; ?>
<?php else: ?>
<p class="cat-view-meta-text">Keine Artikel in dieser Kategorie gefunden.</p>
<?php endif; ?>
</div>
<!-- Footer Paginator -->
<?php if (isset($totalPages) && $totalPages > 1): ?>
<div class="cat-view-pagination-footer">
<div></div>
<div class="s-res-page-navigation">
<button type="button" class="s-res-page-btn" data-page="<?php echo $currentPage - 1; ?>" <?php echo ($currentPage <= 1) ? 'disabled' : ''; ?>>
&laquo;
</button>
<?php for ($i = 1; $i <= $totalPages; $i++): ?>
<button type="button"
class="s-res-page-btn <?php echo ($i === $currentPage) ? 'cat-active-btn' : ''; ?>"
data-page="<?php echo $i; ?>"
<?php echo ($i === $currentPage) ? 'disabled' : ''; ?>>
<?php echo $i; ?>
</button>
<?php endfor; ?>
<button type="button" class="s-res-page-btn" data-page="<?php echo $currentPage + 1; ?>" <?php echo ($currentPage >= $totalPages) ? 'disabled' : ''; ?>>
&raquo;
</button>
</div>
</div>
<?php endif; ?>
</main>
</div>
</form>
+227
View File
@@ -0,0 +1,227 @@
/* --- ZWEISPALTIIGES GRID-LAYOUT --- */
.cat-view-container {
box-sizing: border-box;
max-width: 95%; /* 95% Monitorbreite wie das Original */
width: 95%;
margin: 2rem auto;
padding: 0 1rem;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
color: #212529;
line-height: 1.5;
/* Grid für die Zweispaltigkeit */
display: grid;
grid-template-columns: 320px 1fr; /* 320px Sidebar, Rest für Content */
gap: 2.5rem;
}
.cat-view-container * {
box-sizing: border-box;
}
/* --- SEITENLEISTE (SORTIERUNG) --- */
.cat-sidebar {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.cat-sidebar-box {
background-color: #ffffff;
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 1.25rem;
}
.cat-sidebar-title {
font-size: 1rem;
font-weight: 700;
color: #1a202c;
margin: 0 0 1rem 0;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.cat-filter-group {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.cat-filter-option {
display: flex;
align-items: center;
gap: 0.5rem;
cursor: pointer;
font-size: 0.95rem;
color: #4a5568;
}
.cat-filter-option input[type="radio"] {
margin: 0;
accent-color: #3182ce;
}
/* --- HAUPTINHALT --- */
.cat-view-main {
min-width: 0;
}
.cat-view-header {
margin-bottom: 2rem;
border-bottom: 2px solid #dee2e6;
padding-bottom: 1rem;
}
.cat-view-title {
font-size: 2rem;
color: #1a202c;
margin: 0 0 0.5rem 0;
font-weight: 700;
}
.cat-view-meta-text {
color: #6c757d;
font-size: 0.95rem;
margin: 0;
}
/* --- BEITRÄGE LISTE --- */
.cat-view-list {
display: flex;
flex-direction: column;
gap: 1rem;
}
.cat-view-item {
background-color: #ffffff;
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 1.25rem;
display: flex;
justify-content: space-between;
align-items: center;
transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}
.cat-view-item:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
border-color: #cbd5e1;
}
.cat-view-content {
flex: 1;
}
.cat-view-item-title {
font-size: 1.25rem;
margin: 0 0 0.25rem 0;
font-weight: 600;
}
.cat-view-link {
color: #3182ce;
text-decoration: none;
}
.cat-view-link:hover {
text-decoration: underline;
color: #2b6cb0;
}
.cat-view-meta-row {
display: flex;
gap: 15px;
align-items: center;
margin-bottom: 0.5rem;
}
.cat-view-author {
font-size: 0.875rem;
color: #4a5568;
margin: 0;
}
.cat-view-author-name {
font-weight: 600;
color: #2d3748;
}
.cat-view-likes {
font-size: 0.9em;
color: #475569;
}
.cat-view-arrow {
font-size: 1.5rem;
color: #a0aec0;
padding-left: 1rem;
transition: color 0.2s ease, transform 0.2s ease;
}
.cat-view-item:hover .cat-view-arrow {
color: #3182ce;
transform: translateX(3px);
}
/* --- FOOTER PAGINATION --- */
.cat-view-pagination-footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 2rem;
padding-top: 1.5rem;
border-top: 1px solid #e2e8f0;
}
.cat-view-pagination-footer .s-res-page-navigation {
display: flex;
gap: 0.25rem;
}
.cat-view-pagination-footer .s-res-page-btn {
background-color: #ffffff;
border: 1px solid #cbd5e1;
color: #4a5568;
padding: 0.35rem 0.75rem;
font-size: 0.9rem;
font-weight: 500;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s ease;
}
.cat-view-pagination-footer .s-res-page-btn:hover:not(:disabled) {
background-color: #f8f9fa;
border-color: #cbd5e1;
color: #2d3748;
}
.cat-view-pagination-footer .cat-active-btn {
background-color: #3182ce;
border-color: #3182ce;
color: #ffffff;
cursor: default;
}
.cat-view-pagination-footer .s-res-page-btn:disabled:not(.cat-active-btn) {
background-color: #f1f5f9;
border-color: #e2e8f0;
color: #94a3b8;
cursor: not-allowed;
}
/* RESPONSIVE ANPASSUNG (Unter 768px) */
@media (max-width: 768px) {
.cat-view-container {
grid-template-columns: 1fr; /* Stapelt Sidebar und Inhalt untereinander */
gap: 1.5rem;
margin: 1rem auto;
}
.cat-view-pagination-footer {
flex-direction: column;
gap: 1rem;
align-items: flex-start;
}
}
+1
View File
@@ -63,6 +63,7 @@ if ($pfad === "deleteAccount") {
<link rel="stylesheet" href="css/profile.css"> <link rel="stylesheet" href="css/profile.css">
<link rel="stylesheet" href="css/showArticle.css"> <link rel="stylesheet" href="css/showArticle.css">
<link rel="stylesheet" href="css/message.css"> <link rel="stylesheet" href="css/message.css">
<link rel="stylesheet" href="css/showCategory.css">
<script src="js/paginator.js" async></script> <script src="js/paginator.js" async></script>
<script src="js/sorter.js" async></script> <script src="js/sorter.js" async></script>
+3 -3
View File
@@ -1,13 +1,13 @@
console.log("Die JavaScript-Datei wurde erfolgreich geladen!"); console.log("editor.js wurde erfolgreich geladen!");
function initEditor() { function initEditor() {
const form = document.getElementById("editor-form"); const form = document.getElementById("editor-form");
if (!form) { if (!form) {
console.error("Skript abgebrochen: Formular nicht gefunden!"); console.error("editor.js wurde abgebrochen: Formular nicht gefunden!");
return; return;
} else { } else {
console.log("Formular gefunden und Editor initialisiert:", form); console.log("Formular gefunden und editor.js initialisiert:", form);
} }
const container = document.getElementById("block-container"); const container = document.getElementById("block-container");
+224 -22
View File
@@ -1,27 +1,229 @@
function initPaginator() { console.log("editor.js wurde erfolgreich geladen!");
const form = document.getElementById('search-form-id'); (function () {
const pageInput = document.getElementById('s-res-page-input'); 'use strict';
const pageButtons = document.querySelectorAll('.s-res-page-navigation .s-res-page-btn');
pageButtons.forEach(button => { const state = {
button.addEventListener('click', function() { items: [],
if (this.disabled) return; 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) { function applyFilterAndSort() {
pageInput.value = targetPage; let list = state.items.slice();
form.submit();
} 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? function renderMeta() {
if (document.readyState === 'loading') { const metaEl = document.querySelector('.s-res-meta');
// Falls noch geladen wird, auf das Event warten const queryInput = document.getElementById('site-search');
document.addEventListener('DOMContentLoaded', initPaginator); if (metaEl) {
} else { const q = queryInput ? queryInput.value : '';
// Falls das HTML bereits komplett da ist, sofort ausführen metaEl.textContent = state.sorted.length + ' Treffer für Ihre Suchanfrage "' + q + '"';
initPaginator(); }
} }
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();
}
})();
+13 -42
View File
@@ -2,8 +2,8 @@
if (session_status() === PHP_SESSION_NONE) { if (session_status() === PHP_SESSION_NONE) {
session_start(); session_start();
} }
require_once '../model/LocalArticleManager.php';
require_once '../model/ArticleManager.php'; require_once '../model/ArticleManager.php';
require_once '../model/UserManager.php';
require_once '../model/Article.php'; require_once '../model/Article.php';
require_once '../validator/search-validator.php'; require_once '../validator/search-validator.php';
@@ -16,68 +16,39 @@ if ($_SERVER["REQUEST_METHOD"] === "GET" && isset($_GET["q"])) {
$_SESSION["message"] = "invalid_search_query"; $_SESSION["message"] = "invalid_search_query";
} else { } else {
try { try {
$articleManager = ArticleManager::getInstance(); $articleManager = ArticleManager::getInstance();
$userManager = UserManager::getInstance();
$results = $articleManager->search($search); $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 = []; $safeArrayResults = [];
foreach ($results as $obj) { foreach ($results as $obj) {
$safeArrayResults[] = [ $safeArrayResults[] = [
"id" => $obj->getId(), "id" => $obj->getId(),
"title" => $obj->getTitle(), "title" => $obj->getTitle(),
"content" => $obj->getContent(), "content" => $obj->getContent(),
"author" => $obj->getAuthor(), "author" => $userManager->findUser($obj->getAuthor())["vorname"] . " " . $userManager->findUser($obj->getAuthor())["nachname"],
"category" => $obj->getCategory(), "category" => $obj->getCategory(),
"tags" => $obj->getTags(), "tags" => $obj->getTags(),
"creationDate" => $obj->getCreationDate(), "creationDate" => $obj->getCreationDate(),
"likes" => $obj->getLikes(), "likes" => $obj->getLikes(),
]; ];
} }
$_SESSION["search_results"] = $safeArrayResults; $_SESSION["search_results"] = $safeArrayResults;
$_SESSION["search_query"] = $search; $_SESSION["search_query"] = $search;
$_SESSION["message"] = "new_search_results"; $_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"; $_SESSION["message"] = "internal_error";
} }
} }
$sort = $_GET['sort'] ?? 'alphabet'; header("Location: ../../index.php?pfad=search-results&q=" . urlencode($search));
$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);
exit(); exit();
}
}
?>
+12
View File
@@ -5,6 +5,7 @@ if (session_status() === PHP_SESSION_NONE) {
require_once 'php/model/Article.php'; require_once 'php/model/Article.php';
require_once 'php/model/ArticleManager.php'; require_once 'php/model/ArticleManager.php';
require_once 'php/model/UserManager.php';
require_once 'php/model/CommentManager.php'; require_once 'php/model/CommentManager.php';
if (isset($_GET["id"]) && !empty($_GET["id"])){ if (isset($_GET["id"]) && !empty($_GET["id"])){
@@ -19,12 +20,23 @@ if (isset($_GET["id"]) && !empty($_GET["id"])){
$author = $article->getAuthor(); $author = $article->getAuthor();
$tags = $article->getTags(); $tags = $article->getTags();
$articleObj = $article; // Objekt für die Like-Abfagen sichern $articleObj = $article; // Objekt für die Like-Abfagen sichern
$userManager = UserManager::getInstance();
$name = $userManager->findUser($author)["vorname"]." ".$userManager->findUser($author)["nachname"];
}else{ }else{
//header("location: index.php?pfad=404"); //header("location: index.php?pfad=404");
include_once "content/404.php"; include_once "content/404.php";
exit(); exit();
} }
if($_GET["pfad"] == "updateArticle"){
if($article->getAuthor() != $_SESSION["user_email"]){
$_SESSION["message"] = "unauthorized_access";
header("location: index.php");
exit();
}
}
$commentManager = CommentManager::getInstance(); $commentManager = CommentManager::getInstance();
$comments = $commentManager->getCommentsByArticle($_GET["id"]); $comments = $commentManager->getCommentsByArticle($_GET["id"]);
+48 -2
View File
@@ -1,19 +1,65 @@
<?php <?php
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
require_once 'php/model/Article.php'; require_once 'php/model/Article.php';
require_once 'php/model/ArticleManager.php'; require_once 'php/model/ArticleManager.php';
require_once 'php/model/UserManager.php';
require_once 'php/validator/article-validator.php'; require_once 'php/validator/article-validator.php';
if (isset($_GET["category"]) && !empty($_GET["category"]) && articleCategoryValidator($_GET["category"])){ if (isset($_GET["category"]) && !empty($_GET["category"]) && articleCategoryValidator($_GET["category"])){
$category = $_GET["category"]; $category = $_GET["category"];
// Sortierung auslesen (Standard: alphabet)
$sortStyle = isset($_GET['sort']) ? trim($_GET['sort']) : 'alphabet';
// Aktuelle Seite auslesen
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
if ($page < 1) { $page = 1; }
try { try {
$articleManager = ArticleManager::getInstance(); $articleManager = ArticleManager::getInstance();
$articles = $articleManager->getArticlesByCategory($category); $userManager = UserManager::getInstance();
$allArticles = $articleManager->getArticlesByCategory($category);
foreach ($allArticles as $article) {
$article->setAuthor($userManager->findUser($article->getAuthor())["vorname"] . " " . $userManager->findUser($article->getAuthor())["nachname"]);
}
$totalArticles = count($allArticles);
// --- SORTIERUNG LOGIK ---
if ($sortStyle === 'alphabet') {
usort($allArticles, function($a, $b) {
return strcasecmp($a->getTitle(), $b->getTitle());
});
} elseif ($sortStyle === 'likes') {
usort($allArticles, function($a, $b) {
return $b->getLikes() <=> $a->getLikes(); // Absteigend nach Likes
});
} elseif ($sortStyle === 'newest') {
usort($allArticles, function($a, $b) {
return strtotime($b->getCreationDate()) <=> strtotime($a->getCreationDate()); // Neueste zuerst
});
} elseif ($sortStyle === 'oldest') {
usort($allArticles, function($a, $b) {
return strtotime($a->getCreationDate()) <=> strtotime($b->getCreationDate()); // Älteste zuerst
});
}
// Paginierung konfigurieren
$limit = 10;
$totalPages = ceil($totalArticles / $limit);
if ($page > $totalPages && $totalPages > 0) { $page = $totalPages; }
$offset = ($page - 1) * $limit;
$articles = array_slice($allArticles, $offset, $limit);
} catch (Exception $e) { } catch (Exception $e) {
$_SESSION["message"] = "internal_error"; $_SESSION["message"] = "internal_error";
include_once "content/404.php"; include_once "content/404.php";
exit(); exit();
} }
}else{ } else {
$_SESSION["message"] = "invalid_category"; $_SESSION["message"] = "invalid_category";
include_once "content/404.php"; include_once "content/404.php";
exit(); exit();
+10
View File
@@ -97,6 +97,16 @@ class Article
return $this->author; return $this->author;
} }
/**
* Setzt einen neuen Autor eines Beitrages.
* @param string $author
* @return void
*/
public function setAuthor(string $author)
{
$this->author = $author;
}
/** /**
* Gibt das Veröffentlichungsdatum des Beitrags zurück. * Gibt das Veröffentlichungsdatum des Beitrags zurück.
* @return string * @return string