const MszLoadingIcon = function() { const element =
; for(let i = 0; i < 9; ++i) element.appendChild(); // this is moderately cursed but it'll do const blocks = [ element.children[3], element.children[0], element.children[1], element.children[2], element.children[5], element.children[8], element.children[7], element.children[6], ]; let tsLastUpdate; let counter = 0; let playing = false; let delay = 50; let playResolve; let pauseResolve; const update = tsCurrent => { try { if(tsLastUpdate !== undefined && (tsCurrent - tsLastUpdate) < delay) return; tsLastUpdate = tsCurrent; for(let i = 0; i < blocks.length; ++i) blocks[(counter + i) % blocks.length].classList.toggle('msz-loading-icon-block-hidden', i < 3); ++counter; } finally { if(playResolve) try { playResolve(); } finally { playResolve = undefined; playing = true; } if(pauseResolve) try { pauseResolve(); } finally { pauseResolve = undefined; playing = false; } if(playing) requestAnimationFrame(update); } }; const play = () => { return new Promise(resolve => { if(playing || playResolve) { resolve(); return; } playResolve = resolve; requestAnimationFrame(update); }); }; const pause = () => { return new Promise(resolve => { if(!playing || pauseResolve) { resolve(); return; } pauseResolve = resolve; }); }; const stop = async () => { await pause(); counter = 0; }; const restart = async () => { await stop(); await play(); }; const reverse = () => { blocks.reverse(); }; const setBlock = (num, state=null) => { element.children[num].classList.toggle('msz-loading-icon-block-hidden', !state); }; const batsu = () => { setBlock(0, true);setBlock(1, false);setBlock(2, true); setBlock(3, false);setBlock(4, true);setBlock(5, false); setBlock(6, true);setBlock(7, false);setBlock(8, true); }; const maru = () => { setBlock(0, true);setBlock(1, true);setBlock(2, true); setBlock(3, true);setBlock(4, false);setBlock(5, true); setBlock(6, true);setBlock(7, true);setBlock(8, true); }; return { get element() { return element; }, get playing() { return playing; }, get delay() { return delay; }, set delay(value) { if(typeof value !== 'number') value = parseFloat(value); if(isNaN(value) || !isFinite(value)) return; if(value < 0) value = Math.abs(value); delay = value; }, play, pause, stop, restart, reverse, batsu, maru, }; }; const MszLoading = function(options=null) { if(typeof options !== 'object') throw 'options must be an object'; let { element, size, colour, width, height, inline, containerWidth, containerHeight, gap, margin, hidden, } = options ?? {}; if(typeof element === 'string') element = document.querySelector(element); if(!(element instanceof HTMLElement)) element = ; if(!element.classList.contains('msz-loading')) element.classList.add('msz-loading'); if(inline) element.classList.add('msz-loading-inline'); if(hidden) element.classList.add('hidden'); if(typeof size === 'number' && size > 0) element.style.setProperty('--msz-loading-size', size); if(typeof containerWidth === 'string') element.style.setProperty('--msz-loading-container-width', containerWidth); if(typeof containerHeight === 'string') element.style.setProperty('--msz-loading-container-height', containerHeight); if(typeof gap === 'string') element.style.setProperty('--msz-loading-gap', gap); if(typeof margin === 'string') element.style.setProperty('--msz-loading-margin', margin); if(typeof width === 'string') element.style.setProperty('--msz-loading-width', width); if(typeof height === 'string') element.style.setProperty('--msz-loading-height', height); if(typeof colour === 'string') element.style.setProperty('--msz-loading-colour', colour); let icon; if(element.childElementCount < 1) { icon = new MszLoadingIcon; icon.play(); element.appendChild(