/* teach - start: beeldgrootte, contrast, sessie-herstel */ /* ========================================================= init ==========================================================*/ /* display size: scale the whole app up for pupils who need it (device setting) */ let ZOOM = 100; const btnZoomIn = document.getElementById("btnZoomIn"); const btnZoomOut = document.getElementById("btnZoomOut"); const zoomPct = document.getElementById("zoomPct"); function setZoom(z){ ZOOM = Math.max(100, Math.min(200, Math.round(z/10)*10)); document.body.style.zoom = ZOOM/100; zoomPct.textContent = ZOOM+"%"; zoomPct.classList.toggle("on", ZOOM!==100); btnZoomIn.title = btnZoomOut.title = zoomPct.title = T("zoomUI"); btnZoomIn.disabled = ZOOM>=200; btnZoomOut.disabled = ZOOM<=100; try{ localStorage.setItem("teach.zoom", ZOOM); }catch(e){} } btnZoomIn.addEventListener("click", ()=>setZoom(ZOOM+10)); btnZoomOut.addEventListener("click", ()=>setZoom(ZOOM-10)); zoomPct.addEventListener("click", ()=>setZoom(100)); /* tap the % to reset */ document.addEventListener("langchange", ()=>{ btnZoomIn.title = btnZoomOut.title = zoomPct.title = T("zoomUI"); }); try{ const z = +localStorage.getItem("teach.zoom"); if(z>100) setZoom(z); else setZoom(100); }catch(e){ setZoom(100); } /* weergave-instellingen (Instellingen → Weergave): apparaat-gebonden voorkeuren. Elke seg-groep: knopjes met data-v, keuze in localStorage, body-class toepassen. */ function initSeg(id, key, def, apply){ const seg = document.getElementById(id); let val = def; try{ val = localStorage.getItem(key) || def; }catch(e){} if(![...seg.querySelectorAll("button")].some(b=>b.dataset.v===val)) val = def; const set = v=>{ seg.querySelectorAll("button").forEach(b=>b.classList.toggle("active", b.dataset.v===v)); apply(v); try{ localStorage.setItem(key, v); }catch(e){} }; seg.querySelectorAll("button").forEach(b=>b.addEventListener("click", ()=>set(b.dataset.v))); set(val); } /* thema: licht / donker / automatisch (volgt het OS) */ const darkMq = window.matchMedia("(prefers-color-scheme: dark)"); const applyTheme = v=>{ document.body.classList.toggle("dark", v==="dark" || (v==="auto" && darkMq.matches)); }; initSeg("segTheme", "teach.theme", "light", applyTheme); darkMq.addEventListener("change", ()=>{ try{ if((localStorage.getItem("teach.theme")||"light")==="auto") applyTheme("auto"); }catch(e){} }); /* hoog contrast (voorheen de 👁-knop in de menubalk; zelfde localStorage-sleutel) */ (function(){ let init = "off"; try{ if(localStorage.getItem("teach.hc")==="1") init = "on"; }catch(e){} const seg = document.getElementById("segHC"); const set = v=>{ seg.querySelectorAll("button").forEach(b=>b.classList.toggle("active", b.dataset.v===v)); document.body.classList.toggle("hc", v==="on"); try{ localStorage.setItem("teach.hc", v==="on" ? "1" : ""); }catch(e){} }; seg.querySelectorAll("button").forEach(b=>b.addEventListener("click", ()=>set(b.dataset.v))); set(init); })(); /* menubalk-positie: boven / links / rechts */ initSeg("segTbar", "teach.tbar", "top", v=>{ document.body.classList.toggle("tb-left", v==="left"); document.body.classList.toggle("tb-right", v==="right"); }); /* minder beweging: standaard uit als het OS erom vraagt */ const motionDef = window.matchMedia("(prefers-reduced-motion: reduce)").matches ? "off" : "on"; initSeg("segMotion", "teach.motion", motionDef, v=>document.body.classList.toggle("no-motion", v==="off")); /* glas-effect (transparantie/blur van widgets en balken) */ initSeg("segGlass", "teach.glass", "on", v=>document.body.classList.toggle("no-glass", v==="off")); /* taalkeuze onthouden (de schakelaar staat nu onder Weergave) */ try{ const l = localStorage.getItem("teach.lang"); if(l && I18N[l]) LANG = l; }catch(e){} applyI18n(); updateEmptyHint(); /* sessie herstellen: de HttpOnly session-cookie (niet leesbaar door JS, dus geen client-side token-check meer mogelijk of nodig) gaat vanzelf mee met dit verzoek - een geldige sessie levert de gebruiker op, anders 401 (gast) */ (async function(){ updateBoardsUI(); try{ /* /auth/me en /me/data hangen allebei alleen af van dezelfde sessie-cookie, niet van elkaars antwoord - serieel wachten (eerst wie-ben-ik, dan pas mijn-data ophalen) kost een hele round-trip voor niets. Parallel opvragen en het tweede antwoord meegeven aan hydrateFromServer() (die het gewoon negeert voor een leerling/ouder, zie daar) scheelt die round-trip in het veelvoorkomende geval (staf/thuisgebruiker). */ const [meResult, dataResult] = await Promise.allSettled([api("/auth/me"), api("/me/data")]); if(meResult.status !== "fulfilled") throw meResult.reason; currentUser = meResult.value.user; updateUserUI(); await hydrateFromServer(dataResult.status === "fulfilled" ? dataResult.value : null); }catch(e){ resetToGuest(); } })();