Verbeter grafische kwaliteit van kleurplaten (v0.4.67-beta) #5
5 changed files with 106 additions and 6 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
0.4.39-beta
|
||||
0.4.40-beta
|
||||
|
|
|
|||
|
|
@ -1310,6 +1310,15 @@
|
|||
.role-preview-note{max-width:760px;margin:0 auto 14px;padding:11px 14px;border:1px solid var(--orange);border-radius:12px;background:color-mix(in srgb,var(--orange) 16%,var(--surface));color:var(--ink);font-size:13px;line-height:1.45}
|
||||
body.role-preview-active #parentView button:disabled,body.role-preview-active #parentView input:disabled,body.role-preview-active #parentView select:disabled{opacity:.55;cursor:not-allowed}
|
||||
body.role-preview-pupil #pupilView .widget-body{pointer-events:none;user-select:none}
|
||||
|
||||
.role-preview-note .role-preview-add-widget{display:flex;margin-top:9px}
|
||||
.role-preview-widget-picker{width:min(760px,94vw);max-height:88vh;overflow:auto}
|
||||
.role-preview-widget-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px;margin-top:12px}
|
||||
.role-preview-widget-card{width:100%;display:grid;grid-template-columns:50px minmax(0,1fr);align-items:center;gap:10px;padding:11px;border:1px solid var(--line);border-radius:14px;background:var(--surface);color:var(--ink);text-align:left;cursor:pointer}
|
||||
.role-preview-widget-card:hover,.role-preview-widget-card:focus-visible{border-color:var(--accent);outline:2px solid var(--accent-soft)}
|
||||
.role-preview-widget-card .gi{font-size:30px;text-align:center}.role-preview-widget-card>span:last-child{min-width:0}.role-preview-widget-card .gn,.role-preview-widget-card .gd{display:block}.role-preview-widget-card .gd{margin-top:3px;color:var(--muted);font-size:11px;line-height:1.35}
|
||||
body.role-preview-updating #board{visibility:hidden}
|
||||
@media(max-width:560px){.role-preview-widget-grid{grid-template-columns:1fr}}
|
||||
body.tb-left #rolePreviewBanner,body.tb-right #rolePreviewBanner{top:8px}
|
||||
@media(max-width:720px){.vw-role-block .vw-row{align-items:stretch;flex-direction:column}.vw-role-seg{max-width:none;justify-content:flex-start}#rolePreviewBanner{max-width:calc(100vw - 24px);white-space:nowrap}#rolePreviewBanner strong{display:none}}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"use strict";
|
||||
/* version — shown until /api/version resolves (or if the fetch fails, e.g. offline).
|
||||
Kept in sync by hand with the VERSION file at the repo root on every release. */
|
||||
const VERSION = "0.4.39-beta";
|
||||
const VERSION = "0.4.40-beta";
|
||||
(function(){
|
||||
const tag = document.getElementById("verTag");
|
||||
tag.textContent = "v"+VERSION;
|
||||
|
|
@ -289,6 +289,8 @@ const I18N = {
|
|||
vwPreview:"Voorbeeldweergave", vwPreviewReset:"Terug naar systeem",
|
||||
vwParentPreview:"Voorbeeld van het ouderportaal. Echte kindgegevens en acties zijn in deze weergave uitgeschakeld.",
|
||||
vwPupilPreview:"Voorbeeld van de leerlingomgeving met de taal- en rekenwidgets van het huidige bord. Bediening en voortgang zijn uitgeschakeld.",
|
||||
vwPupilAddWidget:"Widget toevoegen", vwPupilChooseWidget:"Kies een leerlingwidget",
|
||||
vwPupilAddWidgetNote:"Alleen taal- en rekenwidgets die in de leerlingomgeving werken worden getoond.",
|
||||
vwNote:"Deze voorkeuren gelden voor dit apparaat.",
|
||||
pwChanged:"Wachtwoord gewijzigd ✓", pwCurrentPh:"huidig wachtwoord",
|
||||
namePh:"naam", passPh:"wachtwoord",
|
||||
|
|
@ -667,6 +669,8 @@ const I18N = {
|
|||
vwPreview:"Preview mode", vwPreviewReset:"Return to system",
|
||||
vwParentPreview:"Preview of the parent portal. Real child data and actions are disabled in this view.",
|
||||
vwPupilPreview:"Preview of the pupil environment using language and maths widgets from the current board. Controls and progress are disabled.",
|
||||
vwPupilAddWidget:"Add widget", vwPupilChooseWidget:"Choose a pupil widget",
|
||||
vwPupilAddWidgetNote:"Only language and maths widgets supported in the pupil environment are shown.",
|
||||
vwNote:"These preferences apply to this device.",
|
||||
pwChanged:"Password changed ✓", pwCurrentPh:"current password",
|
||||
namePh:"name", passPh:"password",
|
||||
|
|
|
|||
|
|
@ -14,6 +14,78 @@
|
|||
parent:"vwRoleParent",pupil:"vwRolePupil"
|
||||
};
|
||||
let renderSequence=0;
|
||||
let pupilWidgetPicker=null;
|
||||
|
||||
function closePupilWidgetPicker(){
|
||||
if(pupilWidgetPicker)pupilWidgetPicker.classList.remove("open");
|
||||
}
|
||||
function openPupilWidgetPicker(){
|
||||
if(!isSystemManager()||activeRole()!=="pupil")return;
|
||||
if(!pupilWidgetPicker){
|
||||
pupilWidgetPicker=document.createElement("div");
|
||||
pupilWidgetPicker.className="modalwrap";
|
||||
pupilWidgetPicker.id="pupilPreviewWidgetPicker";
|
||||
pupilWidgetPicker.setAttribute("role","dialog");
|
||||
pupilWidgetPicker.setAttribute("aria-modal","true");
|
||||
pupilWidgetPicker.addEventListener("click",event=>{
|
||||
if(event.target===pupilWidgetPicker)closePupilWidgetPicker();
|
||||
});
|
||||
document.body.appendChild(pupilWidgetPicker);
|
||||
}
|
||||
const modal=document.createElement("div");
|
||||
modal.className="modal role-preview-widget-picker";
|
||||
const head=document.createElement("div");
|
||||
head.className="gallery-head";
|
||||
const title=document.createElement("h2");
|
||||
title.id="pupilPreviewWidgetTitle";
|
||||
title.textContent=T("vwPupilChooseWidget");
|
||||
const close=document.createElement("button");
|
||||
close.type="button";close.className="wclose";close.textContent="✕";
|
||||
close.title=T("close");close.setAttribute("aria-label",T("close"));
|
||||
close.addEventListener("click",closePupilWidgetPicker);
|
||||
head.append(title,close);modal.appendChild(head);
|
||||
const note=document.createElement("p");
|
||||
note.className="guestnote";note.textContent=T("vwPupilAddWidgetNote");
|
||||
modal.appendChild(note);
|
||||
const host=document.createElement("div");
|
||||
pupilAllowedDefs().forEach(def=>{
|
||||
const card=document.createElement("button");
|
||||
card.type="button";card.className="gcard role-preview-widget-card";
|
||||
const icon=document.createElement("span");
|
||||
icon.className="gi";icon.textContent=def.icon;
|
||||
const text=document.createElement("span");
|
||||
const name=document.createElement("strong");
|
||||
name.className="gn";name.textContent=T("wg_"+def.id);
|
||||
const desc=document.createElement("small");
|
||||
desc.className="gd";desc.textContent=T("wg_"+def.id+"_d");
|
||||
text.append(name,desc);card.append(icon,text);
|
||||
card.addEventListener("click",()=>addPupilPreviewWidget(def));
|
||||
host.appendChild(card);
|
||||
});
|
||||
host.className="role-preview-widget-grid";
|
||||
modal.appendChild(host);
|
||||
pupilWidgetPicker.setAttribute("aria-labelledby",title.id);
|
||||
pupilWidgetPicker.replaceChildren(modal);
|
||||
pupilWidgetPicker.classList.add("open");
|
||||
close.focus();
|
||||
}
|
||||
async function addPupilPreviewWidget(def){
|
||||
if(!isSystemManager()||activeRole()!=="pupil"||!pupilAllowedDefs().includes(def))return;
|
||||
closePupilWidgetPicker();
|
||||
const previewRole=activeRole();
|
||||
document.body.classList.add("role-preview-updating");
|
||||
stopPupilView();
|
||||
setActiveViewRole("super");
|
||||
try{
|
||||
makeWidget(def);
|
||||
await doSave();
|
||||
}finally{
|
||||
setActiveViewRole(previewRole);
|
||||
document.body.classList.remove("role-preview-updating");
|
||||
renderPreviewSurface();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const isSystemManager=()=>!!currentUser&¤tUser.role==="super";
|
||||
const roleLabel=role=>T(ROLE_KEYS[role]||ROLE_KEYS.super);
|
||||
|
|
@ -39,6 +111,7 @@
|
|||
renderSequence++;
|
||||
document.body.classList.remove("role-preview-active","role-preview-parent","role-preview-pupil");
|
||||
banner.hidden=true;
|
||||
closePupilWidgetPicker();
|
||||
if(isSystemManager()){
|
||||
stopPupilView();
|
||||
stopParentView();
|
||||
|
|
@ -60,6 +133,7 @@
|
|||
const sequence=++renderSequence;
|
||||
if(!isSystemManager()){clearPreviewSurface();syncControls();return;}
|
||||
const role=activeRole();
|
||||
closePupilWidgetPicker();
|
||||
document.body.classList.remove("role-preview-active","role-preview-parent","role-preview-pupil");
|
||||
stopPupilView();
|
||||
stopParentView();
|
||||
|
|
@ -74,7 +148,13 @@
|
|||
const snapshot=serializeBoard();
|
||||
await renderPupilWidgets(snapshot.widgets||[],"kijken",true);
|
||||
if(sequence!==renderSequence)return;
|
||||
pupilView.prepend(previewNotice(T("vwPupilPreview")));
|
||||
const note=previewNotice(T("vwPupilPreview"));
|
||||
const add=document.createElement("button");
|
||||
add.type="button";add.className="tbtn role-preview-add-widget";
|
||||
add.textContent="+ "+T("vwPupilAddWidget");
|
||||
add.addEventListener("click",openPupilWidgetPicker);
|
||||
note.appendChild(add);
|
||||
pupilView.prepend(note);
|
||||
}
|
||||
syncControls();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,22 +38,27 @@ test('Weergave bevat de vijf rollen en laadt de veilige voorbeeldmodule vóór d
|
|||
assert.match(preview,/renderParentView\(\[\]\)/);
|
||||
assert.match(preview,/renderPupilWidgets\(snapshot\.widgets\|\|\[\],"kijken",true\)/);
|
||||
assert.match(preview,/querySelectorAll\("button,input,select,textarea"\)/);
|
||||
assert.match(preview,/pupilAllowedDefs\(\)\.forEach/);
|
||||
assert.match(preview,/pupilAllowedDefs\(\)\.includes\(def\)/);
|
||||
assert.match(preview,/setActiveViewRole\("super"\)[\s\S]*?makeWidget\(def\)[\s\S]*?await doSave\(\)/);
|
||||
assert.match(preview,/role-preview-add-widget/);
|
||||
assert.doesNotMatch(preview,/currentUser\.role\s*=(?!=)/);
|
||||
assert.doesNotMatch(preview,/api\(/);
|
||||
assert.match(css,/body\.role-preview-pupil #pupilView \.widget-body\{pointer-events:none/);
|
||||
for(const key of ['vwRole','vwRoleSystem','vwRoleAdmin','vwRoleTeacher','vwRoleParent','vwRolePupil','vwRoleNote','vwPreviewReset']){
|
||||
for(const key of ['vwRole','vwRoleSystem','vwRoleAdmin','vwRoleTeacher','vwRoleParent','vwRolePupil','vwRoleNote','vwPreviewReset','vwPupilAddWidget','vwPupilChooseWidget','vwPupilAddWidgetNote']){
|
||||
assert.equal((core.match(new RegExp(key+':','g'))||[]).length,2,key);
|
||||
}
|
||||
assert.ok(core.includes('const VERSION = "'+version.trim()+'"'));
|
||||
});
|
||||
|
||||
test('voorbeeldrol begrenst clientmenu’s maar verandert serverpermissies niet',async()=>{
|
||||
const [client,server,settings,admin,explorer]=await Promise.all([
|
||||
const [client,server,settings,admin,explorer,pupil]=await Promise.all([
|
||||
readFile('public/js/permissions.js','utf8'),
|
||||
readFile('src/permissions.js','utf8'),
|
||||
readFile('public/js/settings.js','utf8'),
|
||||
readFile('public/js/admin.js','utf8'),
|
||||
readFile('public/js/explorer.js','utf8')
|
||||
readFile('public/js/explorer.js','utf8'),
|
||||
readFile('public/js/pupil.js','utf8')
|
||||
]);
|
||||
assert.match(client,/function activeRoles\(\)/);
|
||||
assert.doesNotMatch(server,/VIEW_AS_ROLE|activeRole/);
|
||||
|
|
@ -61,4 +66,6 @@ test('voorbeeldrol begrenst clientmenu’s maar verandert serverpermissies niet'
|
|||
assert.match(admin,/activeRoles\(\)\.flatMap/);
|
||||
assert.match(admin,/show:\(\)=>activeRole\(\)==="super"/);
|
||||
assert.match(explorer,/activeRole\(\) === "pupil"/);
|
||||
assert.match(pupil,/async function renderPupilWidgets\(widgets, mode, preview=false\)/);
|
||||
assert.match(pupil,/if\(!preview\)await Promise\.all/);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue