1/** 2 * Accessibility features for EU4LMIApp 3 */ 4 5// Font size adjustment 6function changeFontSize(action) { 7 const root = document.documentElement; 8 const currentSize = parseFloat(getComputedStyle(root).fontSize); 9 let newSize; 10 11 switch(action) { 12 case 'increase': 13 newSize = Math.min(currentSize + 2, 24); // Max size 24px 14 break; 15 case 'decrease': 16 newSize = Math.max(currentSize - 2, 12); // Min size 12px 17 break; 18 case 'reset': 19 newSize = 16; // Default size 20 break; 21 } 22 23 root.style.fontSize = `${newSize}px`; 24 localStorage.setItem('fontSize', newSize); 25 26 // Announce to screen readers 27 announceToScreenReader(`Font size changed to ${newSize} pixels`); 28} 29 30// High contrast mode 31function toggleHighContrast() { 32 const body = document.body; 33 body.classList.toggle('high-contrast'); 34 35 const isHighContrast = body.classList.contains('high-contrast'); 36 localStorage.setItem('highContrast', isHighContrast); 37 38 // Announce to screen readers 39 announceToScreenReader(`High contrast mode ${isHighContrast ? 'enabled' : 'disabled'}`); 40} 41 42// Screen reader announcements 43function announceToScreenReader(message) { 44 const announcer = document.getElementById('accessibility-announcer'); 45 if (announcer) { 46 announcer.textContent = message; 47 } 48} 49 50// Focus outline toggle 51function toggleFocusOutline() { 52 const body = document.body; 53 body.classList.toggle('show-focus-outlines'); 54 55 const showOutlines = body.classList.contains('show-focus-outlines'); 56 localStorage.setItem('showFocusOutlines', showOutlines); 57} 58 59// Initialize accessibility settings from localStorage 60document.addEventListener('DOMContentLoaded', function() { 61 // Create screen reader announcer 62 if (!document.getElementById('accessibility-announcer')) { 63 const announcer = document.createElement('div'); 64 announcer.id = 'accessibility-announcer'; 65 announcer.setAttribute('aria-live', 'polite'); 66 announcer.setAttribute('aria-atomic', 'true'); 67 announcer.classList.add('sr-only'); 68 document.body.appendChild(announcer); 69 } 70 71 // Apply saved font size 72 const savedFontSize = localStorage.getItem('fontSize'); 73 if (savedFontSize) { 74 document.documentElement.style.fontSize = `${savedFontSize}px`; 75 } 76 77 // Apply saved contrast setting 78 const highContrast = localStorage.getItem('highContrast') === 'true'; 79 if (highContrast) { 80 document.body.classList.add('high-contrast'); 81 } 82 83 // Apply saved focus outline setting 84 const showFocusOutlines = localStorage.getItem('showFocusOutlines') === 'true'; 85 if (showFocusOutlines) { 86 document.body.classList.add('show-focus-outlines'); 87 } else { 88 // Default to showing focus outlines for keyboard navigation 89 document.body.classList.add('show-focus-outlines'); 90 } 91 92 // Add keyboard navigation for dropdown menus 93 setupKeyboardNavigation(); 94}); 95 96// Setup keyboard navigation for dropdown menus 97function setupKeyboardNavigation() { 98 const dropdownMenus = document.querySelectorAll('.dropdown-menu'); 99 100 dropdownMenus.forEach(menu => { 101 const items = menu.querySelectorAll('.dropdown-item'); 102 103 items.forEach((item, index) => { 104 item.addEventListener('keydown', function(e) { 105 switch(e.key) { 106 case 'ArrowDown': 107 e.preventDefault(); 108 if (index < items.length - 1) { 109 items[index + 1].focus(); 110 } 111 break; 112 case 'ArrowUp': 113 e.preventDefault(); 114 if (index > 0) { 115 items[index - 1].focus(); 116 } 117 break; 118 case 'Escape': 119 e.preventDefault(); 120 const toggle = menu.previousElementSibling; 121 if (toggle) { 122 toggle.focus(); 123 // Close the dropdown 124 const dropdownInstance = bootstrap.Dropdown.getInstance(toggle); 125 if (dropdownInstance) { 126 dropdownInstance.hide(); 127 } 128 } 129 break; 130 } 131 }); 132 }); 133 }); 134} 135 136// Skip to content functionality 137function skipToContent() { 138 const mainContent = document.querySelector('main'); 139 if (mainContent) { 140 mainContent.setAttribute('tabindex', '-1'); 141 mainContent.focus(); 142 } 143}
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.