1(function (Drupal, drupalSettings) { 2 'use strict'; 3 4 Drupal.behaviors.hgLanguageSwitcher = { 5 attach: function (context) { 6 var settings = drupalSettings.hg_language_switcher || {}; 7 var languages = settings.languages || {}; 8 var languageUrls = settings.language_urls || {}; 9 var currentLanguage = settings.current_language || 'en'; 10 var langKeys = Object.keys(languages); 11 12 if (langKeys.length < 2) { 13 return; 14 } 15 16 // --- Sub-header dropdown (existing logic) --- 17 var subHeaderTriggers = (context || document).querySelectorAll('.hgm-language-switcher--sub-header'); 18 19 subHeaderTriggers.forEach(function (trigger) { 20 if (trigger.dataset.hgLangProcessed) { 21 return; 22 } 23 trigger.dataset.hgLangProcessed = 'true'; 24 25 // Update trigger label. 26 var labelSpan = trigger.querySelector('.hgm-language-switcher-label'); 27 if (labelSpan && languages[currentLanguage]) { 28 labelSpan.textContent = currentLanguage === 'es' ? 'Español' : languages[currentLanguage]; 29 } 30 31 // Build dropdown HTML. 32 var heading = Drupal.t('Select your language'); 33 var description = Drupal.t('Explore the library in your preferred language. Availability of some content may vary.'); 34 35 var dropdownHtml = '<div class="hgm-language-switcher-dropdown" role="menu">' + 36 '<h4>' + heading + '</h4>' + 37 '<p>' + description + '</p>' + 38 '<ul>'; 39 40 langKeys.forEach(function (langcode) { 41 var isActive = langcode === currentLanguage; 42 var url = languageUrls[langcode] || '#'; 43 dropdownHtml += '<li>' + 44 '<a href="' + Drupal.checkPlain(url) + '"' + 45 ' role="menuitem"' + 46 ' hreflang="' + Drupal.checkPlain(langcode) + '"' + 47 ' lang="' + Drupal.checkPlain(langcode) + '"' + 48 (isActive ? ' class="active"' : '') + '>' + 49 '<span>' + Drupal.checkPlain(langcode === 'es' ? 'Español' : languages[langcode]) + '</span>' + 50 (isActive ? '<i class="fa-solid fa-check"></i>' : '') + 51 '</a>' + 52 '</li>'; 53 }); 54 55 dropdownHtml += '</ul></div>'; 56 57 var wrapper = trigger.closest('.hgm-language-switcher-wrapper') || trigger.parentElement; 58 wrapper.insertAdjacentHTML('beforeend', dropdownHtml); 59 60 var dropdown = wrapper.querySelector('.hgm-language-switcher-dropdown'); 61 62 trigger.addEventListener('click', function (e) { 63 e.preventDefault(); 64 e.stopPropagation(); 65 var isOpen = dropdown.classList.contains('open'); 66 67 closeAllDropdowns(); 68 69 if (!isOpen) { 70 dropdown.classList.add('open'); 71 trigger.setAttribute('aria-expanded', 'true'); 72 } 73 }); 74 }); 75 76 // Bind document-level close handlers once. 77 if (!document.documentElement.dataset.hgLangGlobalBound) { 78 document.documentElement.dataset.hgLangGlobalBound = 'true'; 79 80 document.addEventListener('click', function (e) { 81 if (!e.target.closest('.hgm-language-switcher-wrapper')) { 82 closeAllDropdowns(); 83 } 84 }); 85 86 document.addEventListener('keydown', function (e) { 87 if (e.key === 'Escape' || e.key === 'Esc') { 88 closeAllDropdowns(); 89 } 90 }); 91 } 92 93 function closeAllDropdowns() { 94 document.querySelectorAll('.hgm-language-switcher-dropdown.open').forEach(function (d) { 95 d.classList.remove('open'); 96 }); 97 document.querySelectorAll('.hgm-language-switcher--sub-header[aria-expanded="true"]').forEach(function (t) { 98 t.setAttribute('aria-expanded', 'false'); 99 }); 100 } 101 102 // --- Drill-down language switcher --- 103 var drilldownItems = (context || document).querySelectorAll('.hgm-language-switcher-drilldown'); 104 105 drilldownItems.forEach(function (drilldownLi) { 106 if (drilldownLi.dataset.hgLangDrilldownProcessed) { 107 return; 108 } 109 drilldownLi.dataset.hgLangDrilldownProcessed = 'true'; 110 111 // Update trigger label dynamically. 112 var triggerLabel = drilldownLi.querySelector('.hgm-language-switcher-drilldown__label'); 113 if (triggerLabel && languages[currentLanguage]) { 114 triggerLabel.textContent = currentLanguage === 'es' ? 'Español' : languages[currentLanguage]; 115 } 116 117 // Build drill-down child content. 118 var backLabel = Drupal.t('Back'); 119 var heading = Drupal.t('Select your language'); 120 var description = Drupal.t('Explore the library in your preferred language. Availability of some content may vary.'); 121 122 var childHtml = ''; 123 124 // Back button. 125 childHtml += '<li class="hgm-language-switcher-drilldown__back">' + 126 '<a title="' + Drupal.checkPlain(backLabel) + '" href="#" class="back">' + 127 '<i class="fa-solid fa-chevron-left"></i> ' + Drupal.checkPlain(backLabel) + 128 '</a>' + 129 '</li>'; 130 131 // Header with heading and description. 132 childHtml += '<li class="hgm-language-switcher-drilldown__header">' + 133 '<div>' + 134 '<h4>' + heading + '</h4>' + 135 '<p>' + description + '</p>' + 136 '</div>' + 137 '</li>'; 138 139 // Language items. 140 langKeys.forEach(function (langcode) { 141 var isActive = langcode === currentLanguage; 142 var url = languageUrls[langcode] || '#'; 143 childHtml += '<li class="hgm-language-switcher-drilldown__item">' + 144 '<a href="' + Drupal.checkPlain(url) + '"' + 145 ' hreflang="' + Drupal.checkPlain(langcode) + '"' + 146 ' lang="' + Drupal.checkPlain(langcode) + '"' + 147 (isActive ? ' class="active"' : '') + '>
147' + 148 '<span>' + Drupal.checkPlain(langcode === 'es' ? 'Español' : languages[langcode]) + '</span>' + 149 (isActive ? '<i class="fa-solid fa-check"></i>' : '') + 150 '</a>' + 151 '</li>'; 152 }); 153 154 // Populate the empty <ul>. 155 var childUl = drilldownLi.querySelector('ul'); 156 childUl.innerHTML = childHtml; 157 158 // Wire up back button â directly reset drill-down state instead of 159 // delegating to the shared back button. The shared button binds to 160 // 'touchstart' on touch devices, so .click() (a 'click' event) is 161 // ignored on iOS/mobile. 162 var backBtn = childUl.querySelector('.hgm-language-switcher-drilldown__back a.back'); 163 if (backBtn) { 164 backBtn.addEventListener('click', function (e) { 165 e.preventDefault(); 166 e.stopPropagation(); 167 resetDrillDown(drilldownLi); 168 }); 169 backBtn.addEventListener('touchend', function (e) { 170 e.preventDefault(); 171 e.stopPropagation(); 172 resetDrillDown(drilldownLi); 173 }); 174 } 175 }); 176 177 // Reset drill-down to level 0 (primary nav) state. 178 function resetDrillDown(drilldownLi) { 179 var drillDown = drilldownLi.closest('.hgm-drill-down'); 180 if (!drillDown) { 181 return; 182 } 183 184 // Remove active class from language switcher dropdown. 185 drilldownLi.classList.remove('active'); 186 187 // Reset level to 0. 188 drillDown.setAttribute('data-level', '0'); 189 190 var nav = drillDown.querySelector('nav'); 191 if (nav) { 192 // Hide the back button in the shared heading. 193 var heading = nav.querySelector('.hgm-drill-down__heading'); 194 if (heading) { 195 heading.classList.remove('back-visible'); 196 // Reset heading title to original values. 197 var titleEl = heading.querySelector('.title'); 198 if (titleEl) { 199 var titleLink = titleEl.querySelector('a'); 200 if (titleLink) { 201 titleLink.setAttribute('href', titleEl.getAttribute('data-original-link') || '#'); 202 titleLink.textContent = titleEl.getAttribute('data-original-title') || 'Main Menu'; 203 } 204 } 205 } 206 } 207 208 // Reset the menu transform and recalculate height from root items. 209 var menu = drillDown.querySelector('.hgm-drill-down__menu'); 210 if (menu) { 211 menu.style.transform = 'translateX(0)'; 212 var listHeight = 0; 213 for (var i = 0; i < menu.children.length; i++) { 214 listHeight += menu.children[i].offsetHeight; 215 } 216 menu.style.height = listHeight + 'px'; 217 } 218 } 219 220 // Reset drill-down state when off-canvas is closed, so reopening 221 // shows the primary nav instead of the language sub-panel. 222 if (!document.documentElement.dataset.hgLangOffcanvasBound) { 223 document.documentElement.dataset.hgLangOffcanvasBound = 'true'; 224 225 var closeBtn = document.querySelector('.hgm-off-canvas__close'); 226 if (closeBtn) { 227 closeBtn.addEventListener('click', function () { 228 var drilldownLi = document.querySelector('.hgm-language-switcher-drilldown.active'); 229 if (drilldownLi) { 230 resetDrillDown(drilldownLi); 231 } 232 }); 233 } 234 235 // Also reset when clicking outside the off-canvas (body click close). 236 var observer = new MutationObserver(function (mutations) { 237 mutations.forEach(function (mutation) { 238 if (mutation.attributeName === 'class' && 239 !document.body.classList.contains('offcanvas-open')) { 240 var drilldownLi = document.querySelector('.hgm-language-switcher-drilldown.active'); 241 if (drilldownLi) { 242 resetDrillDown(drilldownLi); 243 } 244 } 245 }); 246 }); 247 observer.observe(document.body, { attributes: true, attributeFilter: ['class'] }); 248 } 249 } 250 }; 251 252})(Drupal, drupalSettings);
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.