All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 41s
58 lines
4.3 KiB
JavaScript
58 lines
4.3 KiB
JavaScript
/* widget: zinsbouwer met aanpasbare woordbanken */
|
||
function mountSentence(root, initState){
|
||
const defaults=LANG==='nl' ? {
|
||
who:['De hond','Mijn vriend','De juf','Sara'], does:['lees','speelt','maakt','ziet'],
|
||
what:['een boek','op het plein','een mooie tekening','de rode bal'],
|
||
} : {
|
||
who:['The dog','My friend','The teacher','Sarah'], does:['reads','plays','makes','sees'],
|
||
what:['a book','in the playground','a beautiful drawing','the red ball'],
|
||
};
|
||
const S={banks:JSON.parse(JSON.stringify(initState?.banks||defaults)),sentence:[...(initState?.sentence||[])]};
|
||
root.innerHTML=`
|
||
<div class="sb">
|
||
<div class="sb-sentence" aria-live="polite"></div>
|
||
<div class="sb-banks"></div>
|
||
<div class="sb-add">
|
||
<select class="sb-kind"><option value="who"></option><option value="does"></option><option value="what"></option></select>
|
||
<input class="sb-word" type="text" maxlength="40">
|
||
<button class="tbtn ghost sb-add-btn" type="button">+</button>
|
||
</div>
|
||
<div class="sb-actions"><button class="tbtn ghost sb-surprise" type="button"></button><button class="tbtn ghost sb-back" type="button">↶</button><button class="tbtn ghost sb-clear" type="button"></button><button class="tbtn sb-speak" type="button"></button></div>
|
||
</div>`;
|
||
const q=s=>root.querySelector(s), sentenceEl=q('.sb-sentence'), banksEl=q('.sb-banks'), kind=q('.sb-kind'), word=q('.sb-word');
|
||
function sentenceText(){ return S.sentence.map(x=>x.word).join(' ').replace(/\s+([,.!?])/g,'$1'); }
|
||
function renderSentence(){
|
||
sentenceEl.innerHTML="";
|
||
if(!S.sentence.length){ sentenceEl.textContent=T('sentenceHint'); sentenceEl.classList.add('empty'); return; }
|
||
sentenceEl.classList.remove('empty');
|
||
S.sentence.forEach(part=>{const span=document.createElement('span');span.className='sb-part '+part.kind;span.textContent=part.word;sentenceEl.appendChild(span);});
|
||
}
|
||
function renderBanks(){
|
||
banksEl.innerHTML="";
|
||
['who','does','what'].forEach(k=>{
|
||
const group=document.createElement('section'); group.className='sb-bank '+k;
|
||
const h=document.createElement('h3'); h.textContent=T('sentence_'+k); group.appendChild(h);
|
||
const chips=document.createElement('div'); chips.className='sb-chips';
|
||
S.banks[k].forEach((w,i)=>{
|
||
const wrap=document.createElement('span'); wrap.className='sb-chip-wrap';
|
||
const chip=document.createElement('button'); chip.type='button'; chip.className='sb-chip'; chip.textContent=w;
|
||
chip.addEventListener('click',()=>{S.sentence.push({kind:k,word:w});renderSentence();});
|
||
const remove=document.createElement('button'); remove.type='button'; remove.className='sb-chip-remove'; remove.textContent='×'; remove.title=T('sentenceRemove');
|
||
remove.addEventListener('click',()=>{S.banks[k].splice(i,1);renderBanks();}); wrap.append(chip,remove); chips.appendChild(wrap);
|
||
});
|
||
group.appendChild(chips); banksEl.appendChild(group);
|
||
});
|
||
}
|
||
function addWord(){const w=word.value.trim();if(!w)return;S.banks[kind.value].push(w);word.value='';renderBanks();}
|
||
q('.sb-add-btn').addEventListener('click',addWord); word.addEventListener('keydown',e=>{e.stopPropagation();if(e.key==='Enter')addWord();});
|
||
q('.sb-back').addEventListener('click',()=>{S.sentence.pop();renderSentence();});
|
||
q('.sb-clear').addEventListener('click',()=>{S.sentence=[];renderSentence();});
|
||
q('.sb-surprise').addEventListener('click',()=>{S.sentence=['who','does','what'].filter(k=>S.banks[k].length).map(kind=>({kind,word:S.banks[kind][Math.floor(Math.random()*S.banks[kind].length)]}));renderSentence();sndGood();confetti(sentenceEl)});
|
||
q('.sb-speak').addEventListener('click',()=>{const text=sentenceText();if(text&&'speechSynthesis'in window){speechSynthesis.cancel();const u=new SpeechSynthesisUtterance(text);u.lang=LANG==='nl'?'nl-NL':'en-GB';speechSynthesis.speak(u);}});
|
||
function labels(){
|
||
[...kind.options].forEach(o=>o.textContent=T('sentence_'+o.value)); word.placeholder=T('sentenceAdd');
|
||
q('.sb-surprise').textContent=T('sentenceSurprise');q('.sb-clear').textContent=T('sentenceClear'); q('.sb-speak').textContent=T('sentenceSpeak'); renderSentence();renderBanks();
|
||
}
|
||
document.addEventListener('langchange',labels);labels();
|
||
return {getState:()=>({banks:S.banks,sentence:S.sentence})};
|
||
}
|