All checks were successful
dev - build & deploy naar test / build-and-deploy (push) Successful in 8s
107 lines
3.9 KiB
JavaScript
107 lines
3.9 KiB
JavaScript
/* widget: Foto & video */
|
|
/* =========================================================
|
|
Media widget — photos and videos from external sites
|
|
==========================================================*/
|
|
function mountMedia(root, initState){
|
|
let cur = null;
|
|
root.innerHTML = `
|
|
<div class="media">
|
|
<div class="media-bar">
|
|
<input type="text" class="m-url" spellcheck="false">
|
|
<button class="tbtn m-go"></button>
|
|
<button class="tbtn ghost m-ext">↗</button>
|
|
</div>
|
|
<div class="media-stage"><div class="media-msg"></div></div>
|
|
</div>`;
|
|
const urlInp = root.querySelector(".m-url"),
|
|
goBtn = root.querySelector(".m-go"),
|
|
extBtn = root.querySelector(".m-ext"),
|
|
stage = root.querySelector(".media-stage");
|
|
|
|
function labels(){
|
|
urlInp.placeholder = T("mediaPh");
|
|
goBtn.textContent = T("mediaShow");
|
|
extBtn.title = T("mediaOpen");
|
|
const msg = stage.querySelector(".media-msg");
|
|
if(msg) msg.textContent = T(msg.dataset.err ? "mediaErr" : "mediaEmpty");
|
|
}
|
|
function showMsg(err){
|
|
stage.innerHTML = "";
|
|
const m = document.createElement("div");
|
|
m.className = "media-msg";
|
|
if(err) m.dataset.err = "1";
|
|
m.textContent = T(err ? "mediaErr" : "mediaEmpty");
|
|
stage.appendChild(m);
|
|
}
|
|
function show(raw){
|
|
let url = raw.trim();
|
|
if(!url){ showMsg(false); return; }
|
|
if(!/^https?:\/\//i.test(url)) url = "https://"+url;
|
|
let node = null;
|
|
const yt = url.match(/(?:youtube\.com\/(?:watch\?[^#]*v=|shorts\/|embed\/|live\/)|youtu\.be\/)([\w-]{6,})/);
|
|
const vi = url.match(/vimeo\.com\/(?:video\/)?(\d+)/);
|
|
if(yt){
|
|
/* show the thumbnail first (always works); play attempts the embed */
|
|
const id = yt[1];
|
|
stage.innerHTML = "";
|
|
const wrap = document.createElement("div");
|
|
wrap.className = "media-yt";
|
|
const im = document.createElement("img");
|
|
im.src = "https://i.ytimg.com/vi/"+id+"/hqdefault.jpg"; im.alt = "";
|
|
const pb = document.createElement("button");
|
|
pb.className = "media-play"; pb.textContent = "▶";
|
|
pb.addEventListener("click", ()=>{
|
|
const f = document.createElement("iframe");
|
|
f.src = "https://www.youtube.com/embed/"+id+"?rel=0&autoplay=1";
|
|
f.referrerPolicy = "strict-origin-when-cross-origin";
|
|
f.allow = "autoplay; encrypted-media; picture-in-picture";
|
|
f.allowFullscreen = true;
|
|
stage.innerHTML = "";
|
|
stage.appendChild(f);
|
|
});
|
|
wrap.appendChild(im); wrap.appendChild(pb);
|
|
stage.appendChild(wrap);
|
|
cur = url; urlInp.value = url;
|
|
return;
|
|
}
|
|
if(vi){
|
|
node = document.createElement("iframe");
|
|
node.src = "https://player.vimeo.com/video/"+vi[1];
|
|
node.allow = "autoplay; fullscreen; picture-in-picture";
|
|
node.allowFullscreen = true;
|
|
}else if(/\.(jpe?g|png|gif|webp|svg|avif)([?#]|$)/i.test(url)){
|
|
node = document.createElement("img");
|
|
node.src = url; node.alt = "";
|
|
node.addEventListener("error", ()=>showMsg(true));
|
|
}else if(/\.(mp4|webm|ogg|mov)([?#]|$)/i.test(url)){
|
|
node = document.createElement("video");
|
|
node.src = url; node.controls = true;
|
|
node.addEventListener("error", ()=>showMsg(true));
|
|
}
|
|
if(node){
|
|
stage.innerHTML = "";
|
|
stage.appendChild(node);
|
|
cur = url;
|
|
urlInp.value = url;
|
|
}else{
|
|
showMsg(true);
|
|
}
|
|
}
|
|
goBtn.addEventListener("click", ()=>show(urlInp.value));
|
|
extBtn.addEventListener("click", ()=>{
|
|
let u = (cur || urlInp.value).trim();
|
|
if(!u) return;
|
|
if(!/^https?:\/\//i.test(u)) u = "https://"+u;
|
|
window.open(u, "_blank");
|
|
});
|
|
urlInp.addEventListener("keydown", e=>{
|
|
e.stopPropagation();
|
|
if(e.key==="Enter") show(urlInp.value);
|
|
});
|
|
document.addEventListener("langchange", labels);
|
|
if(initState && initState.url){ urlInp.value = initState.url; show(initState.url); }
|
|
else showMsg(false);
|
|
labels();
|
|
return { getState: ()=>({url: cur || ""}) };
|
|
}
|
|
|