Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c117c7e641 | |||
| 01fc8537cf | |||
| 12ad9759cf | |||
| 057639be7c | |||
| 87e7be1c10 | |||
| 1db77346d0 | |||
| 1e6ac0fcd9 | |||
| b3c74c2172 | |||
| 0805958033 | |||
| 5c0e978c93 | |||
| 520298bae4 | |||
| 969adc4836 | |||
| d9eca06197 | |||
| 48f2e90e49 | |||
| 358247a2a1 | |||
| de4d2fe5c0 | |||
| e1102eb7db | |||
| a8df9590fd | |||
| 3e453e22ec | |||
| beeab0ec90 | |||
| 9353a7eaaa | |||
| cac8f3046d | |||
| 66eeac372c |
+51
-28
@@ -27,7 +27,8 @@ if ($currentPage < 1) {
|
||||
$offset = ($currentPage - 1) * $limit;
|
||||
|
||||
// Nur die Ergebnisse für die aktuelle Seite ausschneiden
|
||||
$results = array_slice($all_results, $offset, $limit);
|
||||
//$results = array_slice($all_results, $offset, $limit);
|
||||
$results = $all_results;
|
||||
$resultCount = count($results);
|
||||
|
||||
?>
|
||||
@@ -44,12 +45,11 @@ $resultCount = count($results);
|
||||
<!-- Links: Seitenleiste für Filter und Suche -->
|
||||
<aside class="s-res-sidebar">
|
||||
|
||||
<!-- Sortierfuntion Box und Such Box-->
|
||||
<form id="search-form-id" action="php/controller/search-results-controller.php" method="GET" class="s-res-sidebar-form">
|
||||
<!-- Dieses Feld hält die aktuelle Seitenzahl für den Submit bereit -->
|
||||
<input type="hidden" name="page" id="s-res-page-input" value="<?php echo $currentPage; ?>">
|
||||
<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; ?>">
|
||||
|
||||
<div class="s-res-sidebar-box">
|
||||
<div class="s-res-sidebar-box">
|
||||
<h3 class="s-res-sidebar-title">Suche anpassen</h3>
|
||||
<input type="search" id="site-search" name="q" placeholder="Suchen..." class="nav__search" value="<?php echo htmlspecialchars($query); ?>" maxlength="50" required>
|
||||
<button type="submit" class="nav__search-button">Suchen</button>
|
||||
@@ -60,25 +60,57 @@ $resultCount = count($results);
|
||||
<?php $currentSort = $_SESSION['search_sort'] ?? 'alphabet'; ?>
|
||||
<div class="s-res-filter-group">
|
||||
<label class="s-res-filter-option">
|
||||
<input type="radio" name="sort" value="alphabet" <?php echo $currentSort === 'alphabet' ? 'checked' : ''; ?> onchange="this.form.submit()">
|
||||
<input type="radio" name="sort" value="alphabet" class="sort-radio" <?php echo $currentSort === 'alphabet' ? 'checked' : ''; ?>>
|
||||
<span>Alphabetisch</span>
|
||||
</label>
|
||||
<!-- Noch disabled, da likes noch nicht implementiert-->
|
||||
<label class="s-res-filter-option">
|
||||
<input type="radio" name="sort" value="likes" <?php echo $currentSort === 'likes' ? 'checked' : ''; ?> onchange="this.form.submit()">
|
||||
<span>Beliebtheit (Likes)</span>
|
||||
</label>
|
||||
<label class="s-res-filter-option">
|
||||
<input type="radio" name="sort" value="newest" <?php echo $currentSort === 'newest' ? 'checked' : ''; ?> onchange="this.form.submit()">
|
||||
<input type="radio" name="sort" value="newest" class="sort-radio" <?php echo $currentSort === 'newest' ? 'checked' : ''; ?>>
|
||||
<span>Neueste Beiträge</span>
|
||||
</label>
|
||||
<label class="s-res-filter-option">
|
||||
<input type="radio" name="sort" value="oldest" <?php echo $currentSort === 'oldest' ? 'checked' : ''; ?> onchange="this.form.submit()">
|
||||
<input type="radio" name="sort" value="oldest" class="sort-radio" <?php echo $currentSort === 'oldest' ? 'checked' : ''; ?>>
|
||||
<span>Älteste Beiträge</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="s-res-sidebar-box">
|
||||
<h3 class="s-res-sidebar-title">Kategorie filtern</h3>
|
||||
<select id="category-filter" class="s-res-limit-select" style="width: 100%; padding: 8px; border-radius: 6px; border: 1px solid #cbd5e1;">
|
||||
<option value="all">Alle Kategorien</option>
|
||||
<option value="Deutsch">Deutsch</option>
|
||||
<option value="Englisch">Englisch</option>
|
||||
<option value="Franzoesisch">Französisch</option>
|
||||
<option value="Latein">Latein</option>
|
||||
<option value="Literatur">Literatur</option>
|
||||
<option value="Mathematik">Mathematik</option>
|
||||
<option value="Biologie">Biologie</option>
|
||||
<option value="Informatik">Informatik</option>
|
||||
<option value="Chemie">Chemie</option>
|
||||
<option value="Physik">Physik</option>
|
||||
<option value="Astronomie">Astronomie</option>
|
||||
<option value="Geschichte">Geschichte</option>
|
||||
<option value="Erdkunde">Erdkunde</option>
|
||||
<option value="Sozialkunde">Sozialkunde</option>
|
||||
<option value="Wirtschaftskunde">Wirtschaftskunde</option>
|
||||
<option value="Religion">Religion</option>
|
||||
<option value="Ethikunterricht">Ethikunterricht</option>
|
||||
<option value="Philosophie">Philosophie</option>
|
||||
<option value="Psychologie">Psychologie</option>
|
||||
<option value="Kunst">Kunst</option>
|
||||
<option value="Musik">Musik</option>
|
||||
<option value="Theater">Theater</option>
|
||||
<option value="Technik">Technik</option>
|
||||
<option value="Werken">Werken</option>
|
||||
<option value="Hauswirtschaft">Hauswirtschaft</option>
|
||||
<option value="Sport">Sport</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</aside>
|
||||
@@ -96,7 +128,7 @@ $resultCount = count($results);
|
||||
if (!empty($results)): ?>
|
||||
|
||||
<?php foreach ($results as $item): ?>
|
||||
<div class="s-res-item">
|
||||
<div class="s-res-item" data-likes="<?php echo $item['likes'] ?? 0; ?>" data-category="<?php echo strtolower($item['category'] ?? ''); ?>">
|
||||
<div class="s-res-content">
|
||||
<h2 class="s-res-item-title">
|
||||
<a href="index.php?pfad=showArticle&id=<?php echo $item['id']; ?>" class="s-res-link">
|
||||
@@ -120,8 +152,8 @@ $resultCount = count($results);
|
||||
elseif (isset($_SESSION["search_query"]) && $_SESSION["search_query"] !== "" && $resultCount === 0): ?>
|
||||
<p>Keine Beiträge zu diesem Suchbegriff gefunden.</p>
|
||||
<?php
|
||||
elseif (isset($_SESSION["message"]) && $_SESSION["message"] == "missing_parameters"): ?>
|
||||
<p>Bitte überprüfe deine Sucheingabe und versuche es erneut!</p>
|
||||
elseif (isset($_SESSION["message"]) && $_SESSION["message"] == "invalid_search_query"): ?>
|
||||
<p>Unzulässige Suchanfrage</p>
|
||||
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
@@ -143,23 +175,14 @@ $resultCount = count($results);
|
||||
</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' : ''; ?>>
|
||||
«
|
||||
</button>
|
||||
<!-- Dynamische Seitenzahlen -->
|
||||
<?php for ($i = 1; $i <= $totalPages; $i++): ?>
|
||||
<button type="button"
|
||||
class="s-res-page-btn <?php echo $i === $currentPage ? 's-res-page-btn-active' : ''; ?>"
|
||||
data-page="<?php echo $i; ?>">
|
||||
<?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' : ''; ?>>
|
||||
»
|
||||
</button>
|
||||
<button type="button" class="s-res-page-btn" id="prev-page-btn" data-page="0">«</button>
|
||||
|
||||
<span id="dynamic-page-numbers"></span>
|
||||
|
||||
<button type="button" class="s-res-page-btn" id="next-page-btn" data-page="2">»</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -53,8 +53,10 @@ if ($pfad === "deleteAccount") {
|
||||
<link rel="stylesheet" href="css/message.css">
|
||||
|
||||
<script src="js/paginator.js" async></script>
|
||||
<script src="js/sorter.js" async></script>
|
||||
<script src="js/comments.js" defer></script>
|
||||
<script src="js/editor.js" async></script>
|
||||
<script src="js/filter.js" async></script>
|
||||
|
||||
<title>EduForge</title>
|
||||
</head>
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
let currentClientPage = 1;
|
||||
const itemsPerPage = 10;
|
||||
|
||||
function initFilter() {
|
||||
const filterSelect = document.getElementById('category-filter');
|
||||
const listContainer = document.querySelector('.s-res-list');
|
||||
|
||||
if (!filterSelect || !listContainer) return;
|
||||
|
||||
updateVisibility();
|
||||
|
||||
filterSelect.addEventListener('change', function() {
|
||||
currentClientPage = 1;
|
||||
updateVisibility();
|
||||
});
|
||||
|
||||
const navigationContainer = document.querySelector('.s-res-page-navigation');
|
||||
if (navigationContainer) {
|
||||
navigationContainer.addEventListener('click', function(e) {
|
||||
const button = e.target.closest('.s-res-page-btn');
|
||||
if (!button || button.disabled) return;
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
const targetPage = button.getAttribute('data-page');
|
||||
if (targetPage) {
|
||||
currentClientPage = parseInt(targetPage, 10);
|
||||
updateVisibility();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function updateVisibility() {
|
||||
const filterSelect = document.getElementById('category-filter');
|
||||
const listContainer = document.querySelector('.s-res-list');
|
||||
const selectedCategory = filterSelect.value.toLowerCase().trim();
|
||||
const cards = listContainer.querySelectorAll('.s-res-item');
|
||||
|
||||
let visibleCards = [];
|
||||
cards.forEach(card => {
|
||||
const cardCategory = (card.getAttribute('data-category') || '').toLowerCase().trim();
|
||||
if (selectedCategory === 'all' || cardCategory.includes(selectedCategory) || selectedCategory.includes(cardCategory)) {
|
||||
visibleCards.push(card);
|
||||
} else {
|
||||
card.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
const totalVisible = visibleCards.length;
|
||||
const totalPages = Math.max(1, Math.ceil(totalVisible / itemsPerPage));
|
||||
|
||||
if (currentClientPage < 1) currentClientPage = 1;
|
||||
if (currentClientPage > totalPages) currentClientPage = totalPages;
|
||||
|
||||
const startOffset = (currentClientPage - 1) * itemsPerPage;
|
||||
const endOffset = startOffset + itemsPerPage;
|
||||
|
||||
visibleCards.forEach((card, index) => {
|
||||
if (index >= startOffset && index < endOffset) {
|
||||
card.style.display = 'flex';
|
||||
} else {
|
||||
card.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
updatePaginatorUI(currentClientPage, totalPages);
|
||||
}
|
||||
|
||||
function updatePaginatorUI(currentPage, totalPages) {
|
||||
const prevBtn = document.getElementById('prev-page-btn');
|
||||
const nextBtn = document.getElementById('next-page-btn');
|
||||
const numbersContainer = document.getElementById('dynamic-page-numbers');
|
||||
|
||||
if (!prevBtn || !nextBtn || !numbersContainer) return;
|
||||
|
||||
prevBtn.setAttribute('data-page', currentPage - 1);
|
||||
prevBtn.disabled = (currentPage <= 1);
|
||||
|
||||
nextBtn.setAttribute('data-page', currentPage + 1);
|
||||
nextBtn.disabled = (currentPage >= totalPages);
|
||||
|
||||
let buttonsHTML = '';
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
const activeClass = (i === currentPage) ? 's-res-page-btn-active' : '';
|
||||
buttonsHTML += `<button type="button" class="s-res-page-btn ${activeClass}" data-page="${i}">${i}</button> `;
|
||||
}
|
||||
numbersContainer.innerHTML = buttonsHTML;
|
||||
}
|
||||
|
||||
// Hilfsfunktion für Math.ceil in JS
|
||||
function ceil(val) { return Math.ceil(val); }
|
||||
|
||||
// ist das DOM bereits vollständig aufgebaut?
|
||||
if (document.readyState === 'loading') {
|
||||
// Falls noch geladen wird, auf das Event warten
|
||||
document.addEventListener('DOMContentLoaded', initFilter);
|
||||
} else {
|
||||
// Falls das HTML bereits komplett da ist, sofort ausführen
|
||||
initFilter();
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
function initSorter() {
|
||||
const listContainer = document.querySelector('.s-res-list');
|
||||
const sortRadios = document.querySelectorAll('.sort-radio');
|
||||
|
||||
// wenn keine liste vorhanden, abbrechen
|
||||
if (!listContainer || sortRadios.length === 0) return;
|
||||
|
||||
sortRadios.forEach(radio => {
|
||||
radio.addEventListener('change', function() {
|
||||
const cards = Array.from(listContainer.querySelectorAll('.s-res-item'));
|
||||
const sortValue = this.value;
|
||||
|
||||
cards.sort((a, b) => {
|
||||
if (sortValue === 'likes') {
|
||||
const likesA = parseInt(a.getAttribute('data-likes') || '0', 10);
|
||||
const likesB = parseInt(b.getAttribute('data-likes') || '0', 10);
|
||||
return likesB - likesA;
|
||||
}
|
||||
else if (sortValue === 'alphabet') {
|
||||
// alphabetische sortierung
|
||||
const titleA = a.querySelector('.s-res-link').textContent.trim().toLowerCase();
|
||||
const titleB = b.querySelector('.s-res-link').textContent.trim().toLowerCase();
|
||||
return titleA.localeCompare(titleB);
|
||||
}
|
||||
else if (sortValue === 'newest' || sortValue === 'oldest') {
|
||||
// hoehere ID wird als neuer gesehen
|
||||
const urlA = a.querySelector('.s-res-link').getAttribute('href');
|
||||
const urlB = b.querySelector('.s-res-link').getAttribute('href');
|
||||
|
||||
const idA = parseInt(urlA.match(/id=(\d+)/)[1], 10);
|
||||
const idB = parseInt(urlB.match(/id=(\d+)/)[1], 10);
|
||||
|
||||
return sortValue === 'newest' ? idB - idA : idA - idB;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
listContainer.innerHTML = '';
|
||||
cards.forEach(card => listContainer.appendChild(card));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ist das DOM bereits vollständig aufgebaut?
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initSorter);
|
||||
} else {
|
||||
initSorter();
|
||||
}
|
||||
@@ -5,14 +5,15 @@ if (session_status() === PHP_SESSION_NONE) {
|
||||
require_once '../model/LocalArticleManager.php';
|
||||
require_once '../model/ArticleManager.php';
|
||||
require_once '../model/Article.php';
|
||||
require_once '../validator/search-validator.php';
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] === "GET" && isset($_GET["q"])) {
|
||||
|
||||
$search = trim($_GET["q"]);
|
||||
if (empty($search)) {
|
||||
if (!searchQueryValidator($search)) {
|
||||
$_SESSION["search_results"] = [];
|
||||
$_SESSION["search_query"] = "";
|
||||
$_SESSION["message"] = "missing_parameters";
|
||||
$_SESSION["message"] = "invalid_search_query";
|
||||
} else {
|
||||
try {
|
||||
|
||||
@@ -70,6 +71,9 @@ if ($_SERVER["REQUEST_METHOD"] === "GET" && isset($_GET["q"])) {
|
||||
|
||||
$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);
|
||||
exit();
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Prüft, ob eine Suchanfrage gültig ist.
|
||||
*
|
||||
* Erlaubt werden Buchstaben, Zahlen, Umlaute, typische Satzzeichen und Leerzeichen.
|
||||
* Die Länge muss zwischen 1 und 50 Zeichen liegen.
|
||||
*
|
||||
* @param string $query Zu prüfender Suchbegriff
|
||||
*
|
||||
* @return bool true wenn die Suche gültig ist, sonst false
|
||||
*/
|
||||
function searchQueryValidator($query)
|
||||
{
|
||||
$query = trim($query);
|
||||
|
||||
// Mindestens 1 Zeichen, maximal 50 Zeichen
|
||||
$length = mb_strlen($query);
|
||||
if ($length < 1 || $length > 50) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Erlaubt Buchstaben (inkl. Umlaut/ß), Zahlen, Leerzeichen sowie ?, !, ., -, _
|
||||
$searchPattern = '/^[a-zA-Z0-9äöüÄÖÜß\s?!.,\-_]+$/u';
|
||||
|
||||
return preg_match($searchPattern, $query) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft, ob das gewählte Treffer-Limit erlaubt ist.
|
||||
*
|
||||
* @param int|string $limit Das zu prüfende Limit
|
||||
*
|
||||
* @return bool true wenn das Limit 10, 20, 50 oder 100 ist, sonst false
|
||||
*/
|
||||
function searchLimitValidator($limit)
|
||||
{
|
||||
$allowedLimits = [10, 20, 50, 100];
|
||||
return in_array((int)$limit, $allowedLimits, true);
|
||||
}
|
||||
Reference in New Issue
Block a user