1/** 2 * Mobile Sidebar System 3 * Handles slideout sidebars for mobile devices 4 */ 5 6window.ChatroomMobileSidebars = (function() { 7 'use strict'; 8 9 let leftSidebarOpen = false; 10 let rightSidebarOpen = false; 11 12 /** 13 * Initialize mobile sidebar system 14 */ 15 function init() { 16 if (!isMobile()) { 17 return; // Only initialize on mobile 18 } 19 20 createToggleButtons(); 21 setupEventListeners(); 22 setupOverlay(); 23 } 24 25 /** 26 * Check if device is mobile 27 */ 28 function isMobile() { 29 return window.innerWidth <= 768; 30 } 31 32 /** 33 * Create toggle buttons for sidebars 34 */ 35 function createToggleButtons() { 36 // Left sidebar toggle (for navigation + channels) 37 const leftToggle = document.createElement('button'); 38 leftToggle.className = 'mobile-sidebar-toggle mobile-sidebar-toggle-left'; 39 leftToggle.innerHTML = 'â°'; 40 leftToggle.title = 'Open Navigation'; 41 leftToggle.id = 'mobile-sidebar-toggle-left'; 42 document.body.appendChild(leftToggle); 43 44 // Right sidebar toggle (for members) 45 const rightToggle = document.createElement('button'); 46 rightToggle.className = 'mobile-sidebar-toggle mobile-sidebar-toggle-right'; 47 rightToggle.innerHTML = 'ð¥'; 48 rightToggle.title = 'Open Members'; 49 rightToggle.id = 'mobile-sidebar-toggle-right'; 50 document.body.appendChild(rightToggle); 51 } 52 53 /** 54 * Setup event listeners 55 */ 56 function setupEventListeners() { 57 const leftToggle = document.getElementById('mobile-sidebar-toggle-left'); 58 const rightToggle = document.getElementById('mobile-sidebar-toggle-right'); 59 const overlay = document.getElementById('mobile-sidebar-overlay'); 60 61 const navColumn = document.querySelector('.navigation-column'); 62 const channelsColumn = document.querySelector('.channels-column'); 63 const membersColumn = document.querySelector('.members-column'); 64 65 // Left toggle - opens navigation and channels 66 if (leftToggle) { 67 leftToggle.addEventListener('click', (e) => { 68 e.stopPropagation(); 69 toggleLeftSidebar(); 70 }); 71 } 72 73 // Right toggle - opens members 74 if (rightToggle) { 75 rightToggle.addEventListener('click', (e) => { 76 e.stopPropagation(); 77 toggleRightSidebar(); 78 }); 79 } 80 81 // Overlay click - closes all sidebars 82 if (overlay) { 83 overlay.addEventListener('click', () => { 84 closeAllSidebars(); 85 }); 86 } 87 88 // Close sidebars when clicking outside 89 document.addEventListener('click', (e) => { 90 if (leftSidebarOpen || rightSidebarOpen) { 91 const isClickInsideLeft = navColumn?.contains(e.target) || 92 channelsColumn?.contains(e.target) || 93 leftToggle?.contains(e.target); 94 const isClickInsideRight = membersColumn?.contains(e.target) || 95 rightToggle?.contains(e.target); 96 97 if (!isClickInsideLeft && !isClickInsideRight) { 98 closeAllSidebars(); 99 } 100 } 101 }); 102 103 // Handle window resize 104 let resizeTimeout; 105 window.addEventListener('resize', () => { 106 clearTimeout(resizeTimeout); 107 resizeTimeout = setTimeout(() => { 108 if (!isMobile()) { 109 closeAllSidebars(); 110 // Hide toggle buttons on desktop 111 if (leftToggle) leftToggle.style.display = 'none'; 112 if (rightToggle) rightToggle.style.display = 'none'; 113 } else { 114 // Show toggle buttons on mobile 115 if (leftToggle) leftToggle.style.display = 'flex'; 116 if (rightToggle) rightToggle.style.display = 'flex'; 117 } 118 }, 100); 119 }); 120 121 // Close sidebars on escape key 122 document.addEventListener('keydown', (e) => { 123 if (e.key === 'Escape') { 124 closeAllSidebars(); 125 } 126 }); 127 } 128 129 /** 130 * Setup overlay 131 */ 132 function setupOverlay() {
133 const overlay = document.createElement('div'); 134 overlay.id = 'mobile-sidebar-overlay'; 135 overlay.className = 'mobile-sidebar-overlay'; 136 document.body.appendChild(overlay); 137 } 138 139 /** 140 * Toggle left sidebar (navigation + channels) 141 */ 142 function toggleLeftSidebar() { 143 const navColumn = document.querySelector('.navigation-column'); 144 const channelsColumn = document.querySelector('.channels-column'); 145 const overlay = document.getElementById('mobile-sidebar-overlay'); 146 147 leftSidebarOpen = !leftSidebarOpen; 148 149 if (leftSidebarOpen) { 150 // Close right sidebar if open 151 if (rightSidebarOpen) { 152 toggleRightSidebar(); 153 } 154 155 navColumn?.classList.add('mobile-open'); 156 channelsColumn?.classList.add('mobile-open'); 157 overlay?.classList.add('active'); 158 document.body.style.overflow = 'hidden'; 159 } else { 160 navColumn?.classList.remove('mobile-open'); 161 channelsColumn?.classList.remove('mobile-open'); 162 if (!rightSidebarOpen) { 163 overlay?.classList.remove('active'); 164 document.body.style.overflow = ''; 165 } 166 } 167 } 168 169 /** 170 * Toggle right sidebar (members) 171 */ 172 function toggleRightSidebar() { 173 const membersColumn = document.querySelector('.members-column'); 174 const overlay = document.getElementById('mobile-sidebar-overlay'); 175 176 rightSidebarOpen = !rightSidebarOpen; 177 178 if (rightSidebarOpen) { 179 // Close left sidebar if open 180 if (leftSidebarOpen) { 181 toggleLeftSidebar(); 182 } 183 184 membersColumn?.classList.add('mobile-open'); 185 overlay?.classList.add('active'); 186 document.body.style.overflow = 'hidden'; 187 } else { 188 membersColumn?.classList.remove('mobile-open'); 189 if (!leftSidebarOpen) { 190 overlay?.classList.remove('active'); 191 document.body.style.overflow = ''; 192 } 193 } 194 } 195 196 /** 197 * Close all sidebars 198 */ 199 function closeAllSidebars() { 200 if (leftSidebarOpen) { 201 toggleLeftSidebar(); 202 } 203 if (rightSidebarOpen) { 204 toggleRightSidebar(); 205 } 206 } 207 208 // Initialize on load 209 if (document.readyState === 'loading') { 210 document.addEventListener('DOMContentLoaded', init); 211 } else { 212 init(); 213 } 214 215 // Re-initialize on resize to handle orientation changes 216 window.addEventListener('resize', () => { 217 if (isMobile() && !document.getElementById('mobile-sidebar-toggle-left')) { 218 init(); 219 } 220 }); 221 222 return { 223 init, 224 toggleLeftSidebar, 225 toggleRightSidebar, 226 closeAllSidebars, 227 isMobile 228 }; 229})(); 230
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.