1/** 2 * CitrusOS Settings â tabbed window shell (replaces modal overlay on index.html). 3 */ 4(function (global) { 5 'use strict'; 6 7 var SETTINGS_AUX_ID = 'settings'; 8 var CSS_HREF = '/css/citrusSettings.css'; 9 var DEFAULT_W = 840; 10 var DEFAULT_H = 624; 11 var activeRoot = null; 12 var tabApi = null; 13 14 function ensureCss() { 15 if (document.querySelector('link[data-citrus-settings-css]')) return; 16 var link = document.createElement('link'); 17 link.rel = 'stylesheet'; 18 link.href = CSS_HREF; 19 link.setAttribute('data-citrus-settings-css', '1'); 20 document.head.appendChild(link); 21 } 22 23 function getPanel() { 24 return document.getElementById('settings-panel'); 25 } 26 27 function centerPosition(w, h) { 28 return { 29 x: Math.max(16, Math.round((global.innerWidth - w) / 2)), 30 y: Math.max(16, Math.round((global.innerHeight - h - 72) / 2)) 31 }; 32 } 33 34 function mountPanel(contentEl) { 35 var panel = getPanel(); 36 if (!panel) return; 37 38 activeRoot = contentEl; 39 contentEl.className = 'citrus-settings-window'; 40 contentEl.innerHTML = ''; 41 contentEl.appendChild(panel); 42 43 panel.style.display = ''; 44 panel.classList.add('settings-panel--citrusos'); 45 46 if (global.PupwifeSettingsTabs && typeof global.PupwifeSettingsTabs.mount === 'function') { 47 tabApi = global.PupwifeSettingsTabs.mount(panel); 48 } 49 50 if (global.PupwifeSettingsSearch && typeof global.PupwifeSettingsSearch.bind === 'function') { 51 global.PupwifeSettingsSearch.bind(panel, { 52 getTabApi: function () { return tabApi; } 53 }); 54 } 55 } 56 57 function onOpen() { 58 if (global.SettingsMenu && typeof global.SettingsMenu.onWindowOpen === 'function') { 59 global.SettingsMenu.onWindowOpen(); 60 } 61 } 62 63 function onClose() { 64 if (global.PupwifeTrailPicker && typeof global.PupwifeTrailPicker.close === 'function') { 65 global.PupwifeTrailPicker.close(); 66 } 67 if (global.PupwifeCursorPicker && typeof global.PupwifeCursorPicker.close === 'function') { 68 global.PupwifeCursorPicker.close(); 69 } 70 71 var panel = getPanel(); 72 if (panel && activeRoot && panel.parentNode === activeRoot) { 73 document.body.appendChild(panel); 74 panel.classList.remove('settings-panel--open'); 75 panel.style.display = 'none'; 76 } 77 78 activeRoot = null; 79 tabApi = null; 80 81 if (global.PupwifeSettingsSearch && typeof global.PupwifeSettingsSearch.clear === 'function') { 82 global.PupwifeSettingsSearch.clear(panel); 83 } 84 85 try { 86 document.dispatchEvent(new CustomEvent('pupwife:settings-closed')); 87 } catch (e) { 88 document.dispatchEvent(new Event('pupwife:settings-closed')); 89 } 90 } 91 92 function open(opts) { 93 opts = opts || {}; 94 if (!global.CitrusDesktop || typeof global.CitrusDesktop.openAuxWindow !== 'function') { 95 openModalFallback(); 96 return; 97 } 98 99 ensureCss(); 100 101 if (global.CitrusStylesPolicy && typeof global.CitrusStylesPolicy.pruneDisallowedHostStyles === 'function') { 102 global.CitrusStylesPolicy.pruneDisallowedHostStyles(); 103 } 104 105 var pos = (opts.x != null && opts.y != null) 106 ? { x: opts.x, y: opts.y } 107 : centerPosition(DEFAULT_W, DEFAULT_H); 108 var win = global.CitrusDesktop.openAuxWindow({ 109 id: SETTINGS_AUX_ID, 110 label: 'Settings', 111 icon: 'fa-solid fa-sliders', 112 w: DEFAULT_W, 113 h: DEFAULT_H, 114 x: pos.x, 115 y: pos.y, 116 nearChat: false, 117 resizable: false, 118 silent: !!opts.silent, 119 auxClass: 'citrus-window--settings', 120 onMount: function (contentEl) { 121 mountPanel(contentEl); 122 }, 123 onClose: onClose 124 }); 125 126 if (win && win.contentEl) { 127 if (!activeRoot || !getPanel() || !win.contentEl.contains(getPanel())) { 128 mountPanel(win.contentEl); 129 } 130 onOpen(); 131 } 132 133 if (opts.minimized && global.CitrusDesktop && typeof global.CitrusDesktop.minimizeApp === 'function') { 134 global.CitrusDesktop.minimizeApp('aux:' + SETTINGS_AUX_ID); 135 } 136 } 137 138 function restoreSession(entry) { 139 if (!entry) return; 140 open({ 141 x: entry.x, 142 y: entry.y, 143 silent: true, 144 minimized: !!entry.minimized 145 }); 146 } 147 148 function openModalFallback() { 149 var backdrop = document.getElementById('settings-backdrop'); 150 var panel = getPanel(); 151 if (!backdrop || !panel) return; 152 backdrop.classList.add('settings-backdrop--open'); 153 panel.classList.add('settings-panel--open'); 154 onOpen(); 155 } 156 157 function close() { 158 if (global.CitrusDesktop && typeof global.CitrusDesktop.closeAuxWindow === 'function') { 159 global.CitrusDesktop.closeAuxWindow(SETTINGS_AUX_ID); 160 return; 161 } 162 openModalFallback(); 163 var backdrop = document.getElementById('settings-backdrop'); 164 var panel = getPanel(); 165 if (backdrop) backdrop.classList.remove('settings-backdrop--open'); 166 if (panel) panel.classList.remove('settings-panel--open'); 167 onClose(); 168 } 169 170 function isOpen() { 171 return !!activeRoot; 172 } 173 174 function setActiveTab(tabId) { 175 if (tabApi && typeof tabApi.setActiveTab === 'function') { 176 tabApi.setActiveTab(tabId); 177 } 178 } 179
180 global.CitrusSettingsWindow = { 181 open: open, 182 close: close, 183 isOpen: isOpen, 184 setActiveTab: setActiveTab, 185 restoreSession: restoreSession 186 }; 187})(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.