52 lines
3.1 KiB
HTML
52 lines
3.1 KiB
HTML
<!doctype html><html><head><meta charset="utf-8">
|
|||
|
|
<link rel="stylesheet" href="./engine.css">
|
||
|
|
<style>body{padding:1.5rem;max-width:44rem;margin:0 auto}</style>
|
||
|
|
</head><body>
|
||
|
|
<section class="card">
|
||
|
|
<h2>Languages on the front page</h2>
|
||
|
|
<p class="hint" id="opLangCount"></p>
|
||
|
|
<div class="row">
|
||
|
|
<input id="opLangFilter" type="search" placeholder="Filter languages…" autocomplete="off">
|
||
|
|
<label class="oprow"><input type="checkbox" id="opLangVoiceOnly"><span>With a voice only</span></label>
|
||
|
|
<button class="btn" id="opLangNone">Turn all off</button>
|
||
|
|
</div>
|
||
|
|
<div id="opLangList" class="langlist"></div>
|
||
|
|
<label class="oprow"><input type="checkbox" id="opAllowAll" checked><span>Let listeners pick any language</span></label>
|
||
|
|
<p class="hint" id="opAllowAllHint">On — all 104 languages are offered. 32 of them have a voice; the rest show captions only.</p>
|
||
|
|
</section>
|
||
|
|
<script src="./languages.js"></script><script src="./voice-catalog.js"></script>
|
||
|
|
<script>
|
||
|
|
/* Same DOM the renderer builds, against the real catalogs. */
|
||
|
|
const $=(id)=>document.getElementById(id);
|
||
|
|
const opConfig={featured:["spa_Latn","zho_Hans","por_Latn","por_PT","fra_Latn","kor_Hang","vie_Latn","hat_Latn","arb_Arab"],allowAllLanguages:true};
|
||
|
|
function render(){
|
||
|
|
const box=$('opLangList'), q=($('opLangFilter').value||'').trim().toLowerCase();
|
||
|
|
const voiceOnly=$('opLangVoiceOnly').checked;
|
||
|
|
const on=new Set(opConfig.featured), spoken=new Set(VoiceCatalog.languages());
|
||
|
|
const codes=Languages.codes().slice().sort((a,b)=>(Languages.get(a).name||a).localeCompare(Languages.get(b).name||b));
|
||
|
|
box.textContent=''; let shown=0;
|
||
|
|
for(const code of codes){
|
||
|
|
const l=Languages.get(code)||{name:code,native:code}, has=spoken.has(code);
|
||
|
|
if(voiceOnly&&!has) continue;
|
||
|
|
if(q&&(l.name+' '+l.native+' '+code).toLowerCase().indexOf(q)===-1) continue;
|
||
|
|
shown++;
|
||
|
|
const row=document.createElement('label'); row.className='langrow'+(has?'':' novoice');
|
||
|
|
const cb=document.createElement('input'); cb.type='checkbox'; cb.checked=on.has(code);
|
||
|
|
cb.addEventListener('change',()=>{cb.checked?opConfig.featured.push(code):opConfig.featured.splice(opConfig.featured.indexOf(code),1);count();});
|
||
|
|
row.appendChild(cb);
|
||
|
|
const nm=document.createElement('span'); nm.className='lname'; nm.textContent=l.name; row.appendChild(nm);
|
||
|
|
const nat=document.createElement('span'); nat.className='lsub'; nat.textContent=l.native===l.name?'':l.native; row.appendChild(nat);
|
||
|
|
const tg=document.createElement('span'); tg.className='ltag'; tg.textContent=has?'voice':'captions only'; row.appendChild(tg);
|
||
|
|
box.appendChild(row);
|
||
|
|
}
|
||
|
|
if(!shown){const p=document.createElement('p');p.className='hint';p.textContent='Nothing matches that.';box.appendChild(p);}
|
||
|
|
count();
|
||
|
|
}
|
||
|
|
function count(){$('opLangCount').textContent=opConfig.featured.length+' of '+Languages.codes().length+
|
||
|
|
' on. These are what a listener sees first — the rest stay reachable by search.';}
|
||
|
|
$('opLangFilter').addEventListener('input',render);
|
||
|
|
$('opLangVoiceOnly').addEventListener('change',render);
|
||
|
|
$('opLangNone').addEventListener('click',()=>{opConfig.featured.length=0;render();});
|
||
|
|
render();
|
||
|
|
</script></body></html>
|