const VALID_DASHBOARD_TABS = ; const DASHBOARD_HASH_ALIASES = { dashboard: 'home', ai: 'home', pages: 'content', messages: 'mails' }; let dashboardRouteApplying = false; let settingsLoaded = false; let currentSettings = null; let currentAiSettings = null; let aiChatMessages = []; let dashboardAiImageUsable = false; let currentDashboardAnalyticsRange = { period: 'days', count: 30 }; let formsAdminLoaded = false; function dashboardHashFor(tab, subtab) { const publicTab = tab === 'home' ? 'dashboard' : (tab === 'content' ? 'pages' : (tab === 'mails' ? 'messages' : tab)); return '#' + publicTab + (subtab ? '/' + subtab : ''); } // Topbar breadcrumb: ["Einstellungen", "Design"] → Einstellungen › Design // Collapsible sidebar: icons only, remembered per browser (function() { var btn = document.getElementById('sidebarCollapseBtn'); if (!btn || !document.documentElement) return; var KEY = 'raijuSidebarCollapsed'; var collapsed = false; try { collapsed = window.localStorage.getItem(KEY) === '1'; } catch (e) {} function applySidebarCollapsed(state) { var root = document.documentElement; if (state) root.setAttribute('data-sidebar', 'collapsed'); else root.removeAttribute('data-sidebar'); btn.setAttribute('aria-pressed', state ? 'true' : 'false'); var label = typeof t === 'function' ? t(state ? 'nav.expand_sidebar' : 'nav.collapse_sidebar') : ''; var labelSpan = btn.querySelector('span'); if (label && labelSpan) labelSpan.textContent = label; if (label) btn.title = label; // Icon-only items explain themselves on hover document.querySelectorAll('.sidebar-nav-item').forEach(function(item) { if (item === btn) return; var text = item.querySelector(':scope > span:not(.mail-badge)'); if (!text) return; if (state) item.setAttribute('title', text.textContent.trim()); else item.removeAttribute('title'); }); } applySidebarCollapsed(collapsed); btn.addEventListener('click', function() { collapsed = !collapsed; try { window.localStorage.setItem(KEY, collapsed ? '1' : '0'); } catch (e) {} applySidebarCollapsed(collapsed); }); })(); function rjSetTopbarTitle(parts) { const el = document.getElementById('topbarTitle'); if (!el) return; const list = (Array.isArray(parts) ? parts : [parts]).filter(Boolean); el.textContent = ''; list.forEach((text, i) => { if (i > 0) { const sep = document.createElement('span'); sep.className = 'topbar-crumb-sep'; sep.setAttribute('aria-hidden', 'true'); sep.textContent = '›'; el.appendChild(sep); } const span = document.createElement('span'); span.className = i < list.length - 1 ? 'topbar-crumb' : 'topbar-crumb-current'; span.textContent = text; el.appendChild(span); }); } window.rjSetTopbarTitle = rjSetTopbarTitle; function parseDashboardHash() { const raw = (window.location.hash || '').replace(/^#/, ''); if (!raw) return { tab: 'home', subtab: '' }; const parts = raw.split('/').filter(Boolean); const first = parts[0] || 'home'; const tab = DASHBOARD_HASH_ALIASES[first] || first; return { tab: VALID_DASHBOARD_TABS.indexOf(tab) !== -1 ? tab : 'home', subtab: parts[1] || '' }; } function updateDashboardHash(tab, subtab, replace) { if (dashboardRouteApplying) return; const next = DASHBOARD_PATH + dashboardHashFor(tab, subtab); if (window.location.pathname + window.location.hash === next) return; history[replace ? 'replaceState' : 'pushState']({ view: 'dashboard', tab: tab, subtab: subtab || '' }, '', next); } async function applyDashboardRoute(replace) { dashboardRouteApplying = true; const params = new URLSearchParams(window.location.search); const pageParam = params.get('page'); const tabParam = params.get('tab'); const postParam = params.get('post'); const route = parseDashboardHash(); const hashParts = (window.location.hash || '').replace(/^#/, '').split('/').filter(Boolean); const needsPageList = hashParts[0] === 'page' || !!pageParam || tabParam === 'news' || route.tab === 'content'; if (needsPageList) { try { const response = await fetch('api.php?action=list-pages&_=' + Date.now()); const result = await response.json(); if (result.success) { applyPageList(result.data); } } catch (e) { console.error('Error loading page list:', e); } } let canonicalTab = route.tab || 'home'; let canonicalSubtab = route.subtab || ''; let canonicalUrl = null; if (hashParts[0] === 'page' && hashParts[1] && hashParts[1].includes('_')) { const page = hashParts[1]; const lang = page.substring(0, page.indexOf('_')); const slug = page.substring(page.indexOf('_') + 1); switchTab('content', { replace: true }); canonicalTab = 'content'; canonicalSubtab = ''; const langSelect = document.getElementById('langSelect'); if (langSelect) { langSelect.value = lang; updatePageSelect(slug); const pageSelect = document.getElementById('pageSelect'); if (pageSelect) { pageSelect.value = slug; await loadContent(false); } } canonicalUrl = DASHBOARD_PATH + '#page/' + page; } else if (route.tab !== 'home' || route.subtab) { switchTab(route.tab, { settingsTab: route.subtab, replace: !!replace }); canonicalTab = route.tab; canonicalSubtab = route.subtab; } else if (tabParam === 'news' && isDashboardModuleEnabled('news')) { switchTab('news'); canonicalTab = 'news'; canonicalSubtab = ''; if (postParam) { // Wait for news to load, then open the post editor await loadNews(); newsLoaded = true; editPost(postParam); } } else if (pageParam && pageParam.includes('_')) { const lang = pageParam.substring(0, pageParam.indexOf('_')); const slug = pageParam.substring(pageParam.indexOf('_') + 1); switchTab('content', { replace: true }); canonicalTab = 'content'; canonicalSubtab = ''; const langSelect = document.getElementById('langSelect'); if (langSelect) { langSelect.value = lang; updatePageSelect(slug); const pageSelect = document.getElementById('pageSelect'); if (pageSelect) { pageSelect.value = slug; await loadContent(false); } } canonicalUrl = DASHBOARD_PATH + '#page/' + pageParam; } else { switchTab('home', { replace: !!replace }); canonicalTab = 'home'; canonicalSubtab = ''; } dashboardRouteApplying = false; if (canonicalUrl) { history.replaceState({ view: 'editor', page: hashParts[1] || pageParam }, '', canonicalUrl); } else if (window.location.pathname.endsWith('/dashboard.php') || replace) { updateDashboardHash(canonicalTab, canonicalSubtab, true); } } // Auto-load page/hash route, otherwise show page list. // Deferred by one microtask: every fragment shares this script block, and a // route into News or Events reads flags (newsLoaded, eventsLoaded) that are // declared further down. Running synchronously here hit their temporal dead // zone and left those tabs empty after a direct #news / #events load. Promise.resolve().then(() => applyDashboardRoute(true)); // Browser back/forward navigation window.addEventListener('popstate', async (e) => { if (e.state && e.state.view === 'editor' && e.state.page) { const lang = e.state.page.substring(0, e.state.page.indexOf('_')); const slug = e.state.page.substring(e.state.page.indexOf('_') + 1); document.getElementById('langSelect').value = lang; updatePageSelect(slug); document.getElementById('pageSelect').value = slug; loadContent(false); } else { await applyDashboardRoute(true); } }); window.addEventListener('hashchange', function() { applyDashboardRoute(true); }); document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { closeModal(); closeMailDetail(); } }); // ============================================================ // TAB NAVIGATION // ============================================================ function dismissFrontendEditBanner() { const banner = document.getElementById('frontendEditBanner'); if (banner) banner.remove(); } function switchTab(tab, options) { options = options || {}; if (!isDashboardModuleEnabled(tab)) { tab = 'home'; options = Object.assign({}, options, { replace: true }); } if (tab !== 'content') { dismissFrontendEditBanner(); } const systemTab = document.getElementById('systemTab'); if (systemTab) systemTab.style.display = tab === 'system' ? 'block' : 'none'; if (tab === 'system') loadSystemStatus(); document.getElementById('homeTab').style.display = tab === 'home' ? 'block' : 'none'; document.getElementById('contentTab').style.display = tab === 'content' ? 'block' : 'none'; document.getElementById('newsTab').style.display = tab === 'news' ? 'block' : 'none'; document.getElementById('eventsTab').style.display = tab === 'events' ? 'block' : 'none'; document.getElementById('mailsTab').style.display = tab === 'mails' ? 'block' : 'none'; const mediaTab = document.getElementById('mediaTab'); if (mediaTab) mediaTab.style.display = tab === 'media' ? 'block' : 'none'; const iconsTab = document.getElementById('iconsTab'); if (iconsTab) iconsTab.style.display = tab === 'icons' ? 'block' : 'none'; document.getElementById('settingsTab').style.display = tab === 'settings' ? 'block' : 'none'; document.getElementById('backupTab').style.display = tab === 'backup' ? 'block' : 'none'; if (typeof syncAssistantEmbed === 'function') syncAssistantEmbed(); // Show/hide topbar selectors — only when editing a page (not on page list) const topbarSelectors = document.getElementById('topbarSelectors'); if (topbarSelectors) { if (tab === 'content' && currentPage) { topbarSelectors.style.display = 'flex'; } else { topbarSelectors.style.display = 'none'; } } // When switching to content tab, always show page list if (tab === 'content') { showPageList(); } // Update sidebar active state document.querySelectorAll('.sidebar-nav-item[data-tab]').forEach(btn => btn.classList.remove('active')); const activeNavItem = document.querySelector(`.sidebar-nav-item[data-tab="${tab}"]`); if (activeNavItem) activeNavItem.classList.add('active'); // Update topbar title const titles = { system: t('system.title'), home: t('dashboard_home.title'), content: currentPage ? t('editor.title') : t('pages.title'), news: t('news.title'), mails: t('mails.title'), events: t('events.title'), media: t('nav.media_library'), icons: t('icons.title'), settings: t('settings.title'), backup: t('settings.backup') }; rjSetTopbarTitle([titles[tab] || 'Dashboard']); // Close sidebar on mobile after tab switch document.getElementById('adminSidebar').classList.remove('open'); if (tab === 'mails') { // Always start on the list view when switching into Mails const mailsList = document.getElementById('mailsListView'); const mailDetail = document.getElementById('mailDetailView'); if (mailsList) mailsList.style.display = ''; if (mailDetail) mailDetail.style.display = 'none'; loadMails(); } if (tab === 'media' && window.NbImageManager) { initDashboardImageManager(); const mount = document.getElementById('mediaLibraryMount'); if (mount) { NbImageManager.mount(mount, { types: ['image', 'audio', 'video', 'document'] }); } } if (tab === 'home') { loadDashboardOverview(); } if (tab === 'news') { showNewsList(); if (!newsLoaded) { newsLoaded = true; loadNews(); } } if (tab === 'events') { // Always start on the list view when switching into Events const listView = document.getElementById('eventsListView'); const editorView = document.getElementById('eventsEditorView'); const trashView = document.getElementById('eventsTrashView'); if (listView) listView.style.display = ''; if (editorView) editorView.style.display = 'none'; if (trashView) trashView.style.display = 'none'; currentEventIndex = null; if (!eventsLoaded) { eventsLoaded = true; loadEventsEditor(); } } if (tab === 'icons' && typeof loadIconManager === 'function') { loadIconManager(); } if (tab === 'settings') { activateSettingsTab(options.settingsTab || getActiveSettingsTab(), { silent: true }); } if (tab === 'settings' && !settingsLoaded) { loadSettings(); } updateDashboardHash(tab, tab === 'settings' ? (options.settingsTab || getActiveSettingsTab()) : '', !!options.replace); }