PageSourceSearch

https://www.gresb.com/wp-content/themes/framework/assets/js/components/_1_language-picker.js?ver=1790907449

js gresb.com collected 2026-10-02 02:36:20 UTC 9,043 bytes, 182 lines download raw bytes

1// File#: _1_language-picker
2// Usage: codyhouse.co/license
3(function() {
4	var LanguagePicker = function(element) {
5		this.element = element;
6		this.select = this.element.getElementsByTagName('select')[0];
7		this.options = this.select.getElementsByTagName('option');
8		this.selectedOption = getSelectedOptionText(this);
9		this.pickerId = this.select.getAttribute('id');
10		this.trigger = false;
11		this.dropdown = false;
12		this.firstLanguage = false;
13		// dropdown arrow inside the button element
14		this.arrowSvgPath = '<svg viewBox="0 0 16 16"><polygon points="3,5 8,11 13,5 "></polygon></svg>';
15		this.globeSvgPath = '<svg viewBox="0 0 16 16"><path d="M8,0C3.6,0,0,3.6,0,8s3.6,8,8,8s8-3.6,8-8S12.4,0,8,0z M13.9,7H12c-0.1-1.5-0.4-2.9-0.8-4.1 C12.6,3.8,13.6,5.3,13.9,7z M8,14c-0.6,0-1.8-1.9-2-5H10C9.8,12.1,8.6,14,8,14z M6,7c0.2-3.1,1.3-5,2-5s1.8,1.9,2,5H6z M4.9,2.9 C4.4,4.1,4.1,5.5,4,7H2.1C2.4,5.3,3.4,3.8,4.9,2.9z M2.1,9H4c0.1,1.5,0.4,2.9,0.8,4.1C3.4,12.2,2.4,10.7,2.1,9z M11.1,13.1 c0.5-1.2,0.7-2.6,0.8-4.1h1.9C13.6,10.7,12.6,12.2,11.1,13.1z"></path></svg>';
16
17		initLanguagePicker(this);
18		initLanguagePickerEvents(this);
19	};
20
21	function initLanguagePicker(picker) {
22		// create the HTML for the custom dropdown element
23		picker.element.insertAdjacentHTML('beforeend', initButtonPicker(picker) + initListPicker(picker));
24		
25		// save picker elements
26		picker.dropdown = picker.element.getElementsByClassName('language-picker__dropdown')[0];
27		picker.languages = picker.dropdown.getElementsByClassName('language-picker__item');
28		picker.firstLanguage = picker.languages[0];
29		picker.trigger = picker.element.getElementsByClassName('language-picker__button')[0];
30	};
31
32	function initLanguagePickerEvents(picker) {
33		// make sure to add the icon class to the arrow dropdown inside the button element
34		var svgs = picker.trigger.getElementsByTagName('svg');
35		Util.addClass(svgs[0], 'icon');
36		Util.addClass(svgs[1], 'icon');
37		// language selection in dropdown
38		// ⚠️ Important: you need to modify this function in production
39		initLanguageSelection(picker);
40
41		// click events
42		picker.trigger.addEventListener('click', function(){
43			toggleLanguagePicker(picker, false);
44		});
45		// keyboard navigation
46		picker.dropdown.addEventListener('keydown', function(event){
47			if(event.keyCode && event.keyCode == 38 || event.key && event.key.toLowerCase() == 'arrowup') {
48				keyboardNavigatePicker(picker, 'prev');
49			} else if(event.keyCode && event.keyCode == 40 || event.key && event.key.toLowerCase() == 'arrowdown') {
50				keyboardNavigatePicker(picker, 'next');
51			}
52		});
53	};
54
55	function toggleLanguagePicker(picker, bool) {
56		var ariaExpanded;
57		if(bool) {
58			ariaExpanded = bool;
59		} else {
60			ariaExpanded = picker.trigger.getAttribute('aria-expanded') == 'true' ? 'false' : 'true';
61		}
62		picker.trigger.setAttribute('aria-expanded', ariaExpanded);
63		if(ariaExpanded == 'true') {
64			picker.firstLanguage.focus(); // fallback if transition is not supported
65			picker.dropdown.addEventListener('transitionend', function cb(){
66				picker.firstLanguage.focus();
67				picker.dropdown.removeEventListener('transitionend', cb);
68			});
69			// place dropdown
70			placeDropdown(picker);
71		}
72	};
73
74	function placeDropdown(picker) {
75		var triggerBoundingRect = picker.trigger.getBoundingClientRect();
76		Util.toggleClass(picker.dropdown, 'language-picker__dropdown--right', (window.innerWidth < triggerBoundingRect.left + picker.dropdown.offsetWidth));
77		Util.toggleClass(picker.dropdown, 'language-picker__dropdown--up', (window.innerHeight < triggerBoundingRect.bottom + picker.dropdown.offsetHeight));
78	};
79
80	function checkLanguagePickerClick(picker, target) { // if user clicks outside the language picker -> close it
81		if( !picker.element.contains(target) ) toggleLanguagePicker(picker, 'false');
82	};
83
84	function moveFocusToPickerTrigger(picker) {
85		if(picker.trigger.getAttribute('aria-expanded') == 'false') return;
86		if(document.activeElement.closest('.language-picker__dropdown') == picker.dropdown) picker.trigger.focus();
87	};
88
89	function initButtonPicker(picker) { // create the button element -> picker trigger
90		// check if we need to add custom classes to the button trigger
91		var customClasses = picker.element.getAttribute('data-trigger-class') ? ' '+picker.element.getAttribute('data-trigger-class') : '';
92	
93		var button = '<button class="language-picker__button'+customClasses+'" aria-label="'+picker.select.value+' '+picker.element.getElementsByTagName('label')[0].textContent+'" aria-expanded="false" aria-controls="'+picker.pickerId+'-dropdown">';
94		button = button + '<span aria-hidden="true" class="language-picker__label language-picker__flag language-picker__flag--'+picker.select.value+'">'+picker.globeSvgPath+'<em>'+picker.selectedOption+'</em>';
95		button = button +picker.arrowSvgPath+'</span>';
96		return button+'</button>';
97	};
98
99	function initListPicker(picker) { // create language picker dropdown
100		var list = '<div class="language-picker__dropdown" aria-describedby="'+picker.pickerId+'-description" id="'+picker.pickerId+'-dropdown">';
101		list = list + '<p class="sr-only" id="'+picker.pickerId+'-description">'+picker.element.getElementsByTagName('label')[0].textContent+'</p>';
102		list = list + '<ul class="language-picker__list" role="listbox">';
103		for(var i = 0; i < picker.options.length; i++) {
104			var selected = picker.options[i].selected ? ' aria-selected="true"' : '',
105				language = picker.options[i].getAttribute('lang');
106			list = list + '<li><a lang="'+language+'" hreflang="'+language+'" href="'+getLanguageUrl(picker.options[i])+'"'+selected+' role="option" data-value="'+picker.options[i].value+'" class="language-picker__item language-picker__flag language-picker__flag--'+picker.options[i].value+'"><span>'+picker.options[i].text+'</span></a></li>';
107		};
108		return list;
109	};
110
111	function getSelectedOptionText(picker) { // used to initialize the label of the picker trigger button
112		var label = '';
113		if('selectedIndex' in picker.select) {
114			label = picker.options[picker.select.selectedIndex].text;
115		} else {
116			label = picker.select.querySelector('option[selected]').text;
117		}
118		return label;
119	};
120
121	function getLanguageUrl(option) {
122		// ⚠️ Important: You should replace this return value with the real link to your website in the selected language
123		// option.value gives you the value of the language that you can use to create your real url (e.g, 'english' or 'italiano')
124		return '#';
125	};
126
127	function initLanguageSelection(picker) {
128		picker.element.getElementsByClassName('language-picker__list')[0].addEventListener('click', function(event){
129			var language = event.target.closest('.language-picker__item');
130			if(!language) return;
131			
132			if(language.hasAttribute('aria-selected') && language.getAttribute('aria-selected') == 'true') {
133				// selecting the same language
134				event.preventDefault();
135				picker.trigger.setAttribute('aria-expanded', 'false'); // hide dropdown
136			} else { 
137				// ⚠️ Important: this 'else' code needs to be removed in production. 
138				// The user has to be redirected to the new url -> nothing to do here
139				event.preventDefault();
140				picker.element.getElementsByClassName('language-picker__list')[0].querySelector('[aria-selected="true"]').removeAttribute('aria-selected');
141				language.setAttribute('aria-selected', 'true');
142				picker.trigger.getElementsByClassName('language-picker__label')[0].setAttribute('class', 'language-picker__label language-picker__flag language-picker__flag--'+language.getAttribute('data-value'));
143				picker.trigger.getElementsByClassName('language-picker__label')[0].getElementsByTagName('em')[0].textContent = language.textContent;
144				picker.trigger.setAttribute('aria-expanded', 'false');
145			}
146		});
147	};
148
149	function keyboardNavigatePicker(picker, direction) {
150		var index = Util.getIndexInArray(picker.languages, document.activeElement);
151		index = (direction == 'next') ? index + 1 : index - 1;
152		if(index < 0) index = picker.languages.length - 1;
153		if(index >= picker.languages.length) index = 0;
154		Util.moveFocus(picker.languages[index]);
155	};
156
157	//initialize the LanguagePicker objects
158	var languagePicker = document.getElementsByClassName('js-language-picker');
159	if( languagePicker.length > 0 ) {
160		var pickerArray = [];
161		for( var i = 0; i < languagePicker.length; i++) {
162			(function(i){pickerArray.push(new LanguagePicker(languagePicker[i]));})(i);
163		}
164
165		// listen for key events
166		window.addEventListener('keyup', function(event){
167			if( event.keyCode && event.keyCode == 27 || event.key && event.key.toLowerCase() == 'escape' ) {
168				// close language picker on 'Esc'
169				pickerArray.forEach(function(element){
170					moveFocusToPickerTrigger(element); // if focus is within dropdown, move it to dropdown trigger
171					toggleLanguagePicker(element, 'false'); // close dropdown
172				});
173			} 
174		});
175		// close language picker when clicking outside it
176		window.addEventListener('click', function(event){
177			pickerArray.forEach(function(element){
178				checkLanguagePickerClick(element, event.target);
179			});
180		});
181	}
182}());

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.