+
-
-
| Zeitstempel | User | Aktion | Ziel |
|---|
+
+
| Zeitstempel | User | Aktion | Ziel |
|---|
@@ -214,17 +246,25 @@
document.addEventListener('DOMContentLoaded', checkSession);
function checkSession() {
- fetch('/api/me').then(res=>res.json()).then(data => {
- if (data.success) {
- document.getElementById('loginView').classList.add('hidden');
- document.getElementById('appView').classList.remove('hidden');
- document.getElementById('userNameDisplay').innerText = data.username;
- isAdmin = (data.role === 'admin');
- if (isAdmin) document.getElementById('navAdmin').classList.remove('hidden');
- loadCategories(); loadLatest(); loadHistory(); openArticle(1);
- } else {
- document.getElementById('appView').classList.add('hidden');
- document.getElementById('loginView').classList.remove('hidden');
+ fetch('/api/me')
+ .then(res => res.text()) // Antwort erst als rohen Text lesen
+ .then(text => {
+ try {
+ const data = JSON.parse(text); // Versuchen, es in JSON umzuwandeln
+ if (data.success) {
+ document.getElementById('loginView').classList.add('hidden');
+ document.getElementById('appView').classList.remove('hidden');
+ document.getElementById('userNameDisplay').innerText = data.username;
+ isAdmin = (data.role === 'admin');
+ if (isAdmin) document.getElementById('navAdmin').classList.remove('hidden');
+ loadCategories(); loadLatest(); loadHistory(); openArticle(1);
+ } else {
+ document.getElementById('appView').classList.add('hidden');
+ document.getElementById('loginView').classList.remove('hidden');
+ }
+ } catch (e) {
+ // Wenn es kein JSON ist, ist das Backend gecrasht. Fehler direkt anzeigen!
+ document.body.innerHTML = `
Backend-Crash 💥
Die PHP-Dateien werfen einen Fehler statt JSON aus:
${text}
`;
}
});
}
@@ -241,6 +281,15 @@
function logout() { fetch('/api/logout').then(() => { location.reload(); }); }
+ // --- MOBILE MENU LOGIC ---
+ function toggleMobileMenu() {
+ const sidebar = document.getElementById('leftSidebar');
+ const overlay = document.getElementById('mobileMenuOverlay');
+ sidebar.classList.toggle('-translate-x-full');
+ overlay.classList.toggle('hidden');
+ }
+
+ // --- WIKI LOGIK (REKURSIVE KATEGORIEN) ---
function loadCategories() {
fetch('/api/categories').then(res=>res.json()).then(data => {
if(!data.success) return;
@@ -250,48 +299,37 @@
if(adminList) adminList.innerHTML = ''; if(adminSel) adminSel.innerHTML = '
';
let allCats = data.data;
-
- // ROBUSTHEITS-CHECK FÜR LEERES WIKI
- if(allCats.length === 0) {
- nav.innerHTML = '
Noch keine Bibliotheken vorhanden.
Lege oben rechts unter ⚙️ deine erste Kategorie an!
';
- sel.innerHTML = '
';
- return;
- }
-
- let mainCats = allCats.filter(c => !c.parent_id);
+ let mainCats = allCats.filter(c => c.parent_id == null);
+ // Admin Dropdowns füllen
allCats.forEach(c => {
- let safeName = (c.name || 'Unbenannt').replace(/'/g, "\\'");
- let safeIcon = c.icon || '📁';
- let safeParent = c.parent_id || '';
-
- sel.innerHTML += `
`;
- if(adminSel) adminSel.innerHTML += `
`;
-
+ sel.innerHTML += `
`;
+ if(adminSel) adminSel.innerHTML += `
`;
if(adminList) {
let parentLabel = c.parent_id ? '
(Unterkategorie)' : '';
- adminList.innerHTML += `
${safeIcon} ${c.name || 'Unbenannt'}${parentLabel} `;
+ adminList.innerHTML += `
${c.icon} ${c.name}${parentLabel} `;
}
});
+ // Rekursiver Baum-Aufbau für Navigation
mainCats.forEach(cat => { nav.innerHTML += buildCategoryTree(cat, allCats); });
- }).catch(err => console.error(err));
+ });
}
function buildCategoryTree(cat, allCats) {
let children = allCats.filter(c => c.parent_id == cat.id);
- let safeName = cat.name || 'Unbenannt'; let safeIcon = cat.icon || '📁';
- let html = `
${safeIcon} ${safeName}
`;
+ let html = `${cat.icon} ${cat.name}
`;
- let arts = cat.articles || [];
- if(arts.length === 0 && children.length === 0) html += `- Leer
`;
+ if(cat.articles.length === 0 && children.length === 0) html += `- Leer
`;
- arts.forEach(art => {
+ cat.articles.forEach(art => {
let activeCls = (art.id == currentArticleId) ? 'text-accent font-bold' : 'text-gray-400 hover:text-white';
- html += `- ${art.title}
`;
+ html += `- ${art.title}
`;
});
- children.forEach(child => { html += `- ` + buildCategoryTree(child, allCats) + `
`; });
+ children.forEach(child => {
+ html += `- ` + buildCategoryTree(child, allCats) + `
`;
+ });
return html + `
`;
}
@@ -299,7 +337,6 @@
fetch('/api/latest').then(res=>res.json()).then(data => {
if(!data.success) return;
const nav = document.getElementById('latestNav'); nav.innerHTML = '';
- if(data.data.length === 0) nav.innerHTML = 'Noch keine Updates
';
data.data.forEach(a => { nav.innerHTML += `${a.title}
Von ${a.author_name}
`; });
});
}
@@ -308,28 +345,13 @@
fetch('/api/history').then(res=>res.json()).then(data => {
if(!data.success) return;
const nav = document.getElementById('historyNav'); nav.innerHTML = '';
- if(data.data.length === 0) nav.innerHTML = 'Noch keine Historie
';
data.data.forEach(h => { nav.innerHTML += `${h.title}
${h.viewed_at.substring(0,16)}
`; });
});
}
function openArticle(id) {
fetch('/api/article?id=' + id).then(res=>res.json()).then(data => {
- // FALLBACK WENN DB KOMPLETT LEER IST
- if(!data.success) {
- document.getElementById('readView').classList.remove('hidden');
- document.getElementById('editView').classList.add('hidden');
- document.getElementById('readCategory').innerText = 'System Info';
- document.getElementById('readTitle').innerText = 'CoreWiki ist einsatzbereit!';
- document.getElementById('readAuthor').innerText = '-';
- document.getElementById('readDate').innerText = '-';
- document.getElementById('readContent').innerHTML = 'Das Wiki ist noch leer. Klicke oben rechts auf das Zahnrad ⚙️ -> Kategorien, um deine erste Bibliothek (z.B. "Infrastruktur") anzulegen. Klicke danach auf + Neuer Artikel, um zu starten!
';
- document.getElementById('btnDelete').classList.add('hidden');
- document.getElementById('btnEdit').classList.add('hidden');
- return;
- }
-
- document.getElementById('btnEdit').classList.remove('hidden');
+ if(!data.success) return;
currentArticleId = id; const art = data.data;
document.getElementById('readView').classList.remove('hidden'); document.getElementById('editView').classList.add('hidden');
document.getElementById('readCategory').innerText = art.category_name || 'Allgemein'; document.getElementById('readTitle').innerText = art.title;
@@ -341,6 +363,12 @@
if (isAdmin && id != 1) document.getElementById('btnDelete').classList.remove('hidden'); else document.getElementById('btnDelete').classList.add('hidden');
if(window.mermaid) setTimeout(() => { window.mermaid.run({ querySelector: '.mermaid' }); }, 100);
loadCategories(); loadHistory();
+
+ // Close mobile menu if open
+ if(window.innerWidth < 768) {
+ document.getElementById('leftSidebar').classList.add('-translate-x-full');
+ document.getElementById('mobileMenuOverlay').classList.add('hidden');
+ }
});
}
@@ -372,6 +400,7 @@
fetch('/api/article/delete', { method: 'POST', body: fd }).then(res=>res.json()).then(data => { if(data.success) { openArticle(1); loadLatest(); } else alert('Fehler'); });
}
+ // --- Kategorie Management ---
document.getElementById('catForm').addEventListener('submit', function(e) {
e.preventDefault(); const fd = new FormData();
fd.append('id', document.getElementById('catId').value); fd.append('name', document.getElementById('catName').value);
@@ -381,13 +410,17 @@
});
});
function resetCatForm() { document.getElementById('catForm').reset(); document.getElementById('catId').value = '0'; }
- function editCategory(id, name, icon, parentId) { document.getElementById('catId').value = id; document.getElementById('catName').value = name; document.getElementById('catIcon').value = icon; document.getElementById('catParentId').value = parentId; }
+ function editCategory(id, name, icon, parentId) {
+ document.getElementById('catId').value = id; document.getElementById('catName').value = name;
+ document.getElementById('catIcon').value = icon; document.getElementById('catParentId').value = parentId;
+ }
function deleteCategory(id) {
if(!confirm('Kategorie löschen? (Artikel werden in Hauptkategorie verschoben)')) return;
const fd = new FormData(); fd.append('id', id);
fetch('/api/categories/delete', { method: 'POST', body: fd }).then(res=>res.json()).then(data => { if(data.success) loadCategories(); });
}
+ // --- DRAG & DROP BILDER UPLOAD ---
const editor = document.getElementById('editContent');
editor.addEventListener('dragover', (e) => { e.preventDefault(); editor.classList.add('border-accent'); });
editor.addEventListener('dragleave', (e) => { e.preventDefault(); editor.classList.remove('border-accent'); });
@@ -402,19 +435,20 @@
else editor.value = editor.value.replace(``, `*(Upload fehlgeschlagen)*`);
});
+ // --- CORETEMPLATE ADMIN LOGIK ---
function openModal(id) {
document.getElementById(id).classList.remove('hidden');
- if(id === 'adminModal') { loadUsers(); loadSettings(); loadAuditLogs(); loadCategories(); }
+ if(id === 'adminModal') { loadUsers(); loadSettings(); loadAuditLogs(); }
}
function closeModal(id) { document.getElementById(id).classList.add('hidden'); }
function switchAdminTab(tab) {
['categories', 'users', 'settings', 'logs'].forEach(t => {
document.getElementById('admin-tab-'+t).classList.add('hidden');
- document.getElementById('btn-admin-'+t).className = 'text-gray-400 hover:text-white';
+ document.getElementById('btn-admin-'+t).className = 'text-gray-400 hover:text-white text-sm md:text-base px-2';
});
document.getElementById('admin-tab-'+tab).classList.remove('hidden');
- document.getElementById('btn-admin-'+tab).className = 'text-accent font-bold';
+ document.getElementById('btn-admin-'+tab).className = 'text-accent font-bold text-sm md:text-base px-2';
}
document.getElementById('passwordForm').addEventListener('submit', function(e) {
@@ -428,13 +462,83 @@
});
});
- function loadAuditLogs() { fetch('/api/logs').then(res => res.json()).then(data => { if (data.success) { const tbody = document.getElementById('logTableBody'); tbody.innerHTML = ''; data.data.forEach(log => { tbody.innerHTML += `| ${log.timestamp} | ${log.username} | ${log.action} | ${log.target || '-'} |
`; }); } }); }
- function loadSettings() { fetch('/api/settings').then(res => res.json()).then(data => { if (data.success) { const tbody = document.getElementById('settingsTableBody'); tbody.innerHTML = ''; data.data.forEach(setting => { tbody.innerHTML += `| ${setting.config_key} | ${setting.config_value} | |
`; }); } }); }
- function loadUsers() { fetch('/api/users').then(res => res.json()).then(data => { if (data.success) { const tbody = document.getElementById('usersTableBody'); tbody.innerHTML = ''; data.data.forEach(u => { let roleBadge = u.role === 'admin' ? 'Admin' : 'Author'; tbody.innerHTML += `| ${u.id} | ${u.username} | ${roleBadge} | |
`; }); } }); }
- function deleteSetting(key) { if (!confirm(`Einstellung "${key}" löschen?`)) return; const fd = new FormData(); fd.append('config_key', key); fetch('/api/settings/delete', { method: 'POST', body: fd }).then(res => res.json()).then(data => { if (data.success) loadSettings(); }); }
- function deleteUser(id) { if (!confirm('Benutzer löschen?')) return; const fd = new FormData(); fd.append('id', id); fetch('/api/users/delete', { method: 'POST', body: fd }).then(res => res.json()).then(data => { if (data.success) loadUsers(); else alert(data.error); }); }
- document.getElementById('settingsForm').addEventListener('submit', function(e) { e.preventDefault(); const fd = new FormData(); fd.append('config_key', document.getElementById('configKey').value); fd.append('config_value', document.getElementById('configValue').value); fetch('/api/settings', { method: 'POST', body: fd }).then(res => res.json()).then(data => { if (data.success) { document.getElementById('configKey').value = ''; document.getElementById('configValue').value = ''; loadSettings(); } }); });
- document.getElementById('userForm').addEventListener('submit', function(e) { e.preventDefault(); const fd = new FormData(); fd.append('username', document.getElementById('newUsername').value); fd.append('password', document.getElementById('newUserPass').value); fd.append('role', document.getElementById('newUserRole').value); fetch('/api/users', { method: 'POST', body: fd }).then(res => res.json()).then(data => { if (data.success) { document.getElementById('newUsername').value = ''; document.getElementById('newUserPass').value = ''; loadUsers(); } else alert(data.error); }); });
+ function loadAuditLogs() {
+ fetch('/api/logs').then(res => res.json()).then(data => {
+ if (data.success) {
+ const tbody = document.getElementById('logTableBody'); tbody.innerHTML = '';
+ data.data.forEach(log => { tbody.innerHTML += `| ${log.timestamp} | ${log.username} | ${log.action} | ${log.target || '-'} |
`; });
+ }
+ });
+ }
+
+ function loadSettings() {
+ fetch('/api/settings').then(res => res.json()).then(data => {
+ if (data.success) {
+ const tbody = document.getElementById('settingsTableBody'); tbody.innerHTML = '';
+ data.data.forEach(setting => { tbody.innerHTML += `| ${setting.config_key} | ${setting.config_value} | |
`; });
+ }
+ });
+ }
+
+ function loadUsers() {
+ fetch('/api/users').then(res => res.json()).then(data => {
+ if (data.success) {
+ const tbody = document.getElementById('usersTableBody'); tbody.innerHTML = '';
+ data.data.forEach(u => {
+ let roleBadge = u.role === 'admin' ? 'Admin' : 'Author';
+ tbody.innerHTML += `| ${u.id} | ${u.username} | ${roleBadge} | |
`;
+ });
+ }
+ });
+ }
+
+ function deleteSetting(key) {
+ if (!confirm(`Einstellung "${key}" löschen?`)) return; const fd = new FormData(); fd.append('config_key', key);
+ fetch('/api/settings/delete', { method: 'POST', body: fd }).then(res => res.json()).then(data => { if (data.success) loadSettings(); });
+ }
+
+ function deleteUser(id) {
+ if (!confirm('Benutzer löschen?')) return; const fd = new FormData(); fd.append('id', id);
+ fetch('/api/users/delete', { method: 'POST', body: fd }).then(res => res.json()).then(data => { if (data.success) loadUsers(); else alert(data.error); });
+ }
+
+ document.getElementById('settingsForm').addEventListener('submit', function(e) {
+ e.preventDefault(); const fd = new FormData(); fd.append('config_key', document.getElementById('configKey').value); fd.append('config_value', document.getElementById('configValue').value);
+ fetch('/api/settings', { method: 'POST', body: fd }).then(res => res.json()).then(data => { if (data.success) { document.getElementById('configKey').value = ''; document.getElementById('configValue').value = ''; loadSettings(); } });
+ });
+
+ document.getElementById('userForm').addEventListener('submit', function(e) {
+ e.preventDefault(); const fd = new FormData(); fd.append('username', document.getElementById('newUsername').value); fd.append('password', document.getElementById('newUserPass').value); fd.append('role', document.getElementById('newUserRole').value);
+ fetch('/api/users', { method: 'POST', body: fd }).then(res => res.json()).then(data => { if (data.success) { document.getElementById('newUsername').value = ''; document.getElementById('newUserPass').value = ''; loadUsers(); } else alert(data.error); });
+ });
+
+ // --- LIVE SUCHE ---
+ let searchTimeout;
+ function searchWiki() {
+ clearTimeout(searchTimeout);
+ const query = document.getElementById('searchInput').value;
+ const resBox = document.getElementById('searchResults');
+
+ if (query.length < 2) {
+ resBox.classList.add('hidden');
+ return;
+ }
+
+ searchTimeout = setTimeout(() => {
+ fetch('/api/search?q=' + encodeURIComponent(query))
+ .then(res => res.json())
+ .then(data => {
+ if (!data.success || data.data.length === 0) {
+ resBox.innerHTML = 'Nichts gefunden.
';
+ } else {
+ resBox.innerHTML = data.data.map(art =>
+ `${art.title}
`
+ ).join('');
+ }
+ resBox.classList.remove('hidden');
+ });
+ }, 300); // 300ms Debounce, um die Datenbank zu schonen
+ }