1(function (T9N) { 2 /** 3 * @param {HTMLElement} element 4 * @constructor 5 */ 6 var LanguagePicker = function(element) { 7 this.element = element; 8 this.pickerId = element.getAttribute('id'); 9 this.enabled = typeof T9N !== 'undefined'; 10 this.trigger = this.element.getElementsByClassName('language-picker-button')[0]; 11 this.dropdown = this.element.getElementsByClassName('language-picker-dropdown')[0]; 12 this.dropdownDescription = document.getElementById(this.dropdown.getAttribute('aria-describedby')).innerText; 13 this.defaultLanguage = this.dropdown.getAttribute('data-default'); 14 this.activeLanguage = this.trigger.getElementsByClassName('language')[0]; 15 this.currentLanguage = window.HiveTargetLanguageCode; 16 this.currentLanguageLabel = this.activeLanguage.innerText; 17 18 var that = this; 19 getAvailableLanguages() 20 .then(function(languages) { 21 languages.sort(function(a, b) { 22 if (a.code === that.defaultLanguage) { 23 return -1; 24 } 25 if (b.code === that.defaultLanguage) { 26 return 1; 27 } 28 return a.code.localeCompare(b.code); 29 }) 30 that.languages = languages; 31 initLanguagePicker(that); 32 initLanguagePickerEvents(that); 33 }) 34 .catch(function(err) { 35 that.enabled = false; 36 initLanguagePicker(that); 37 initLanguagePickerEvents(that); 38 }); 39 } 40 41 /** 42 * @param {LanguagePicker} picker 43 */ 44 function initLanguagePicker(picker) { 45 picker.element.classList.add('language-picker-inline'); 46 47 picker.trigger.setAttribute('aria-disabled', !picker.enabled ? 'true' : 'false'); 48 49 initDropdownPicker(picker); 50 51 picker.element.classList.remove('hidden'); 52 } 53 54 /** 55 * @param {LanguagePicker} picker 56 */ 57 function initDropdownPicker(picker) { 58 if (picker.enabled) { 59 var list = picker.dropdown.getElementsByClassName('language-picker-list')[0]; 60 61 if (picker.languages && Array.isArray(picker.languages)) {
62 picker.languages.forEach(function(language) { 63 var selected = picker.currentLanguage === language.code ? ' aria-selected="true"' : ''; 64 list.insertAdjacentHTML('beforeend', '<li><a href="' + getLinkToLanguage(language.code) + '" lang="' + language.code + '" data-value="' + language.code + '"' + selected + ' role="option" class="language-picker-item">' + language.name + '</a></li>'); 65 }); 66 list.classList.remove('hidden'); 67 } else { 68 console.error('[LANG-PICKER] picker.languages is not an array or is undefined'); 69 } 70 } else { 71 var message = picker.dropdown.getElementsByClassName('translation-unavailable')[0] 72 message.classList.remove('hidden'); 73 } 74 } 75 /** 76 * @param {string} language 77 */ 78 function changeLanguage(language) { 79 var newLocale = language; 80 if (typeof window.HiveLanguageMappings !== 'undefined' && typeof window.HiveLanguageMappings[newLocale] !== 'undefined') { 81 newLocale = window.HiveLanguageMappings[newLocale]; 82 } 83 84 var expiry = new Date(); 85 expiry.setTime(expiry.getTime() + (365 * 24 * 60 * 60 * 1000)); 86 document.cookie = "locale=" + newLocale + "; expires=" + expiry.toUTCString() + "; path=/"; 87 88 window.location.reload(); 89 } 90 91 /** 92 * @param {LanguagePicker} picker 93 * @param {string} bool 94 */ 95 function toggleLanguagePicker(picker, bool) { 96 var ariaExpanded; 97 if (bool) { 98 ariaExpanded = bool; 99 } else { 100 ariaExpanded = picker.trigger.getAttribute('aria-expanded') === 'true' ? 'false' : 'true'; 101 } 102 picker.trigger.setAttribute('aria-expanded', ariaExpanded); 103 if (ariaExpanded === 'true') { 104 if (picker.enabled) { 105 picker.dropdown.getElementsByClassName('language-picker-item')[0].focus(); 106 } else { 107 picker.dropdown.getElementsByClassName('translation-unavailable')[0].focus(); 108 } 109 } 110 } 111 112 /** 113 * @param {LanguagePicker} picker 114 * @param {string} direction 115 */ 116 function keyboardNavigatePicker(picker, direction) { 117 var current = document.activeElement; 118 if (current.getAttribute('role') !== 'option') { 119 return; 120 } 121 var list = picker.dropdown.getElementsByClassName('language-picker-list')[0]; 122 var options = Array.from(list.querySelectorAll('[role="option"]')); 123 var index = options.findIndex((opt) => opt.getAttribute('data-value') === current.getAttribute('data-value')); 124 index = (direction === 'next') ? index + 1 : index - 1; 125 if (index < 0) { 126 index = options.length - 1; 127 } 128 if (index >= options.length) { 129 index = 0; 130 } 131 options[index].focus(); 132 } 133 134 /** 135 * @param {LanguagePicker} picker 136 */ 137 function moveFocusToPickerTrigger(picker) { 138 if (picker.trigger.getAttribute('aria-expanded') === 'false') { 139 return; 140 } 141 if (document.activeElement.closest('.language-picker-dropdown') == picker.dropdown) { 142 picker.trigger.focus(); 143 } 144 } 145 146 /** 147 * @param {LanguagePicker} picker 148 */ 149 function initLanguagePickerEvents(picker) { 150 picker.trigger.addEventListener('click', function(e) { 151 e.preventDefault(); 152 toggleLanguagePicker(picker); 153 }); 154 155 picker.trigger.addEventListener('keydown', function(e) { 156 if (e.key && e.key === ' ') { 157 e.preventDefault(); 158 toggleLanguagePicker(picker); 159 } 160 }); 161 162 if (picker.enabled) { 163 picker.dropdown.getElementsByClassName('language-picker-list')[0].addEventListener('click', function(e) { 164 e.preventDefault(); 165 166 var option = e.target; 167 if (option.hasAttribute('aria-selected') && option.getAttribute('aria-selected') === 'true') { 168 picker.trigger.setAttribute('aria-expanded', 'false'); 169 } else { 170 changeLanguage(option.getAttribute('data-value')); 171 } 172 }); 173 174 picker.dropdown.addEventListener('keydown', function(e) { 175 if (e.key) { 176 switch (e.key.toLowerCase()) { 177 case 'arrowup': 178 e.preventDefault(); 179 keyboardNavigatePicker(picker, 'prev'); 180 break; 181 case 'arrowdown': 182 e.preventDefault(); 183 keyboardNavigatePicker(picker, 'next'); 184 break; 185 } 186 } 187 }); 188 } 189 } 190 191 function getLanguageLabel(picker, lang) { 192 if (!picker.languages) { 193 return null; 194 } 195 196 var language = picker.languages.find(function(l) { 197 return l.code === lang; 198 }); 199 if (language) { 200 return language.name; 201 } 202 203 return null; 204 } 205 206 function getLinkToLanguage(lang) { 207 try { 208 var url = new URL(window.location.href); 209 url.searchParams.set('ljs', lang); 210 return url.toString(); 211 } catch (e) { 212 console.error(e); 213 } 214 215 return '#'; 216 } 217 218 /** 219 * @param {LanguagePicker} picker 220 */ 221 function updateSelectedLanguage(picker) { 222 var newLanguageLabel = getLanguageLabel(picker, picker.currentLanguage); 223 if (newLanguageLabel) { 224 picker.activeLanguage.innerText = newLanguageLabel; 225 picker.trigger.setAttribute('aria-label', newLanguageLabel + ' ' + picker.dropdownDescription); 226 } 227 228 var languageList = picker.dropdown.getElementsByClassName('language-picker-list')[0]; 229 Array.from(languageList.getElementsByClassName('language-picker-item')).forEac
229h(function(element) { 230 var selected = picker.currentLanguage === element.getAttribute('lang'); 231 element.setAttribute('aria-selected', selected ? 'true' : 'false'); 232 }); 233 } 234 235 236 function checkLanguagePickerClick(picker, target) { 237 if (!picker.element.contains(target)) { 238 toggleLanguagePicker(picker, 'false'); 239 } 240 } 241 242 /** 243 * @return {Promise} 244 */ 245 function getAvailableLanguages() { 246 return new Promise(function(resolve, reject) { 247 try { 248 249 // Ensure default language is always included 250 if (typeof window.HiveAvailableLanguages !== 'undefined') { 251 252 var languages = window.HiveAvailableLanguages; 253 console.log('[LANG-PICKER] Available languages:', languages); 254 255 // Since there's only one dropdown per site, directly get the data-default attribute 256 var dropdown = document.querySelector('.language-picker-dropdown'); 257 var defaultLangCode = dropdown ? dropdown.getAttribute('data-default') : null; 258 259 console.log('[LANG-PICKER] Default language code:', defaultLangCode); 260 261 if (defaultLangCode && Array.isArray(languages)) { 262 // Find the default language in global available languages 263 var defaultLang = window.HiveAvailableLanguages.find(function(lang) { 264 return lang.code === defaultLangCode; 265 }); 266 267 // If default language is in global available languages but not in current list, add it 268 if (defaultLang && !languages.some(function(lang) { return lang.code === defaultLangCode; })) { 269 console.log('[LANG-PICKER] Adding default language (' + defaultLangCode + ') to available languages'); 270 languages.push(defaultLang); 271 } 272 } 273 274 // Resolve the promise with the languages array 275 resolve(languages); 276 } else { 277 // If HiveAvailableLanguages is not defined, resolve with empty array 278 resolve([]); 279 } 280 281 } catch (err) { 282 console.error('[LANG-PICKER] Error getting available languages:', err); 283 reject(err); 284 } 285 }); 286 } 287 288 var languagePicker = document.getElementsByClassName('js-language-picker'); 289 if (languagePicker.length) { 290 var pickerArray = []; 291 for (var i = 0; i < languagePicker.length; i++) { 292 (function(i){ 293 pickerArray.push(new LanguagePicker(languagePicker[i])) 294 })(i); 295 } 296 297 window.addEventListener('keyup', function(e) { 298 if (e.key && e.key.toLowerCase() === 'escape') { 299 pickerArray.forEach(function(element) { 300 moveFocusToPickerTrigger(element); 301 toggleLanguagePicker(element, 'false'); 302 }) 303 } 304 }); 305 306 window.addEventListener('click', function(e) { 307 pickerArray.forEach(function(element) { 308 checkLanguagePickerClick(element, e.target); 309 }); 310 }); 311 } 312}(window.T9N));
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.