PageSourceSearch

https://pupwife.com/scripts/desktop/citrusShellBoot.js

js pupwife.com collected 2026-09-30 15:05:04 UTC 10,026 bytes, 223 lines download raw bytes

1/**
2 * CitrusOS shell services — settings, routes, global cursor (once, not per window).
3 */
4(function (global) {
5    'use strict';
6
7    function bootReport(track, fraction, label) {
8        if (global.CitrusBoot && typeof global.CitrusBoot.reportBoot === 'function') {
9            global.CitrusBoot.reportBoot(track, fraction, label);
10        }
11    }
12
13    function bootFinalize(track, label) {
14        if (global.CitrusBoot && typeof global.CitrusBoot.finalizeBootTrack === 'function') {
15            global.CitrusBoot.finalizeBootTrack(track, label);
16        }
17    }
18
19    function shellScriptLabel(src) {
20        if (!src || typeof src !== 'string') return 'Loading shell modules...';
21        if (src.indexOf('firebase-app') !== -1 || src.indexOf('firebase-database') !== -1) {
22            return 'Connecting Firebase...';
23        }
24        if (src.indexOf('firebaseConfig') !== -1) return 'Connecting Firebase... OK';
25        if (src.indexOf('sharedUsername') !== -1) return 'Loading account services...';
26        if (src.indexOf('settingsMenu') !== -1) return 'Loading settings menu...';
27        if (src.indexOf('spaRouteManifest') !== -1) return 'Registering app routes...';
28        if (src.indexOf('spaNav') !== -1) return 'Loading navigation...';
29        if (src.indexOf('citrusWindowLoader') !== -1) return 'Starting window manager...';
30        if (src.indexOf('ensureSiteFontAwesome') !== -1) return 'Loading icons...';
31        if (src.indexOf('scriptLoadOnce') !== -1) return 'Loading core modules...';
32        if (src.indexOf('resolveSiteAssetUrl') !== -1) return 'Resolving asset paths...';
33        if (src.indexOf('siteThemePalettes') !== -1) return 'Loading theme palettes...';
34        if (src.indexOf('citrusDirectMountRoutes') !== -1) return 'Mounting desktop apps...';
35        if (src.indexOf('chatroomRouteAssets') !== -1) return 'Loading chatroom assets...';
36        return null;
37    }
38
39    function reportShellStep(stepIndex, totalSteps, src) {
40        if (!totalSteps) return;
41        var fraction = stepIndex / totalSteps;
42        var label = shellScriptLabel(src) || ('Loading shell modules (' + stepIndex + '/' + totalSteps + ')...');
43        bootReport('shell', fraction, label);
44    }
45
46    function markScriptLoaded(src) {
47        var el = document.querySelector('script[src="' + src + '"]');
48        if (el) el.dataset.spaLoaded = '1';
49    }
50
51    function isShellScriptAlreadyReady(src) {
52        if (src.indexOf('siteThemePalettes.js') !== -1 && global.SiteThemePalettes) {
53            return true;
54        }
55        if (src.indexOf('firebase-app-compat') !== -1 && global.firebase) {
56            return true;
57        }
58        if (src.indexOf('firebase-database-compat') !== -1 &&
59            global.firebase && typeof global.firebase.database === 'function') {
60            return true;
61        }
62        if (src.indexOf('firebaseConfig.js') !== -1 &&
63            typeof global.ensureFirebaseApp === 'function' &&
64            global.firebase && global.firebase.apps && global.firebase.apps.length) {
65            return true;
66        }
67        return false;
68    }
69
70    function loadScript(src) {
71        if (isShellScriptAlreadyReady(src)) {
72            markScriptLoaded(src);
73            return Promise.resolve();
74        }
75        if (global.PupwifeScriptLoad && typeof global.PupwifeScriptLoad.once === 'function') {
76            return global.PupwifeScriptLoad.once(src);
77        }
78        return new Promise(function (resolve, reject) {
79            if (document.querySelector('script[src="' + src + '"]')) {
80                resolve();
81                return;
82            }
83            var s = document.createElement('script');
84            s.src = src;
85            s.async = false;
86            s.onload = function () { resolve(); };
87            s.onerror = function () { reject(new Error('Failed to load ' + src)); };
88            document.body.appendChild(s);
89        });
90    }
91
92    function ensureStylesheet(href) {
93        if (document.querySelector('link[href="' + href + '"]')) return;
94        var link = document.createElement('link');
95        link.rel = 'stylesheet';
96        link.href = href;
97        document.head.appendChild(link);
98    }
99
100    var SHELL_CTX_MENU_V = 'citrus-ctx-20260927a';
101
102    function boot() {
103        if (!document.body || !document.body.classList.contains('page-citrusos')) return;
104
105        var shellScripts = [
106            '/scripts/effects/spaGlobalServices.js',
107            'https://www.gstatic.com/firebasejs/9.22.0/firebase-app-compat.js',
108            'https://www.gstatic.com/firebasejs/9.22.0/firebase-database-compat.js',
109            '/scripts/dependencies/firebaseConfig.js',
110            '/scripts/dependencies/sharedUsername.js',
111            '/scripts/dependencies/accountIndicator.js',
112            '/scripts/dependencies/accountPage.js',
113            '/scripts/dependencies/perfModeToggle.js',
114            '/scripts/effects/siteThemePalettes.js',
115            '/scripts/effects/settingsMenu.js',
116            '/scripts/effects/settingsTabs.js',
117            '/scripts/desktop/citrusSettingsWindow.js',
118            '/scripts/effects/siteAudio.js',
119            '/scripts/desktop/citrusDirectMountRoutes.js?v=citrus-daw-20260907',
120            '/projects/chatroom/scripts/chatroomRouteAssets.js',
121            '/scripts/effects/spaRouteManifest.js?v=charsheet-vitals-20260929',
122            '/scripts/desktop/citrusStylesPolicy.js',
123            '/scripts/desktop/citrusToolContract.js',
124            '/scripts/desktop/citrusToolUi.js',
125            '/scripts/effects/spaNav.js',
126            '/scripts/desktop/citrusWindowLoader.js',
127            '/scripts/desktop/citrusAccountWindow.js'
128        ];
129        var preludeScripts = [
130            '/scripts/dependencies/resolveSiteAssetUrl.js',
131            '/scripts/effects/scriptLoadOnce.js',
132            '/scripts/effects/ensureSiteFontAwesome.js'
133        ];
134        var totalShellSteps = preludeScripts.length + shellScripts.length;
135        var shellStep = 0;
136
137        function advanceShell(src) {
138            shellStep += 1;
139            reportShellStep(shellStep, totalShellSteps, src);
140        }
141
142        var chain = loadScript(preludeScripts[0]).then(function () {
143            advanceShell(preludeScripts[0]);
144            return loadScript(preludeScripts[1]);
145        }).then(function () {
146            advanceShell(preludeScripts[1]);
147            return loadScript(preludeScripts[2]);
148        }).then(function () {
149            advanceShell(preludeScripts[2]);
150            if (typeof global.ensureSiteFontAwesome === 'function') {
151                return global.ensureSiteFontAwesome();
152            }
153        });
154
155        shellScripts.forEach(function (src) {
156            chain = chain.then(function () {
157                return loadScript(src).then(function () {
158                    advanceShell(src);
159                });
160            });
161        });
162
163        chain.then(function () {
164            bootFinalize('shell', 'Shell modules... OK');
165            bootReport('services', 0, 'Starting global services...');
166            if (global.PupwifeSpa && typeof global.PupwifeSpa.ensureGlobalDashboardServices === 'function') {
167                return global.PupwifeSpa.ensureGlobalDashboardServices();
168            }
169        }).then(function () {
170            bootFinalize('services', 'Global services... OK');
171            bootReport('ambient', 0, 'Loading WebGL wallpaper...');
172            if (global.SiteAmbientBoot && typeof global.SiteAmbientBoot.ensure === 'function') {
173                return global.SiteAmbientBoot.ensure({ routeId: 'index.html' });
174            }
175        }).then(function () {
176            bootFinalize('ambient', 'Ambient effects... OK');
177            bootReport('finalize', 0, 'Loading context menus...');
178            ensureStylesheet('/css/siteContextMenu.css');
179            return loadScript('/scripts/effects/siteContextMenu.js?v=' + SHELL_CTX_MENU_V);
180        }).then(function () {
181            bootReport('finalize', 0.45, 'Registering context menus...');
182            return loadScript('/scripts/effects/siteContextMenuRegistry.js?v=' + SHELL_CTX_MENU_V);
183        }).then(function () {
184            bootReport('finalize', 0.75, 'Applying settings...');
185            if (global.CitrusStylesPolicy && typeof global.CitrusStylesPolicy.pruneDisallowedHostStyles === 'function') {
186                global.CitrusStylesPolicy.pruneDisallowedHostStyles();
187            }
188            if (global.SettingsMenu && typeof global.SettingsMenu.init === 'function') {
189                global.SettingsMenu.init();
190            }
191            if (global.SiteContextMenu && typeof global.SiteContextMenu.init === 'function') {
192                global.SiteContextMenu.init();
193            }
194            if (global.AccountIndicator && typeof global.AccountIndicator.update === 'function') {
195                global.AccountIndicator.update();
196            }
197            if (global.CitrusDirectMountRoutes && typeof global.CitrusDirectMountRoutes.ensure === 'function') {
198                global.CitrusDirectMountRoutes.ensure();
199            }
200            bootFinalize('finalize', 'Shell ready... OK');
201            try {
202                global.__citrusShellReady = true;
203                global.dispatchEvent(new CustomEvent('pupwife:citrus-shell-ready'));
204            } catch (e) { /* ignore */ }
205        }).catch(function (err) {
206            console.warn('[citrusShellBoot]', err);
207            bootFinalize('shell', 'Shell modules... OK');
208            bootFinalize('services', 'Global services... OK');
209            bootFinalize('ambient', 'Ambient effects... OK');
210            bootFinalize('finalize', 'Shell ready... OK');
211            try {
212                global.__citrusShellReady = true;
213                global.dispatchEvent(new CustomEvent('pupwife:citrus-shell-ready'));
214            } catch (e2) { /* ignore */ }
215        });
216    }
217
218    if (document.readyState === 'loading') {
219        document.addEventListener('DOMContentLoaded', boot);
220    } else {
221        boot();
222    }
223})(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.