teach/public/js/wiki.js
Ramon 9bab7f39c0
All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 39s
feat: koppel widgets aan kerndoelen (v0.4.38-beta)
2026-07-19 21:46:38 +02:00

205 lines
8.4 KiB
JavaScript

/* Curriculumwiki: doorzoekbare volwassenweergave van CURRICULUM_PO_2026. */
"use strict";
(function(){
const root=document.getElementById("curriculumWiki");
let selectedArea="all";
let query="";
const node=(tag,cls,text)=>{
const el=document.createElement(tag);
if(cls)el.className=cls;
if(text!=null)el.textContent=text;
return el;
};
const normal=value=>String(value||"").toLocaleLowerCase("nl-NL");
const coverageKey=value=>value==="partial"?"wikiCoveragePartial":value==="support"?"wikiCoverageSupport":"wikiCoverageOpen";
const widgetName=id=>{
const translated=T("wg_"+id);
return translated==="wg_"+id?id:translated;
};
const goalHaystack=(area,goal)=>normal([
area.title,area.description,goal.id,goal.domain,goal.summary,
...goal.parts,...goal.widgets, ...goal.widgets.map(widgetName)
].join(" "));
function wikiLink(label,href){
const link=node("a","wiki-link",label);
link.href=href;
link.target="_blank";
link.rel="noopener noreferrer";
return link;
}
function drawGoals(holder,filters){
holder.replaceChildren();
const needle=normal(query.trim());
let shown=0;
CURRICULUM_PO_2026.areas.forEach(area=>{
if(selectedArea!=="all"&&selectedArea!==area.id)return;
const areaHit=needle&&normal(area.title+" "+area.description).includes(needle);
const goals=area.goals.filter(goal=>!needle||areaHit||goalHaystack(area,goal).includes(needle));
if(!goals.length)return;
shown+=goals.length;
const section=node("section","wiki-area");
section.id="wiki-area-"+area.id;
const areaHead=node("div","wiki-area-head");
const title=node("h3");
title.appendChild(node("span","wiki-area-icon",area.icon));
title.appendChild(document.createTextNode(area.title));
areaHead.appendChild(title);
areaHead.appendChild(node("span","wiki-range",T("wikiGoalsRange").replace("{range}",area.goalsRange)));
section.appendChild(areaHead);
section.appendChild(node("p","wiki-area-intro",area.description));
const grid=node("div","wiki-grid");
goals.forEach(goal=>{
const card=node("article","wiki-goal");
card.id="wiki-goal-"+goal.id;
const head=node("div","wiki-goal-head");
head.appendChild(node("span","wiki-goal-id",T("wikiGoal")+" "+goal.id));
head.appendChild(node("span","wiki-domain",goal.domain));
card.appendChild(head);
card.appendChild(node("p","wiki-summary",goal.summary));
const partTitle=node("h4",null,T("wikiParts"));
card.appendChild(partTitle);
const parts=node("ul","wiki-parts");
goal.parts.forEach((part,index)=>{
const code=String(goal.id)+String.fromCharCode(65+index);
const item=node("li");
item.appendChild(node("strong",null,code));
item.appendChild(document.createTextNode(" · "+part));
parts.appendChild(item);
});
card.appendChild(parts);
const coverage=node("div","wiki-coverage-row");
coverage.appendChild(node("span","wiki-coverage wiki-coverage-"+goal.coverage,T(coverageKey(goal.coverage))));
if(goal.widgets.length){
const widgets=node("div","wiki-widgets");
widgets.appendChild(node("span","wiki-widgets-label",T("wikiWidgets")+":"));
goal.widgets.forEach(id=>widgets.appendChild(node("span","wiki-widget",widgetName(id))));
coverage.appendChild(widgets);
}
card.appendChild(coverage);
grid.appendChild(card);
});
section.appendChild(grid);
const pageUrl=CURRICULUM_PO_2026.source+"#page="+area.page;
section.appendChild(wikiLink(T("wikiOfficialArea").replace("{area}",area.title),pageUrl));
holder.appendChild(section);
});
if(!shown)holder.appendChild(node("div","wiki-empty",T("wikiNoResults")));
filters.querySelectorAll("button").forEach(button=>button.setAttribute("aria-pressed",String(button.dataset.area===selectedArea)));
}
function renderCurriculumWiki(payload){
if(payload&&payload.area){selectedArea=payload.area;query="";}
root.replaceChildren();
const header=node("div","wiki-hero");
const heroText=node("div","wiki-hero-text");
heroText.appendChild(node("div","wiki-kicker",T("wikiKicker")));
heroText.appendChild(node("h2",null,T("wikiTitle")));
heroText.appendChild(node("p",null,T("wikiIntro")));
header.appendChild(heroText);
const facts=node("div","wiki-facts");
facts.appendChild(node("strong",null,"9"));
facts.appendChild(node("span",null,T("wikiAreas")));
facts.appendChild(node("strong",null,"40"));
facts.appendChild(node("span",null,T("wikiGoals")));
header.appendChild(facts);
root.appendChild(header);
const status=node("aside","wiki-status");
status.appendChild(node("strong",null,T("wikiStatusTitle")));
status.appendChild(node("span",null,T("wikiStatusText")));
status.appendChild(wikiLink(T("wikiOfficialSource"),CURRICULUM_PO_2026.source));
root.appendChild(status);
const tule=node("details","wiki-tule");
const tuleSummary=node("summary",null,T("wikiTuleTitle"));
tule.appendChild(tuleSummary);
tule.appendChild(node("p",null,T("wikiTuleText")));
const sourceLinks=node("div","wiki-source-links");
sourceLinks.appendChild(wikiLink(T("wikiTuleSource"),CURRICULUM_PO_2026.tule));
sourceLinks.appendChild(wikiLink(T("wikiProgressionsSource"),CURRICULUM_PO_2026.progressions));
tule.appendChild(sourceLinks);
root.appendChild(tule);
if(LANG==="en")root.appendChild(node("p","wiki-language-note",T("wikiLanguageNote")));
const searchWrap=node("div","wiki-search");
const label=node("label",null,T("wikiSearchLabel"));
label.htmlFor="wikiGoalSearch";
const input=node("input");
input.type="search";
input.id="wikiGoalSearch";
input.placeholder=T("wikiSearchPlaceholder");
input.autocomplete="off";
input.value=query;
searchWrap.appendChild(label);
searchWrap.appendChild(input);
root.appendChild(searchWrap);
const filters=node("div","wiki-filters");
filters.setAttribute("aria-label",T("wikiAreaFilter"));
const all=node("button",null,T("wikiAllAreas"));
all.type="button";
all.dataset.area="all";
filters.appendChild(all);
CURRICULUM_PO_2026.areas.forEach(area=>{
const button=node("button",null,area.icon+" "+area.title);
button.type="button";
button.dataset.area=area.id;
filters.appendChild(button);
});
root.appendChild(filters);
const holder=node("div","wiki-results");
root.appendChild(holder);
filters.addEventListener("click",event=>{
const button=event.target.closest("button[data-area]");
if(!button)return;
selectedArea=button.dataset.area;
drawGoals(holder,filters);
holder.scrollIntoView({block:"nearest"});
});
input.addEventListener("input",()=>{
query=input.value;
drawGoals(holder,filters);
});
drawGoals(holder,filters);
if(payload&&payload.goal)requestAnimationFrame(()=>{
const target=document.getElementById("wiki-goal-"+payload.goal);
if(target){target.classList.add("wiki-goal-focus");target.scrollIntoView({block:"center"});}
});
const disclaimer=node("footer","wiki-disclaimer");
disclaimer.appendChild(node("strong",null,T("wikiCarefulTitle")));
disclaimer.appendChild(document.createTextNode(" "+T("wikiCarefulText")));
root.appendChild(disclaimer);
}
window.renderCurriculumWiki=renderCurriculumWiki;
registerSettingsSection({
id:"curriculum",icon:"📚",group:"personal",order:3,
label:()=>T("wikiTitle"),sub:()=>T("wikiSub"),
visible:()=>!!currentUser&&can("curriculum.view"),
activate(payload){showSettingsDom("curriculum");renderCurriculumWiki(payload);},
keywords:()=>[
T("wikiTitle"),T("wikiSub"),"SLO","kerndoelen","curriculum","leerlijnen","TULE",
...CURRICULUM_PO_2026.areas.flatMap(area=>[area.title,area.description])
],
searchItems:needle=>{
const q=normal(needle);
return CURRICULUM_PO_2026.areas.flatMap(area=>{
const areaMatch=normal(area.title+" "+area.description).includes(q);
const goalMatch=area.goals.some(goal=>goalHaystack(area,goal).includes(q));
if(!areaMatch&&!goalMatch)return[];
return[{icon:area.icon,label:area.title,sub:T("wikiGoal")+" "+area.goalsRange,
go:()=>goSettingsSection("curriculum",{area:area.id})}];
});
}
});
})();