#include elem.js #include xhr.js const MakaiSiteHeaderImages = function() { const url = '/header-bgs.json'; let headers; const all = async () => { if(!Array.isArray(headers)) headers = (await $x.get('/header-bgs.json')).json(); return headers; }; return { all: all, random: async () => { const images = await all(); if(images.length < 1) return '/flonnerator.png'; return images[Math.floor(Math.random() * images.length)]; }, }; }; const MakaiSiteHeader = function(element) { if(!(element instanceof Element)) throw 'element must be an instance of Element'; const images = new MakaiSiteHeaderImages; const bgElem = element.querySelector('.js-header-background'); const getBgImgElem = () => bgElem.querySelector('img'); const setBackgroundImage = (url, duration) => { return new Promise((resolve, reject) => { if(typeof duration !== 'number') duration = 500; while(bgElem.childElementCount > 1) bgElem.removeChild(bgElem.lastChild); const prevImage = getBgImgElem(); if(prevImage.src === url) { resolve(); return; } let startTimeStamp; const updateTransition = timeStamp => { if(startTimeStamp === undefined) startTimeStamp = timeStamp; const elapsed = timeStamp - startTimeStamp; const t = Math.min(1, Math.max(0, elapsed / duration)); prevImage.style.opacity = 1 - t; if(t < 1) requestAnimationFrame(updateTransition); else { $r(prevImage); resolve(); } }; prevImage.style.zIndex = '2'; const nextImage = $e({ tag: 'img', attrs: { alt: url, src: url, onerror: () => { prevImage.style.opacity = null; prevImage.style.zIndex = null; bgElem.removeChild(nextImage); reject(); }, onload: () => { requestAnimationFrame(updateTransition); }, }, style: { zIndex: '1' }, }); bgElem.appendChild(nextImage); }); }; return { get images() { return images; }, get backgroundElement() { return bgElem; }, get backgroundImage() { return getBgImgElem().src; }, setBackgroundImage: setBackgroundImage, randomBackgroundImage: async () => { await setBackgroundImage(await images.random()); }, }; };