(function () { 'use strict'; var script = document.currentScript || (function () { var scripts = document.getElementsByTagName('script'); return scripts[scripts.length - 1] || null; })(); var service = script && script.dataset ? script.dataset.service : ''; var endpoint = script && script.dataset && script.dataset.endpoint ? script.dataset.endpoint : new URL('../asset-version.php', script ? script.src : window.location.href).toString(); var interval = script && script.dataset && script.dataset.interval ? Number(script.dataset.interval) : 30000; if (!service || window.__assetReloadStarted) return; window.__assetReloadStarted = true; interval = Math.max(15000, Number.isFinite(interval) ? interval : 30000); var storageKey = 'assetVersion:' + service; var reloadKey = 'assetReload:' + service; var running = false; var memoryStore = {}; var lastCheckAt = 0; function cookieName(key) { return key.replace(/[^A-Za-z0-9_-]/g, '_'); } function getCookie(key) { var name = cookieName(key) + '='; return (document.cookie || '').split(';').map(function (part) { return part.trim(); }).reduce(function (found, part) { if (found || part.indexOf(name) !== 0) return found; return decodeURIComponent(part.slice(name.length)); }, ''); } function setCookie(key, value) { document.cookie = cookieName(key) + '=' + encodeURIComponent(value) + '; Path=/; Max-Age=31536000; SameSite=Lax'; } function storeGet(key) { try { return localStorage.getItem(key) || getCookie(key) || memoryStore[key] || ''; } catch (e) { return getCookie(key) || memoryStore[key] || ''; } } function storeSet(key, value) { memoryStore[key] = value; try { localStorage.setItem(key, value); } catch (e) {} try { setCookie(key, value); } catch (e) {} } function sessionGet(key) { try { return sessionStorage.getItem(key) || memoryStore[key] || ''; } catch (e) { return memoryStore[key] || ''; } } function sessionSet(key, value) { memoryStore[key] = value; try { sessionStorage.setItem(key, value); } catch (e) {} } function withTimeout(promise, timeout) { return new Promise(function (resolve) { var done = false; var timer = setTimeout(function () { if (done) return; done = true; resolve(); }, timeout); Promise.resolve(promise).then(function () { if (done) return; done = true; clearTimeout(timer); resolve(); }).catch(function () { if (done) return; done = true; clearTimeout(timer); resolve(); }); }); } function addQuery(url, key, value) { var parsed = new URL(url, window.location.href); parsed.searchParams.set(key, value); return parsed.toString(); } function sameOriginUrl(url) { try { var parsed = new URL(url, window.location.href); return parsed.origin === window.location.origin ? parsed : null; } catch (e) { return null; } } function addAssetToken(element, attr, token) { var current = element && element.getAttribute(attr); var parsed = current ? sameOriginUrl(current) : null; if (!parsed || parsed.searchParams.get('assetReload') === token) return; parsed.searchParams.set('assetReload', token); element.setAttribute(attr, parsed.pathname + parsed.search + parsed.hash); } function applyAssetToken(token) { if (!token) return; document.querySelectorAll('script[src]').forEach(function (element) { addAssetToken(element, 'src', token); }); document.querySelectorAll('link[href]').forEach(function (element) { var rel = (element.getAttribute('rel') || '').toLowerCase(); if (rel.indexOf('stylesheet') === -1 && rel.indexOf('icon') === -1 && rel.indexOf('manifest') === -1) return; addAssetToken(element, 'href', token); }); } function assetTokenFromLocation() { return new URL(window.location.href).searchParams.get('assetReload') || ''; } var currentAssetToken = assetTokenFromLocation(); if (currentAssetToken) { applyAssetToken(currentAssetToken); new MutationObserver(function () { applyAssetToken(currentAssetToken); }).observe(document.documentElement, { childList: true, subtree: true }); } function deleteCaches() { if (!window.caches || !window.caches.keys) return Promise.resolve(); return window.caches.keys().then(function (keys) { return Promise.all(keys.map(function (key) { return window.caches.delete(key); })); }).catch(function () {}); } function reloadWith(version) { var token = version.slice(0, 12); var marker = token + ':' + Math.floor(Date.now() / 10000); if (assetTokenFromLocation() === token) return; if (assetTokenFromLocation() && sessionGet(reloadKey) === marker) return; sessionSet(reloadKey, marker); withTimeout(deleteCaches(), 2500).then(function () { if (navigator.serviceWorker && navigator.serviceWorker.getRegistrations) { navigator.serviceWorker.getRegistrations().then(function (registrations) { registrations.forEach(function (registration) { if (registration && typeof registration.update === 'function') registration.update(); }); }).catch(function () {}); } window.location.replace(addQuery(window.location.href, 'assetReload', token)); }); } function check(force) { if (running || (!force && document.hidden)) return; if (force && Date.now() - lastCheckAt < 1000) return; lastCheckAt = Date.now(); running = true; fetch(addQuery(endpoint, '_', String(Date.now())), { cache: 'no-store', credentials: 'same-origin', headers: { 'Cache-Control': 'no-cache', 'Pragma': 'no-cache' } }).then(function (response) { if (!response.ok) throw new Error('asset version request failed'); return response.json(); }).then(function (data) { if (!data || data.result !== 'ok' || !data.version) return; var token = data.version.slice(0, 12); var previous = storeGet(storageKey); storeSet(storageKey, data.version); if (assetTokenFromLocation() !== token) { reloadWith(data.version); return; } if (previous && previous !== data.version) { reloadWith(data.version); } }).then(function () { running = false; }, function () { running = false; }); } window.addEventListener('pageshow', function () { check(true); setTimeout(function () { check(true); }, 250); setTimeout(function () { check(true); }, 1500); }); window.addEventListener('focus', function () { check(true); }); window.addEventListener('online', function () { check(true); }); window.addEventListener('orientationchange', function () { setTimeout(function () { check(true); }, 500); }); ['pointerdown', 'touchstart', 'click'].forEach(function (eventName) { window.addEventListener(eventName, function () { if (document.hidden || Date.now() - lastCheckAt < 5000) return; check(true); }, { passive: true }); }); document.addEventListener('visibilitychange', function () { if (!document.hidden) check(true); }); setInterval(function () { check(false); }, interval); check(true); })();