1(function() { 2 'use strict'; 3 4 const panelConfigs = [ 5 { 6 container: '.header-search', 7 toggle: '.search-toggle', 8 dropdown: '.search-dropdown', 9 input: '.search-input' // Optional 10 }, 11 { 12 container: '.login-panel', 13 toggle: '.login-toggle', 14 dropdown: '.login-dropdown' 15 }, 16 { 17 container: '.mobile-login-panel', 18 toggle: '.mobile-cta-login', 19 dropdown: '.mobile-login-drop' 20 } 21 ]; 22 23 // Store active instances to manage cross-closing 24 const activePanels = []; 25 26 function initPanels() { 27 panelConfigs.forEach(config => { 28 const container = document.querySelector(config.container); 29 if (!container) return; 30 31 const toggle = container.querySelector(config.toggle); 32 const dropdown = container.querySelector(config.dropdown); 33 const input = config.input ? container.querySelector(config.input) : null; 34 35 if (!toggle || !dropdown) return; 36 37 const panel = { 38 container, 39 toggle, 40 dropdown, 41 isOpen: false, 42 43 open() {
44 // Close all other open panels first to prevent conflicts 45 activePanels.forEach(p => { 46 if (p !== this && p.isOpen) p.close(); 47 }); 48 49 container.classList.add('is-open'); 50 toggle.setAttribute('aria-expanded', 'true'); 51 if (input) input.focus(); 52 this.isOpen = true; 53 }, 54 55 close() { 56 container.classList.remove('is-open'); 57 toggle.setAttribute('aria-expanded', 'false'); 58 this.isOpen = false; 59 }, 60 61 togglePanel() { 62 this.isOpen ? this.close() : this.open(); 63 } 64 }; 65 66 // Toggle on button click 67 toggle.addEventListener('click', (e) => { 68 // Prevent default in case it's an <a> tag 69 e.preventDefault(); 70 panel.togglePanel(); 71 }); 72 73 // Close on Escape key 74 container.addEventListener('keydown', (e) => { 75 if (e.key === 'Escape' && panel.isOpen) { 76 e.preventDefault(); 77 panel.close(); 78 toggle.focus(); // Return focus for accessibility 79 } 80 }); 81 82 activePanels.push(panel); 83 }); 84 85 // click listener for all panels 86 document.addEventListener('click', (e) => { 87 activePanels.forEach(panel => { 88 // If the panel is open AND the click happened outside of this specific container 89 if (panel.isOpen && !panel.container.contains(e.target)) { 90 panel.close(); 91 } 92 }); 93 }); 94 } 95 96 /** 97 * Gravity Forms File Upload Enhancement 98 */ 99 function initFileUploadUI() { 100 function bindFileInputs() { 101 const inputs = document.querySelectorAll('.ginput_container_fileupload input[type="file"]'); 102 103 inputs.forEach(input => { 104 if (input.dataset.bound) return; 105 106 input.dataset.bound = "true"; 107 108 input.addEventListener('change', function () { 109 console.log('file changed'); 110 111 const container = input.closest('.ginput_container_fileupload'); 112 if (!container) return; 113 114 if (input.files.length > 0) { 115 container.classList.add('has-file'); 116 container.setAttribute('data-file', input.files[0].name); 117 } 118 }); 119 }); 120 } 121 122 // Run once 123 bindFileInputs(); 124 125 // GF hook (jQuery-based) 126 if (window.jQuery) { 127 jQuery(document).on('gform_post_render', function () { 128 bindFileInputs(); 129 }); 130 } 131 } 132 133 function initAll() { 134 initPanels(); 135 initFileUploadUI(); 136 } 137 138 // Initialize when DOM is ready 139 if (document.readyState === 'loading') { 140 document.addEventListener('DOMContentLoaded', initAll); 141 } else { 142 initAll(); 143 } 144})();
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.