// Login page: language, theme, local form and/or OIDC button (from /auth/config). (function () { var I18N = { fr: { intro: 'Synchronisation de configuration Proxmox VE', user: 'Utilisateur', pass: 'Mot de passe', submit: 'Se connecter', sso: 'Se connecter avec le SSO', or: 'ou', error: 'Utilisateur ou mot de passe incorrect.', theme: 'Thème clair / sombre', demo: 'Mode démo : comptes {a}, {o} et {l}, mot de passe {p}.' }, en: { intro: 'Proxmox VE configuration synchronization', user: 'User', pass: 'Password', submit: 'Sign in', sso: 'Sign in with SSO', or: 'or', error: 'Wrong user or password.', theme: 'Light / dark theme', demo: 'Demo mode: accounts {a}, {o} and {l}, password {p}.' }, }; function get(k) { try { return localStorage.getItem('confsync.' + k); } catch (e) { return null; } } function set(k, v) { try { localStorage.setItem('confsync.' + k, v); } catch (e) {} } var lang = get('lang'); if (!I18N[lang]) lang = /^en\b/i.test(navigator.language || '') ? 'en' : 'fr'; var cfg = { local: true, oidc: false, demo: false }; function el(id) { return document.getElementById(id); } function code(s) { var c = document.createElement('code'); c.textContent = s; return c; } function applyLang() { var d = I18N[lang]; document.documentElement.lang = lang; document.querySelectorAll('[data-i18n]').forEach(function (e) { e.textContent = d[e.dataset.i18n]; }); document.querySelectorAll('[data-i18n-title]').forEach(function (e) { e.title = d[e.dataset.i18nTitle]; }); document.querySelectorAll('[data-i18n-aria]').forEach(function (e) { e.setAttribute('aria-label', d[e.dataset.i18nAria]); }); document.querySelectorAll('#langSwitch [data-lang]').forEach(function (b) { b.setAttribute('aria-checked', String(b.dataset.lang === lang)); }); var h = el('demoHint'); h.textContent = ''; if (cfg.demo) { // "{a}" placeholders become elements, never HTML from a string d.demo.split(/(\{[aolp]\})/).forEach(function (part) { var v = { '{a}': 'admin', '{o}': 'operateur', '{l}': 'lecteur', '{p}': 'confsync-demo' }[part]; h.appendChild(v ? code(v) : document.createTextNode(part)); }); } } document.querySelectorAll('#langSwitch [data-lang]').forEach(function (b) { b.addEventListener('click', function () { lang = b.dataset.lang; set('lang', lang); applyLang(); }); }); el('themeBtn').addEventListener('click', function () { var root = document.documentElement; var dark = root.dataset.theme ? root.dataset.theme === 'dark' : matchMedia('(prefers-color-scheme: dark)').matches; root.dataset.theme = dark ? 'light' : 'dark'; set('theme', root.dataset.theme); }); var q = new URLSearchParams(location.search); var ret = q.get('r') || '/'; el('ret').value = ret; el('err').hidden = q.get('e') !== '1'; el('ssoBtn').href = 'auth/oidc?r=' + encodeURIComponent(ret); function show() { el('localForm').hidden = !cfg.local; el('ssoBtn').hidden = !cfg.oidc; el('sep').hidden = !(cfg.local && cfg.oidc); el('submitBtn').className = cfg.oidc ? 'btn' : 'btn primary'; el('demoHint').hidden = !cfg.demo; applyLang(); } show(); fetch('auth/config', { headers: { Accept: 'application/json' } }) .then(function (r) { return r.json(); }) .then(function (c) { cfg = c; show(); }) .catch(function () {}); })();