export default class QuizImagePreloader { constructor() { this.isPreloading = false this.preloadedImages = new Map() } init() { // Start preloading on initial page load document.addEventListener('DOMContentLoaded', () => { sessionStorage.removeItem('quiz_images_preloaded') // this.startPreloadingFromHeader() // console.info('startPreloadingFromHeader'); }) // Continue preloading on Turbo navigation document.addEventListener('turbo:load', () => { this.startPreloadingFromHeader() console.info('startPreloadingFromHeader'); }) } startPreloadingFromHeader() { if (sessionStorage.getItem('quiz_images_preloaded') === 'true') { return } // Skip if already preloading if (this.isPreloading) { return } const imageUrls = this.getImageUrlsFromHeader() if (imageUrls.length > 0) { this.preloadImages(imageUrls) } } getImageUrlsFromHeader() { const headerElement = document.querySelector('header[data-quiz-images]') || document.querySelector('[data-quiz-images]') if (!headerElement) return [] try { const urls = JSON.parse(headerElement.dataset.quizImages || '[]') return urls.filter(url => url && url.trim()) } catch (e) { console.warn('Failed to parse quiz image URLs from header:', e) return [] } } preloadImages(imageUrls) { this.isPreloading = true let loadedCount = 0 const totalImages = imageUrls.length imageUrls.forEach((url, index) => { // Skip if already preloaded if (this.preloadedImages.has(url)) { loadedCount++ if (loadedCount === totalImages) { this.onPreloadComplete() } return } const img = new Image() img.onload = () => { this.preloadedImages.set(url, img) loadedCount++ if (loadedCount === totalImages) { this.onPreloadComplete() } } img.onerror = () => { console.warn(`Failed to preload image: ${url}`) loadedCount++ if (loadedCount === totalImages) { this.onPreloadComplete() } } // Stagger requests to avoid overwhelming server setTimeout(() => { img.src = url }, index * 30) }) } onPreloadComplete() { this.isPreloading = false sessionStorage.setItem('quiz_images_preloaded', 'true') console.info('PreloadComplete'); // Dispatch completion event for components that need to know document.dispatchEvent(new CustomEvent('quiz:preload:complete', { detail: { totalImages: this.preloadedImages.size } })) } // Check if preloading is complete isComplete() { return sessionStorage.getItem('quiz_images_preloaded') === 'true' } }