1/** 2 * Global dashboard services that must stay alive across SPA navigations 3 * (music player, voice chat, listening party, casino invites, etc.). 4 */ 5(function (global) { 6 'use strict'; 7 8 var initPromise = null; 9 10 function loadScriptOnce(src) { 11 return new Promise(function (resolve, reject) { 12 if (document.querySelector('script[src="' + src + '"]')) { 13 resolve(); 14 return; 15 } 16 var s = document.createElement('script'); 17 s.src = src; 18 s.async = false; 19 s.onload = function () { resolve(); }; 20 s.onerror = function () { reject(new Error('Failed to load ' + src)); }; 21 document.body.appendChild(s); 22 }); 23 } 24 25 function ensureVcOverlayStack() { 26 if (typeof global.ensureSpaVcOverlayLoaded === 'function') { 27 return global.ensureSpaVcOverlayLoaded(); 28 } 29 return loadScriptOnce('/scripts/effects/spaVcOverlayShell.js') 30 .then(function () { 31 return loadScriptOnce('/scripts/effects/spaVcOverlay.js'); 32 }) 33 .then(function () { 34 if (global.SpaVcOverlay && typeof global.SpaVcOverlay.init === 'function') { 35 global.SpaVcOverlay.init(); 36 } 37 }); 38 } 39 40 function ensureListeningParty() { 41 return loadScriptOnce('/scripts/effects/listeningParty.js').then(function () { 42 if (global.ListeningParty && typeof global.ListeningParty.boot === 'function') { 43 return global.ListeningParty.boot(); 44 } 45 }); 46 } 47 48 function ensureStaleRoomSweeper() { 49 return loadScriptOnce('/scripts/dependencies/staleRoomSweeper.js') 50 .then(function () { 51 if (global.StaleRoomSweeper && typeof global.StaleRoomSweeper.runIfDue === 'function') { 52 return global.StaleRoomSweeper.runIfDue(); 53 } 54 }) 55 .catch(function (err) { 56 console.warn('[spaGlobalServices] stale room sweeper failed', err); 57 }); 58 } 59 60 function bootReport(fraction, label) { 61 if (global.CitrusBoot && typeof global.CitrusBoot.reportBoot === 'function') { 62 global.CitrusBoot.reportBoot('services', fraction, label); 63 } 64 } 65 66 function ensureGlobalDashboardServices(deps) { 67 if (!deps || typeof deps.ensureMusicPlayer !== 'function') { 68 return Promise.resolve(); 69 } 70 if (initPromise) return initPromise; 71 72 bootReport(0, 'Loading voice chat overlay...'); 73 74 var overlayReady = ensureVcOverlayStack().catch(function (err) { 75 console.warn('[spaGlobalServices] VC overlay preload failed', err); 76 }); 77 78 initPromise = overlayReady 79 .then(function () { 80 bootReport(0.12, 'Loading music player...'); 81 return deps.ensureMusicPlayer(); 82 }) 83 .then(function () { 84 bootReport(0.42, 'Starting voice chat...'); 85 if (typeof deps.ensureGlobalVoice === 'function') { 86 return deps.ensureGlobalVoice(); 87 } 88 }) 89 .then(function () { 90 bootReport(0.58, 'Starting voice overlay...'); 91 return ensureVcOverlayStack(); 92 }) 93 .then(function () { 94 bootReport(0.68, 'Starting listening party...'); 95 return ensureListeningParty(); 96 }) 97 .then(function () { 98 bootReport(0.82, 'Starting casino invites...'); 99 if (typeof deps.ensureCasinoInviteSystem === 'function') { 100 return deps.ensureCasinoInviteSystem(); 101 } 102 }) 103 .then(function () { 104 bootReport(0.92, 'Running room sweeper...'); 105 return ensureStaleRoomSweeper(); 106 }) 107 .catch(function (err) { 108 initPromise = null; 109 console.warn('[spaGlobalServices]', err); 110 }); 111 112 return initPromise; 113 } 114 115 global.SpaGlobalServices = { 116 ensure: ensureGlobalDashboardServices, 117 ensureVcOverlay: ensureVcOverlayStack, 118 reset: function () { 119 initPromise = null; 120 } 121 }; 122})(typeof window !== 'undefined' ? window : this);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.