bug fixes
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
|
||||
input[type="text"] {
|
||||
padding: 10px; font-size: 16px; width: 250px;
|
||||
background: #333; border: 1px solid #666; color: white;
|
||||
background: #333; border: 1px solid #666; color: white; outline: none;
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
@@ -22,14 +22,15 @@
|
||||
}
|
||||
.tab-btn.active { background: #4caf50; color: white; }
|
||||
.tab-btn#tab-public.active { background: #2196F3; } /* Blau für Public */
|
||||
.tab-btn#tab-badwords.active { background: #f44336; } /* Rot für Badwords */
|
||||
|
||||
/* Liste */
|
||||
/* Normale Liste */
|
||||
.entry {
|
||||
background: #333; padding: 15px; margin-bottom: 8px;
|
||||
display: flex; justify-content: space-between; align-items: center;
|
||||
border-left: 5px solid #555;
|
||||
}
|
||||
.entry.highlight { border-left-color: #ffeb3b; background: #444; } /* Suchtreffer */
|
||||
.entry.highlight { border-left-color: #ffeb3b; background: #444; }
|
||||
|
||||
.info { font-size: 1.1em; }
|
||||
.meta { font-size: 0.85em; color: #aaa; margin-top: 4px; font-family: monospace; }
|
||||
@@ -37,10 +38,42 @@
|
||||
|
||||
/* Buttons */
|
||||
button { cursor: pointer; padding: 8px 15px; border: none; font-weight: bold; color: white; border-radius: 4px; }
|
||||
.btn-approve { background: #4caf50; margin-right: 5px; }
|
||||
.btn-delete { background: #f44336; }
|
||||
.btn-delete:hover { background: #d32f2f; }
|
||||
|
||||
/* BADWORD STYLES (Tags) */
|
||||
#badword-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
padding: 20px;
|
||||
background: #333;
|
||||
border: 1px solid #555;
|
||||
}
|
||||
|
||||
.badword-tag {
|
||||
background: #222;
|
||||
padding: 8px 15px;
|
||||
border-radius: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
border: 1px solid #f44336;
|
||||
color: #ff8a80;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.badword-remove {
|
||||
cursor: pointer;
|
||||
color: #f44336;
|
||||
font-weight: bold;
|
||||
background: rgba(255,255,255,0.1);
|
||||
width: 20px; height: 20px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.badword-remove:hover { background: #f44336; color: white; }
|
||||
|
||||
.empty { text-align: center; padding: 40px; color: #666; font-style: italic; }
|
||||
</style>
|
||||
</head>
|
||||
@@ -52,28 +85,43 @@
|
||||
</div>
|
||||
|
||||
<div class="tabs">
|
||||
<button id="tab-unverified" class="tab-btn active" onclick="switchTab('unverified')">⏳ Warteschlange (Prüfen)</button>
|
||||
<button id="tab-public" class="tab-btn" onclick="switchTab('public')">🏆 Bestenliste (Fertig)</button>
|
||||
<button id="tab-public" class="tab-btn active" onclick="switchTab('public')">🏆 Bestenliste</button>
|
||||
<button id="tab-badwords" class="tab-btn" onclick="switchTab('badwords')">🤬 Badwords</button>
|
||||
</div>
|
||||
|
||||
<div id="list">Lade...</div>
|
||||
<div id="list-section">
|
||||
<div id="list">Lade...</div>
|
||||
</div>
|
||||
|
||||
<div id="badword-section" style="display:none;">
|
||||
<div style="margin-bottom: 20px; display:flex; gap:10px;">
|
||||
<input type="text" id="newBadword" placeholder="Neues Wort hinzufügen...">
|
||||
<button onclick="addBadword()" style="background:#f44336; color:white; border:none; padding:10px 20px; cursor:pointer;">+ Hinzufügen</button>
|
||||
</div>
|
||||
|
||||
<h3>Aktuelle Liste:</h3>
|
||||
<div id="badword-container">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let currentTab = 'unverified';
|
||||
let allEntries = []; // Speichert die geladenen Daten für die Suche
|
||||
let currentTab = 'public';
|
||||
let allEntries = [];
|
||||
|
||||
// Initial laden
|
||||
loadList();
|
||||
|
||||
// --- FUNKTIONEN FÜR BESTENLISTE ---
|
||||
async function loadList() {
|
||||
const listEl = document.getElementById('list');
|
||||
listEl.innerHTML = '<div style="text-align:center">Lade Daten...</div>';
|
||||
|
||||
try {
|
||||
// API Aufruf mit Typ (unverified oder public)
|
||||
const res = await fetch('/api/admin/list?type=' + currentTab);
|
||||
const res = await fetch('/api/admin/list?type=public');
|
||||
allEntries = await res.json();
|
||||
|
||||
renderList(allEntries);
|
||||
} catch(e) {
|
||||
listEl.innerHTML = '<div class="empty">Fehler beim Laden der Daten.</div>';
|
||||
listEl.innerHTML = '<div class="empty">Fehler beim Laden.</div>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,14 +135,6 @@
|
||||
|
||||
let html = "";
|
||||
data.forEach(entry => {
|
||||
// Buttons: In der "Public" Liste brauchen wir keinen "Freigeben" Button mehr
|
||||
let actions = '';
|
||||
if (currentTab === 'unverified') {
|
||||
actions += `<button class="btn-approve" onclick="decide('${entry.sessionId}', 'approve')">✔ OK</button>`;
|
||||
}
|
||||
// Löschen darf man immer (falls man sich verklickt hat oder Schüler nervt)
|
||||
actions += `<button class="btn-delete" onclick="decide('${entry.sessionId}', 'delete')">🗑 Weg</button>`;
|
||||
|
||||
html += `
|
||||
<div class="entry">
|
||||
<div class="info">
|
||||
@@ -105,65 +145,104 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
${actions}
|
||||
<button class="btn-delete" onclick="decide('${entry.sessionId}', 'delete')">🗑 Löschen</button>
|
||||
</div>
|
||||
</div>`;
|
||||
});
|
||||
listEl.innerHTML = html;
|
||||
|
||||
// Filter direkt anwenden, falls noch Text in der Suche steht
|
||||
filterList();
|
||||
}
|
||||
|
||||
// Such-Logik (Client-Side, rasend schnell)
|
||||
function filterList() {
|
||||
const term = document.getElementById('searchInput').value.toUpperCase();
|
||||
const entries = document.querySelectorAll('.entry');
|
||||
|
||||
entries.forEach(div => {
|
||||
// Wir suchen im gesamten Text des Eintrags (Name, Code, Score)
|
||||
const text = div.innerText.toUpperCase();
|
||||
if (text.includes(term)) {
|
||||
div.style.display = "flex";
|
||||
// Kleines Highlight wenn gesucht wird
|
||||
if(term.length > 0) div.classList.add("highlight");
|
||||
else div.classList.remove("highlight");
|
||||
} else {
|
||||
div.style.display = "none";
|
||||
}
|
||||
});
|
||||
filterList(); // Suche anwenden falls Text drin steht
|
||||
}
|
||||
|
||||
async function decide(sid, action) {
|
||||
if(!confirm(action === 'approve' ? "Freigeben?" : "Endgültig löschen?")) return;
|
||||
|
||||
if(!confirm("Eintrag endgültig löschen?")) return;
|
||||
await fetch('/api/admin/action', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
method: 'POST', headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({ sessionId: sid, action: action })
|
||||
});
|
||||
loadList(); // Neu laden
|
||||
}
|
||||
|
||||
function switchTab(tab) {
|
||||
currentTab = tab;
|
||||
|
||||
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
||||
document.getElementById('tab-' + tab).classList.add('active');
|
||||
|
||||
document.getElementById('searchInput').value = "";
|
||||
|
||||
loadList();
|
||||
}
|
||||
|
||||
// Start
|
||||
loadList();
|
||||
function filterList() {
|
||||
const term = document.getElementById('searchInput').value.toUpperCase();
|
||||
const entries = document.querySelectorAll('.entry');
|
||||
entries.forEach(div => {
|
||||
if (div.innerText.toUpperCase().includes(term)) {
|
||||
div.style.display = "flex";
|
||||
if(term.length > 0) div.classList.add("highlight"); else div.classList.remove("highlight");
|
||||
} else { div.style.display = "none"; }
|
||||
});
|
||||
}
|
||||
|
||||
setInterval(() => {
|
||||
if(currentTab === 'unverified' && document.getElementById('searchInput').value === "") {
|
||||
// --- FUNKTIONEN FÜR BADWORDS ---
|
||||
async function loadBadwords() {
|
||||
try {
|
||||
const res = await fetch('/api/admin/badwords');
|
||||
const words = await res.json(); // Array von Strings
|
||||
|
||||
const container = document.getElementById('badword-container');
|
||||
container.innerHTML = '';
|
||||
|
||||
if (!words || words.length === 0) {
|
||||
container.innerHTML = "<div class='empty'>Keine Badwords definiert.</div>";
|
||||
return;
|
||||
}
|
||||
|
||||
// Tags generieren
|
||||
words.forEach(w => {
|
||||
container.innerHTML += `
|
||||
<div class="badword-tag">
|
||||
${w}
|
||||
<span class="badword-remove" onclick="removeBadword('${w}')" title="Löschen">✖</span>
|
||||
</div>`;
|
||||
});
|
||||
} catch(e) {
|
||||
document.getElementById('badword-container').innerHTML = "Fehler beim Laden.";
|
||||
}
|
||||
}
|
||||
|
||||
async function addBadword() {
|
||||
const input = document.getElementById('newBadword');
|
||||
const word = input.value.trim();
|
||||
if(!word) return;
|
||||
|
||||
await fetch('/api/admin/badwords', {
|
||||
method: 'POST', headers: {'Content-Type':'application/json'},
|
||||
body: JSON.stringify({ action: 'add', word: word })
|
||||
});
|
||||
input.value = "";
|
||||
loadBadwords();
|
||||
}
|
||||
|
||||
async function removeBadword(word) {
|
||||
if(!confirm(`Das Wort "${word}" von der Liste entfernen?`)) return;
|
||||
await fetch('/api/admin/badwords', {
|
||||
method: 'POST', headers: {'Content-Type':'application/json'},
|
||||
body: JSON.stringify({ action: 'remove', word: word })
|
||||
});
|
||||
loadBadwords();
|
||||
}
|
||||
|
||||
// --- TAB UMSCHALTEN ---
|
||||
function switchTab(tab) {
|
||||
currentTab = tab;
|
||||
|
||||
// Buttons stylen
|
||||
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
||||
document.getElementById('tab-' + tab).classList.add('active');
|
||||
|
||||
// Ansicht wechseln
|
||||
if (tab === 'badwords') {
|
||||
document.getElementById('list-section').style.display = 'none';
|
||||
document.getElementById('badword-section').style.display = 'block';
|
||||
document.getElementById('searchInput').style.display = 'none';
|
||||
loadBadwords();
|
||||
} else {
|
||||
document.getElementById('list-section').style.display = 'block';
|
||||
document.getElementById('badword-section').style.display = 'none';
|
||||
document.getElementById('searchInput').style.display = 'block';
|
||||
loadList();
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user