/* teach - leerling-omgeving: toont enkel de widgets die de leerkracht heeft klaargezet (via een toewijzing aan de klas of de leerling zelf), in speelmodus (readonly) en zonder de sleep/vergroot/sluit-chrome van het bord. Geen momentopname: /my/assignment zoekt live in het bord van de leerkracht, dus deze pagina pollt periodiek zodat nieuwe woorden vanzelf doorkomen. Modus per toewijzing: "werken" (default, leerling werkt in de widget en voortgang wordt gelogd) of "kijken" (alleen meekijken: alle interactie geblokkeerd via een overlay, snellere poll zodat wijzigingen van de leerkracht vlot doorkomen). */ const PUPIL_WIDGET_CATS = ["taal", "rekenen"]; const PUPIL_POLL_MS = { kijken: 5000, werken: 20000 }; const pupilView = document.getElementById("pupilView"); let pupilPollTimer = null; let pupilLastSig = null; let pupilMode = "werken"; function pupilAllowedDefs(){ return REGISTRY.filter(d => PUPIL_WIDGET_CATS.includes(d.cat)); } function renderPupilWidgets(widgets, mode){ pupilView.innerHTML = ""; const defs = pupilAllowedDefs(); const watch = mode === "kijken"; const usable = widgets .map(w => ({ w, def: defs.find(d => d.id === w.id) })) .filter(x => x.def); if(!usable.length){ const hint = document.createElement("div"); hint.className = "pupil-empty"; hint.textContent = T("pupilEmpty"); pupilView.appendChild(hint); return; } usable.forEach(({ w, def }, idx)=>{ const card = document.createElement("div"); card.className = "widget pupil-card" + (watch ? " watch" : ""); card.dataset.widget = def.id; card.style.width = `min(100%, ${def.w}px)`; card.style.minWidth = "0"; card.style.minHeight = def.h + "px"; const body = document.createElement("div"); body.className = "widget-body"; card.appendChild(body); if(watch){ const badge = document.createElement("div"); badge.className = "pupil-watch-badge"; badge.textContent = "👁 " + T("pupilWatching"); card.appendChild(badge); } pupilView.appendChild(card); /* borden die vóór de invoering van stabiele widget-ids zijn opgeslagen hebben nog geen wid - dan is positie in de lijst de terugval-identiteit, stabiel zolang de leerkracht de widgets op het bord niet herschikt */ const widgetId = w.wid || (def.id + ":" + idx); /* in kijken-modus geen voortgang: de leerling doet zelf niets */ const opts = watch ? { readonly:true } : { readonly:true, onProgress: (p)=>{ api("/my/progress", { method:"POST", body: { widgetId, widgetType: def.id, ...p } }).catch(()=>{}); }}; def.mount(body, w.state || null, opts); }); } async function pupilPoll(){ try{ const res = await api("/my/assignment"); const mode = res.mode === "kijken" ? "kijken" : "werken"; /* modus in de signature zodat een moduswissel ook zonder widget-wijziging een her-render (en dus de juiste overlay) oplevert */ const sig = mode + "|" + JSON.stringify(res.widgets || []); if(sig !== pupilLastSig){ pupilLastSig = sig; renderPupilWidgets(res.widgets || [], mode); } if(mode !== pupilMode){ pupilMode = mode; clearInterval(pupilPollTimer); pupilPollTimer = setInterval(pupilPoll, PUPIL_POLL_MS[mode]); } }catch(e){ /* stille mislukking - volgende poll probeert opnieuw */ } } function startPupilView(){ document.body.classList.add("pupil-mode"); pupilLastSig = null; pupilMode = "werken"; pupilPoll(); clearInterval(pupilPollTimer); pupilPollTimer = setInterval(pupilPoll, PUPIL_POLL_MS[pupilMode]); } function stopPupilView(){ document.body.classList.remove("pupil-mode"); clearInterval(pupilPollTimer); pupilPollTimer = null; pupilView.innerHTML = ""; }