This commit is contained in:
2025-11-28 02:46:51 +01:00
parent 99ad78dbe4
commit aae6006656
4 changed files with 192 additions and 149 deletions

View File

@@ -1,87 +1,114 @@
// public/assets/js/header.js
document.addEventListener('DOMContentLoaded', function () {
document.addEventListener("DOMContentLoaded", function () {
// --------------------------------------------------
// Sprachauflösung: basiert NUR auf usbConfig / i18n
// Sprachauflösung: basiert auf derselben Logik wie lang.js
//
// Priorität:
// a) ?lang= in der URL
// b) localStorage (usbcheck_lang)
// c) Browsersprache
// d) 'en' wenn vorhanden
// e) erste verfügbare Sprache
// --------------------------------------------------
const cfg = window.usbConfig || {};
const i18nCfg = cfg.i18n || {};
const availLangs = i18nCfg.available || {};
const availCodes = Object.keys(availLangs);
const cfg = window.usbConfig || {};
const i18nCfg = cfg.i18n || {};
const availLangs = i18nCfg.available || {};
const availCodes = Object.keys(availLangs);
function normalizeLang(code) {
if (!code) return '';
if (!code) return "";
return String(code).slice(0, 2).toLowerCase();
}
function detectBrowserLang() {
const nav = window.navigator || {};
const candidates = [];
if (Array.isArray(nav.languages)) {
candidates.push(...nav.languages);
}
if (typeof nav.language === "string") {
candidates.push(nav.language);
}
if (typeof nav.userLanguage === "string") {
candidates.push(nav.userLanguage);
}
for (const raw of candidates) {
const code = normalizeLang(raw);
if (availCodes.includes(code)) {
return code;
}
}
return null;
}
function resolveCurrentLang() {
const url = new URL(window.location.href);
const urlLang = normalizeLang(url.searchParams.get('lang'));
const urlLang = normalizeLang(url.searchParams.get("lang"));
// 1) ?lang= aus der URL, wenn gültig
// a) ?lang= aus der URL, wenn gültig
if (urlLang && availCodes.includes(urlLang)) {
return urlLang;
}
// 2) localStorage (vom lang.js gesetzt)
const stored = normalizeLang(localStorage.getItem('usbcheck_lang'));
// b) localStorage (vom lang.js gesetzt)
const stored = normalizeLang(localStorage.getItem("usbcheck_lang"));
if (stored && availCodes.includes(stored)) {
return stored;
}
// 3) PHP-Konfig (fileload/app_config)
const cfgLang = normalizeLang(i18nCfg.current || cfg.lang);
if (cfgLang && availCodes.includes(cfgLang)) {
return cfgLang;
if (stored && !availCodes.includes(stored)) {
localStorage.removeItem("usbcheck_lang");
}
// 4) <html lang="...">
const docLang = normalizeLang(document.documentElement.getAttribute('lang'));
if (docLang && availCodes.includes(docLang)) {
return docLang;
// c) Browsersprache
const browserLang = detectBrowserLang();
if (browserLang) {
return browserLang;
}
// 5) Fallback: en, wenn vorhanden
if (availCodes.includes('en')) {
return 'en';
// d) Fallback: en, wenn vorhanden
if (availCodes.includes("en")) {
return "en";
}
// 6) sonst erste verfügbare Sprache
// e) Sonst erste verfügbare Sprache
if (availCodes.length > 0) {
return availCodes[0];
}
// 7) absolute Notlösung
return 'en';
// f) absolute Notlösung
return "en";
}
// --------------------------------------------------
// LOGIN-BUTTON → /login mit redirect + lang
// --------------------------------------------------
const loginBtn = document.getElementById('loginButton');
const loginBtn = document.getElementById("loginButton");
if (loginBtn) {
loginBtn.addEventListener('click', function (event) {
loginBtn.addEventListener("click", function (event) {
event.preventDefault();
const currentPath = window.location.pathname || '/';
const currentQuery = window.location.search || '';
const currentPath = window.location.pathname || "/";
const currentQuery = window.location.search || "";
const redirect = currentPath + currentQuery;
const lang = resolveCurrentLang();
// Wenn wir bereits auf /login sind → nur zum #auth scrollen
if (currentPath === '/login' || currentPath === '/login/') {
const authEl = document.getElementById('auth');
if (currentPath === "/login" || currentPath === "/login/") {
const authEl = document.getElementById("auth");
if (authEl) {
authEl.scrollIntoView({ behavior: 'smooth', block: 'start' });
authEl.scrollIntoView({ behavior: "smooth", block: "start" });
}
return;
}
// Sonst: auf Login-Seite mit lang + redirect-Parameter
const url = '/login/?lang=' + encodeURIComponent(lang) +
'&redirect=' + encodeURIComponent(redirect) +
'#auth';
const url = "/login/?lang=" + encodeURIComponent(lang) +
"&redirect=" + encodeURIComponent(redirect) +
"#auth";
window.location.href = url;
});
@@ -90,21 +117,21 @@ document.addEventListener('DOMContentLoaded', function () {
// --------------------------------------------------
// AVATAR-MENÜ (userAvatar / userMenu)
// --------------------------------------------------
const avatarBtn = document.getElementById('userAvatar');
const userMenu = document.getElementById('userMenu');
const avatarBtn = document.getElementById("userAvatar");
const userMenu = document.getElementById("userMenu");
if (avatarBtn && userMenu) {
avatarBtn.addEventListener('click', function (event) {
avatarBtn.addEventListener("click", function (event) {
event.stopPropagation();
userMenu.classList.toggle('hidden');
userMenu.classList.toggle("hidden");
const expanded = avatarBtn.getAttribute('aria-expanded') === 'true';
avatarBtn.setAttribute('aria-expanded', expanded ? 'false' : 'true');
const expanded = avatarBtn.getAttribute("aria-expanded") === "true";
avatarBtn.setAttribute("aria-expanded", expanded ? "false" : "true");
});
// Klick außerhalb schließt Menü
document.addEventListener('click', function (event) {
if (userMenu.classList.contains('hidden')) {
document.addEventListener("click", function (event) {
if (userMenu.classList.contains("hidden")) {
return;
}
@@ -112,8 +139,8 @@ document.addEventListener('DOMContentLoaded', function () {
const clickedAvatarButton = avatarBtn.contains(event.target);
if (!clickedInsideMenu && !clickedAvatarButton) {
userMenu.classList.add('hidden');
avatarBtn.setAttribute('aria-expanded', 'false');
userMenu.classList.add("hidden");
avatarBtn.setAttribute("aria-expanded", "false");
}
});
}
@@ -122,9 +149,9 @@ document.addEventListener('DOMContentLoaded', function () {
// LOGOUT-MODAL
// --------------------------------------------------
const logoutButtons = document.querySelectorAll('[data-logout-link="true"]');
const backdrop = document.getElementById('logoutModalBackdrop');
const btnConfirm = document.getElementById('logoutConfirm');
const btnCancel = document.getElementById('logoutCancel');
const backdrop = document.getElementById("logoutModalBackdrop");
const btnConfirm = document.getElementById("logoutConfirm");
const btnCancel = document.getElementById("logoutCancel");
let logoutTarget = null;
@@ -132,64 +159,64 @@ document.addEventListener('DOMContentLoaded', function () {
logoutTarget = targetHref || null;
if (!backdrop) return;
backdrop.classList.remove('hidden');
document.body.classList.add('overflow-hidden');
backdrop.classList.remove("hidden");
document.body.classList.add("overflow-hidden");
}
function hideLogoutModal() {
if (!backdrop) return;
backdrop.classList.add('hidden');
document.body.classList.remove('overflow-hidden');
backdrop.classList.add("hidden");
document.body.classList.remove("overflow-hidden");
logoutTarget = null;
}
if (logoutButtons.length && backdrop && btnConfirm && btnCancel) {
logoutButtons.forEach(function (btn) {
btn.addEventListener('click', function (event) {
btn.addEventListener("click", function (event) {
event.preventDefault();
event.stopPropagation();
const href = btn.getAttribute('data-logout-href')
|| btn.getAttribute('href')
|| '/auth/logout';
const href = btn.getAttribute("data-logout-href")
|| btn.getAttribute("href")
|| "/auth/logout";
showLogoutModal(href);
// Avatar-Menü beim Öffnen des Modals schließen
if (userMenu && !userMenu.classList.contains('hidden')) {
userMenu.classList.add('hidden');
if (userMenu && !userMenu.classList.contains("hidden")) {
userMenu.classList.add("hidden");
if (avatarBtn) {
avatarBtn.setAttribute('aria-expanded', 'false');
avatarBtn.setAttribute("aria-expanded", "false");
}
}
});
});
// Bestätigen → weiter zur Logout-URL
btnConfirm.addEventListener('click', function () {
btnConfirm.addEventListener("click", function () {
if (logoutTarget) {
window.location.href = logoutTarget;
} else {
window.location.href = '/auth/logout';
window.location.href = "/auth/logout";
}
});
// Abbrechen → Modal schließen
btnCancel.addEventListener('click', function () {
btnCancel.addEventListener("click", function () {
hideLogoutModal();
});
// Klick auf Hintergrund schließt Modal (außer man klickt auf die Card)
backdrop.addEventListener('click', function (event) {
const card = backdrop.querySelector('.max-w-sm');
backdrop.addEventListener("click", function (event) {
const card = backdrop.querySelector(".max-w-sm");
if (card && !card.contains(event.target)) {
hideLogoutModal();
}
});
// ESC-Taste schließt Modal
document.addEventListener('keydown', function (event) {
if (event.key === 'Escape' && !backdrop.classList.contains('hidden')) {
document.addEventListener("keydown", function (event) {
if (event.key === "Escape" && !backdrop.classList.contains("hidden")) {
hideLogoutModal();
}
});