fishies-ui/src/fx-image.ts
2026-10-31 08:35:11 +00:00

24 lines
1.6 KiB
TypeScript

export type FxState = 'wait' | 'fade' | 'ready' | 'error'
let alternative: (src: string) => string | null = () => null
export function configureImageFallback(find: (src: string) => string | null): void { alternative = find }
export const imageFallback = (src: string): string | null => alternative(src)
export function reveal(img: HTMLImageElement, instant?: boolean): void {
if (img.getAttribute('data-fx') !== 'wait' || !img.complete) return
const src = img.currentSrc || img.src
const set = (state: string) => {
if (img.getAttribute('data-fx') === 'wait' && (img.currentSrc || img.src) === src) img.setAttribute('data-fx', state)
}
if (!img.naturalWidth) { set('error'); return }
if (instant) { set('ready'); return }
if (typeof img.decode !== 'function') { set('fade'); return }
img.decode().then(() => set('fade'), () => set(img.naturalWidth ? 'fade' : 'error'))
}
export const FX_IMAGE_SCRIPT = `(function(){var r=${reveal.toString()};` +
`var p=/(\\/game\\/[^?#\\s]+)\\.png(?=[?#\\s]|$)/g;` +
`function w(t){if(t.getAttribute('data-webp-tried'))return false;var s=t.getAttribute('src')||'';if(!/\\/game\\/[^?#]+\\.png/.test(s))return false;` +
`t.setAttribute('data-webp-tried','1');var ss=t.getAttribute('srcset');if(ss)t.setAttribute('srcset',ss.replace(p,'$1.webp'));t.setAttribute('src',s.replace(p,'$1.webp'));return true}` +
`function h(e){var t=e.target;if(!t||t.tagName!=='IMG')return;if(e.type==='error'&&w(t))return;if(t.hasAttribute('data-fx'))r(t)}` +
`document.addEventListener('load',h,true);document.addEventListener('error',h,true)})()`