(function() { 'use strict'; // Core module bundle loaded synchronously in main.html. // This loader only handles version cache-busting, splash, terminal init, and optional ext modules. const LATEST_VER = 'v4.6.77'; const CACHE = '?v=' + LATEST_VER; const stored = localStorage.getItem('webx11_cache_ver'); if (stored !== LATEST_VER) { localStorage.setItem('webx11_cache_ver', LATEST_VER); } function setSplash(phase, current, total, filename) { const fill = document.getElementById('splash-progress-fill'); const phaseEl = document.getElementById('splash-phase'); const fileEl = document.getElementById('splash-filename'); if (fill && total > 0) { fill.style.width = Math.round((current / total) * 100) + '%'; } if (phaseEl) phaseEl.textContent = phase; if (fileEl) fileEl.textContent = filename || ''; } function hideSplash() { const overlay = document.getElementById('splash-overlay'); if (overlay) { overlay.classList.add('hidden'); setTimeout(() => { overlay.style.display = 'none'; }, 350); } } function showSplashError(msg) { const el = document.getElementById('splash-error'); const fill = document.getElementById('splash-progress-fill'); if (el) { el.textContent = msg; el.classList.add('show'); } if (fill) fill.style.background = 'var(--error-color)'; } // Create webx11 synchronously so critical-ext-bundle.js (loaded right after us) // can call registerModule() without waiting for DOMContentLoaded const webx11 = new WebX11Terminal(); window.webx11 = webx11; async function init() { try { const total = 3; let count = 0; setSplash('Core bundle loaded (1/3)', ++count, total, 'core-bundle.js'); setSplash('Critical ext bundle loaded (2/3)', ++count, total, 'critical-ext-bundle.js'); setSplash('Initializing terminal (3/3)', total, total, ''); // webx11 already created synchronously above — just init ext modules if (typeof webx11._loadExtModules === 'function') { let extKeys = ['calc', 'voice', 'debug-panel', 'cron', 'theme', 'wpm', 'mindmap', 'webdav', 'skill-pack-core', 'cryptogzip', 'tutorial', 'floating', 'console', 'media', 'three', 'kanban', 'course']; const saved = localStorage.getItem('webx11_startup_modules'); let selected = null; try { if (saved) selected = JSON.parse(saved); } catch (e) {} if (selected && Array.isArray(selected)) { extKeys = extKeys.filter(k => selected.includes(k + '.js')); } let disabledMods = []; try { disabledMods = JSON.parse(localStorage.getItem('webx11_module_disabled') || '[]'); } catch (e) {} extKeys = extKeys.filter(k => !disabledMods.includes(k)); if (extKeys.length > 0) { setTimeout(() => webx11._loadExtModules(extKeys), 800); } } hideSplash(); console.log('[ModuleLoader] Core loader initialized'); } catch (err) { console.error('[ModuleLoader] Fatal error:', err); showSplashError('Loading failed — ' + err.message); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();