All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 31s
182 lines
6.9 KiB
JavaScript
182 lines
6.9 KiB
JavaScript
/* teach - herbruikbare plaatjeskiezer (bibliotheek / emoji / ARASAAC / upload).
|
|
Bouwt voort op dezelfde bouwstenen als de woordkaart-editor in letters.js
|
|
(EMOJI_CATS, arasaacSearch/arasaacUrl, setPic, dezelfde CSS-klassen) i.p.v.
|
|
een tweede plaatjessysteem te maken. Gebruikt door widgets die snel een los
|
|
plaatje willen laten kiezen zonder de volledige woordkaart-editor te openen
|
|
(bv. Ankerwoorden, als snelkoppeling vanaf een woord zonder automatisch plaatje). */
|
|
"use strict";
|
|
let pickerWrap = null, pickerCat = 0, pickerOnSelect = null;
|
|
|
|
function choosePic(pic){
|
|
if(pickerOnSelect) pickerOnSelect(pic);
|
|
closePicPicker();
|
|
}
|
|
function closePicPicker(){
|
|
if(pickerWrap) pickerWrap.classList.remove("open");
|
|
pickerOnSelect = null;
|
|
}
|
|
|
|
function ensurePicPicker(){
|
|
if(pickerWrap) return pickerWrap;
|
|
const wrap = document.createElement("div");
|
|
wrap.className = "modalwrap";
|
|
wrap.innerHTML = `
|
|
<div class="modal">
|
|
<div class="am-head">
|
|
<h2 data-i18n="pickPic"></h2>
|
|
<button class="wclose pp-close">✕</button>
|
|
</div>
|
|
<div class="ed-tabs">
|
|
<button type="button" data-t="emoji"></button>
|
|
<button type="button" data-t="picto"></button>
|
|
<button type="button" data-t="upload"></button>
|
|
<button type="button" data-t="library"></button>
|
|
</div>
|
|
<div class="ed-pane">
|
|
<div class="ed-p-emoji">
|
|
<div class="ed-cats"></div>
|
|
<div class="ed-grid"></div>
|
|
</div>
|
|
<div class="ed-p-picto" style="display:none;">
|
|
<div class="ed-pictorow">
|
|
<input type="text" class="ed-psearch" maxlength="30">
|
|
<button class="tbtn ed-pgo"></button>
|
|
</div>
|
|
<div class="ed-status"></div>
|
|
<div class="ed-pgrid"></div>
|
|
<div class="ed-credit"></div>
|
|
</div>
|
|
<div class="ed-p-upload" style="display:none;">
|
|
<label class="ed-upload"><span class="ed-uplbl"></span><input type="file" accept="image/*"></label>
|
|
<div class="ed-uphint"></div>
|
|
</div>
|
|
<div class="ed-p-library" style="display:none;">
|
|
<button class="tbtn ed-open-library" type="button"></button>
|
|
<p class="ed-library-hint"></p>
|
|
</div>
|
|
</div>
|
|
</div>`;
|
|
document.body.appendChild(wrap);
|
|
pickerWrap = wrap;
|
|
const q = s => wrap.querySelector(s);
|
|
|
|
wrap.addEventListener("click", e=>{ if(e.target===wrap) closePicPicker(); });
|
|
q(".pp-close").addEventListener("click", closePicPicker);
|
|
|
|
let tab = "emoji";
|
|
function setTab(t){ tab = t; refreshTabs(); }
|
|
function applyLabels(){
|
|
q(".ed-uplbl").textContent = T("upload");
|
|
q(".ed-uphint").textContent = T("upHint");
|
|
q(".ed-credit").innerHTML = T("pictoCredit");
|
|
q(".ed-pgo").textContent = T("pictoSearch");
|
|
q(".ed-psearch").placeholder = T("pictoPh");
|
|
q(".ed-open-library").textContent = "🗂 "+T("imgOpenLibrary");
|
|
q(".ed-library-hint").textContent = T("imgLanguageHint");
|
|
q(".pp-close").title = T("close");
|
|
refreshTabs();
|
|
}
|
|
function refreshTabs(){
|
|
wrap.querySelectorAll(".ed-tabs button").forEach(b=>{
|
|
b.textContent = T("tab"+b.dataset.t[0].toUpperCase()+b.dataset.t.slice(1));
|
|
b.classList.toggle("active", b.dataset.t===tab);
|
|
});
|
|
q(".ed-p-emoji").style.display = tab==="emoji" ? "block" : "none";
|
|
q(".ed-p-picto").style.display = tab==="picto" ? "block" : "none";
|
|
q(".ed-p-upload").style.display = tab==="upload" ? "block" : "none";
|
|
q(".ed-p-library").style.display = tab==="library" ? "block" : "none";
|
|
}
|
|
wrap.querySelectorAll(".ed-tabs button").forEach(b=>{
|
|
b.addEventListener("click", ()=>{ tab = b.dataset.t; refreshTabs(); });
|
|
});
|
|
|
|
function renderCats(){
|
|
const cats = q(".ed-cats");
|
|
cats.innerHTML = "";
|
|
T("cats").forEach((name,i)=>{
|
|
const b = document.createElement("button");
|
|
b.type = "button"; b.textContent = name;
|
|
b.classList.toggle("active", i===pickerCat);
|
|
b.addEventListener("click", ()=>{ pickerCat=i; renderCats(); });
|
|
cats.appendChild(b);
|
|
});
|
|
const grid = q(".ed-grid");
|
|
grid.innerHTML = "";
|
|
EMOJI_CATS[pickerCat].forEach(em=>{
|
|
const b = document.createElement("button");
|
|
b.type = "button"; b.textContent = em;
|
|
b.addEventListener("click", ()=>choosePic(em));
|
|
grid.appendChild(b);
|
|
});
|
|
}
|
|
|
|
async function searchPictos(){
|
|
const term = q(".ed-psearch").value.trim();
|
|
if(!term) return;
|
|
q(".ed-status").textContent = T("pictoLoad");
|
|
q(".ed-pgrid").innerHTML = "";
|
|
try{
|
|
const arr = await arasaacSearch(term, LANG);
|
|
if(!arr.length){ q(".ed-status").textContent = T("pictoNone"); return; }
|
|
q(".ed-status").textContent = "";
|
|
arr.slice(0,12).forEach(p=>{
|
|
const url = arasaacUrl(p._id);
|
|
const b = document.createElement("button");
|
|
b.type = "button";
|
|
const im = document.createElement("img");
|
|
im.src = url; im.loading = "lazy"; im.alt = term;
|
|
b.appendChild(im);
|
|
b.addEventListener("click", ()=>choosePic(url));
|
|
q(".ed-pgrid").appendChild(b);
|
|
});
|
|
}catch(e){ q(".ed-status").textContent = T("pictoErr"); }
|
|
}
|
|
q(".ed-pgo").addEventListener("click", searchPictos);
|
|
q(".ed-psearch").addEventListener("keydown", e=>{ if(e.key==="Enter") searchPictos(); });
|
|
q(".ed-open-library").addEventListener("click", ()=>{
|
|
openImageCatalog((src,image)=>choosePic(image?.value||src));
|
|
});
|
|
|
|
q(".ed-p-upload input").addEventListener("change", async e=>{
|
|
const f = e.target.files[0]; if(!f) return;
|
|
e.target.value = "";
|
|
if(currentUser){
|
|
const hint=q(".ed-uphint"),old=hint.textContent;
|
|
hint.textContent=T("imgUploading");
|
|
try{
|
|
const image=await uploadImageToCatalog(f,{folder:"Taal/Mijn woordkaarten"});
|
|
choosePic(image.src);
|
|
}catch(err){hint.textContent=err.message;setTimeout(()=>{hint.textContent=old},3500)}
|
|
return;
|
|
}
|
|
const img = new Image();
|
|
img.onload = ()=>{
|
|
const c = document.createElement("canvas");
|
|
const s = Math.min(1, 128/Math.max(img.width, img.height));
|
|
c.width = Math.round(img.width*s); c.height = Math.round(img.height*s);
|
|
c.getContext("2d").drawImage(img, 0, 0, c.width, c.height);
|
|
choosePic(c.toDataURL("image/png"));
|
|
URL.revokeObjectURL(img.src);
|
|
};
|
|
img.src = URL.createObjectURL(f);
|
|
});
|
|
|
|
wrap.__applyLabels = applyLabels;
|
|
wrap.__renderCats = renderCats;
|
|
wrap.__searchPictos = searchPictos;
|
|
wrap.__setTab = setTab;
|
|
return wrap;
|
|
}
|
|
|
|
function openPicPicker(word, onSelect){
|
|
const wrap = ensurePicPicker();
|
|
pickerOnSelect = onSelect;
|
|
wrap.__applyLabels();
|
|
wrap.__renderCats();
|
|
wrap.querySelector(".ed-psearch").value = word || "";
|
|
/* Bij een woord staat de herbruikbare, thematisch ingedeelde bibliotheek
|
|
voorop. Zonder account blijft de bestaande online pictozoeker beschikbaar. */
|
|
wrap.__setTab(word ? (currentUser ? "library" : "picto") : "emoji");
|
|
wrap.classList.add("open");
|
|
if(word && !currentUser) wrap.__searchPictos();
|
|
}
|