(function () { 'use strict'; const versions = Object.freeze({ app: '0.12.14', jquery: '4.0.0', jqueryUi: '1.14.2' }); const steps = ['storage', 'jquery', 'jquery-ui', 'modules', 'server', 'routes', 'location']; const stepLabels = Object.freeze({ get storage() { return globalThis.Wegwichtel.I18n.t("bootstrap-loader.gespeicherte.inhalte.prufen"); }, get jquery() { return globalThis.Wegwichtel.I18n.t("bootstrap-loader.wegwichtel.vorbereiten"); }, get 'jquery-ui'() { return globalThis.Wegwichtel.I18n.t("bootstrap-loader.die.bedienung.vorbereiten"); }, get modules() { return globalThis.Wegwichtel.I18n.t("bootstrap-loader.die.app.vorbereiten"); }, get server() { return globalThis.Wegwichtel.I18n.t("bootstrap-loader.verbindung.prufen"); }, get routes() { return globalThis.Wegwichtel.I18n.t("bootstrap-loader.strecken.laden"); }, get location() { return globalThis.Wegwichtel.I18n.t("bootstrap.location"); } }); const screen = document.getElementById('bootstrap-screen'); const progress = document.getElementById('bootstrap-progress'); const errorBox = document.getElementById('bootstrap-error'); const retry = document.getElementById('bootstrap-retry'); const enter = document.getElementById('bootstrap-enter'); const readyText = document.getElementById('bootstrap-ready'); const cleanupStatus = document.getElementById('storage-cleanup-status'); const actionStatus = document.getElementById('bootstrap-action-status'); const statusText = document.getElementById('bootstrap-status-text'); const androidBrowserHint = document.getElementById('android-browser-hint'); let ready = false; let statusTransition = 0; const completedSteps = new Set(); const versioned = path => `${path}${path.includes('?') ? '&' : '?'}v=${encodeURIComponent(versions.app)}`; function updateAndroidBrowserHint() { if (!androidBrowserHint) return; const userAgent = globalThis.navigator?.userAgent || ''; const platform = globalThis.navigator?.userAgentData?.platform || ''; const isAndroid = /Android/i.test(`${userAgent} ${platform}`); if (!isAndroid) { androidBrowserHint.hidden = true; return; } const isChrome = /Chrome\//i.test(userAgent) && !/(?:EdgA|OPR|SamsungBrowser)\//i.test(userAgent); androidBrowserHint.hidden = false; androidBrowserHint.dataset.browser = isChrome ? 'chrome' : 'other'; androidBrowserHint.textContent = isChrome ? globalThis.Wegwichtel.I18n.t("bootstrap-loader.auf.diesem.gerat.kannst.du.bilder.und") : globalThis.Wegwichtel.I18n.t("bootstrap-loader.tipp.fur.android.mit.chrome.lassen.sich"); } function schedule(callback, delay = 0) { if (typeof globalThis.setTimeout === 'function') { return globalThis.setTimeout(callback, delay); } callback(); return null; } function setStatusText(text, immediate = false) { if (!statusText) return; statusTransition += 1; const transition = statusTransition; if (immediate) { statusText.textContent = text; statusText.classList.remove('is-fading'); return; } statusText.classList.add('is-fading'); schedule(() => { if (transition !== statusTransition) return; statusText.textContent = text; statusText.classList.remove('is-fading'); }, 180); } function nextPendingStep() { return steps.find(step => !completedSteps.has(step)); } function announceStep(step) { if (stepLabels[step]) setStatusText(stepLabels[step]); } function mark(step, state) { if (!steps.includes(step)) return; const item = document.querySelector(`[data-step="${step}"]`); item?.classList?.remove('done', 'failed'); if (state === 'done') completedSteps.add(step); else completedSteps.delete(step); item?.classList?.add(state); if (progress) progress.value = completedSteps.size; if (state === 'failed') { setStatusText(globalThis.Wegwichtel.I18n.t("bootstrap.step.failed", { value1: stepLabels[step] || step })); return; } if (state === 'done') { const next = nextPendingStep(); if (next) announceStep(next); } } function loadScript(src, test) { return new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = versioned(src); script.async = false; script.onload = () => { if (test && !test()) reject(new Error(globalThis.Wegwichtel.I18n.t("bootstrap-loader.ein.teil.der.app.konnte.nicht.starten"))); else resolve(); }; script.onerror = () => reject(new Error(globalThis.Wegwichtel.I18n.t("bootstrap-loader.ein.teil.der.app.konnte.nicht.geladen"))); document.head.appendChild(script); }); } function initializeJqueryUi() { const $ = globalThis.jQuery; $('#bootstrap-retry').button({ icon: 'ui-icon-refresh' }); $('#bootstrap-enter').button(); $('.back-button').button(); $('#clear-route-search').button({ icon: 'ui-icon-close', showLabel: false }); $('#slide-prev').button(); $('#slide-next').button(); } function updateCleanupProgress(removed, total) { cleanupStatus.textContent = globalThis.Wegwichtel.I18n.t("bootstrap-loader.alten.fortschritt.loschen", { value1: removed, value2: total }); cleanupStatus.hidden = false; } async function cleanupOldProgress() { cleanupStatus.hidden = true; await globalThis.Wegwichtel.PrivacyStorage.cleanupExpired(updateCleanupProgress); } function isActivation(event) { if (event.type === 'keydown') return event.key === 'Enter' || event.key === ' '; if (event.type !== 'pointerup') return false; if (event.isPrimary === false) return false; return event.pointerType !== 'mouse' || event.button === 0; } function openApplication(event) { if (!ready || globalThis.Wegwichtel.OfflineCache?.busy || !isActivation(event)) return; if (event.target !== enter && event.target.closest('button, input, label, a, dialog')) return; if (event.target.closest('.offline-help, .storage-usage')) return; event.preventDefault(); event.stopPropagation?.(); screen.hidden = true; document.getElementById('app-shell').hidden = false; globalThis.Wegwichtel.App.navigate('#routes-page', { replace: true }); } function showReadyState() { ready = true; screen.setAttribute('aria-busy', 'false'); screen.classList.add('ready'); readyText.hidden = false; setStatusText(globalThis.Wegwichtel.I18n.t("bootstrap.ready")); actionStatus?.classList.add('is-leaving'); enter.hidden = false; const showEnter = () => enter.classList.add('is-visible'); if (typeof globalThis.requestAnimationFrame === 'function') { globalThis.requestAnimationFrame(showEnter); } else { schedule(showEnter); } schedule(() => { if (actionStatus) actionStatus.hidden = true; }, 220); enter.focus(); } async function boot() { ready = false; completedSteps.clear(); if (progress) progress.value = 0; screen.setAttribute('aria-busy', 'true'); screen.classList.remove('ready'); readyText.hidden = true; enter.hidden = true; enter.classList.remove('is-visible'); errorBox.hidden = true; retry.hidden = true; if (actionStatus) { actionStatus.hidden = false; actionStatus.classList.remove('is-leaving'); } try { await globalThis.Wegwichtel.OfflineCache?.initialize(); setStatusText(stepLabels.storage, true); await cleanupOldProgress(); mark('storage', 'done'); await loadScript( `vendor/jquery/jquery-${versions.jquery}.min.js`, () => globalThis.jQuery?.fn?.jquery === versions.jquery ); mark('jquery', 'done'); await loadScript( `vendor/jquery-ui/jquery-ui-${versions.jqueryUi}.min.js`, () => globalThis.jQuery?.ui?.version === versions.jqueryUi ); initializeJqueryUi(); mark('jquery-ui', 'done'); for (const module of ['config', 'api-client', 'distance', 'geolocation', 'orientation', 'slideshow', 'audio-player', 'vibration', 'app']) { await loadScript(`js/${module}.js`, () => Boolean(globalThis.Wegwichtel)); } mark('modules', 'done'); await globalThis.Wegwichtel.App.initialize({ markStep: mark }); showReadyState(); } catch (error) { console.error(error); const current = nextPendingStep(); if (current) mark(current, 'failed'); errorBox.textContent = globalThis.Wegwichtel.UserMessages?.error(error, globalThis.Wegwichtel.I18n.t("bootstrap-loader.wegwichtel.konnte.nicht.starten.prufe.deine.verbindung")) || globalThis.Wegwichtel.I18n.t("bootstrap-loader.wegwichtel.konnte.nicht.starten.bitte.versuche.es"); errorBox.hidden = false; retry.hidden = false; } } function retryBoot(event) { if (!isActivation(event)) return; event.preventDefault(); event.stopPropagation(); location.reload(); } retry.addEventListener('pointerup', retryBoot); retry.addEventListener('keydown', retryBoot); enter.addEventListener('pointerup', openApplication); enter.addEventListener('keydown', openApplication); screen.addEventListener('pointerup', openApplication); updateAndroidBrowserHint(); boot(); }());