PageSourceSearch

https://engagehalifax.ca/application/js/hive-translator-picker.js?_v=2.70.26.1

js engagehalifax.ca collected 2026-10-09 04:53:28 UTC 11,688 bytes, 312 lines download raw bytes

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.