(preAuthState)
| 1858 | |
| 1859 | // ---------- HEAVY BOOT ---------- |
| 1860 | async function bootHeavy(preAuthState) { |
| 1861 | if (window.__FR_FLAGS.bootPromise) return window.__FR_FLAGS.bootPromise; |
| 1862 | window.__FR_FLAGS.bootPromise = (async () => { |
| 1863 | if (window.__FR_FLAGS.booted) return; // no-op if somehow set |
| 1864 | window.__FR_FLAGS.booted = true; |
| 1865 | ensureToastReady(); |
| 1866 | // show chrome |
| 1867 | |
| 1868 | const hb = document.querySelector('.header-buttons'); if (hb) hb.style.visibility = 'visible'; |
| 1869 | const ov = document.getElementById('loadingOverlay'); if (ov) ov.style.display = 'flex'; |
| 1870 | |
| 1871 | try { |
| 1872 | // 0) refresh auth snapshot (once) |
| 1873 | let state = preAuthState || {}; |
| 1874 | try { |
| 1875 | if (!state || !Object.keys(state).length) { |
| 1876 | const r = await fetch('/api/auth/checkAuth.php', { credentials: 'include' }); |
| 1877 | state = await r.json(); |
| 1878 | } |
| 1879 | if (state && state.username) localStorage.setItem('username', state.username); |
| 1880 | if (typeof state.isAdmin !== 'undefined') localStorage.setItem('isAdmin', state.isAdmin ? '1' : '0'); |
| 1881 | window.__FR_AUTH_STATE = state; |
| 1882 | } catch (e) { } |
| 1883 | |
| 1884 | // authed → heavy boot path |
| 1885 | document.body.classList.add('authed'); |
| 1886 | |
| 1887 | // 1) i18n (safe) |
| 1888 | // i18n: honor saved language first, then apply translations |
| 1889 | try { |
| 1890 | const i18n = await import(withBase('/js/i18n.js?v={{APP_QVER}}')).catch(async (err) => { |
| 1891 | console.error('[boot] import i18n.js failed (versioned)', err && err.message, err && err.sourceURL); |
| 1892 | return import(withBase('/js/i18n.js')); |
| 1893 | }); |
| 1894 | let saved = 'en'; |
| 1895 | try { saved = localStorage.getItem('language') || 'en'; } catch (e) { } |
| 1896 | let appliedLocale = saved; |
| 1897 | if (typeof i18n.setLocale === 'function') { appliedLocale = await i18n.setLocale(saved); } |
| 1898 | if (typeof i18n.applyTranslations === 'function') { i18n.applyTranslations(); } |
| 1899 | try { document.documentElement.setAttribute('lang', appliedLocale); } catch (e) { } |
| 1900 | } catch (e) { |
| 1901 | console.error('[boot] i18n import/apply failed', e && e.message, e && e.sourceURL); |
| 1902 | } |
| 1903 | // 2) core app — **initialize exactly once** (this calls initUpload/initFileActions/loadFolderTree/etc.) |
| 1904 | const app = await import(withBase('/js/appCore.js?v={{APP_QVER}}')).catch(async (err) => { |
| 1905 | console.error('[boot] import appCore.js failed (versioned)', err && err.message, err && err.sourceURL); |
| 1906 | return import(withBase('/js/appCore.js')); |
| 1907 | }); |
| 1908 | if (!window.__FR_FLAGS.initialized) { |
| 1909 | if (typeof app.loadCsrfToken === 'function') await app.loadCsrfToken(); |
| 1910 | if (typeof app.initializeApp === 'function') app.initializeApp(); |
| 1911 | const darkBtn = document.getElementById('darkModeToggle'); |
| 1912 | if (darkBtn) { |
| 1913 | darkBtn.removeAttribute('hidden'); |
| 1914 | darkBtn.style.setProperty('display', 'inline-flex', 'important'); // beats any CSS |
| 1915 | darkBtn.style.visibility = ''; // just in case |
| 1916 | } |
| 1917 | const link = document.createElement('link'); |
no test coverage detected