1// Dark popover select â same floating menu language as the top-right language selector 2(function () { 3 'use strict'; 4 5 var SELECTOR = [ 6 'select.js-custom-select', 7 '#scheduleCategorySelect', 8 '#liveSportSelect', 9 '#preferredLanguage', 10 '#favoritesSort', 11 '#expHistoryCategory' 12 ].join(','); 13 14 var openRoot = null; 15 16 function selectedOption(select) { 17 if (!select || !select.options || !select.options.length) return null; 18 return select.options[select.selectedIndex] || select.options[0]; 19 } 20 21 function close(root) { 22 if (!root) return; 23 root.classList.remove('is-open'); 24 var trigger = root.querySelector('.custom-select-trigger'); 25 if (trigger) trigger.setAttribute('aria-expanded', 'false'); 26 if (openRoot === root) openRoot = null; 27 } 28 29 function closeAll(except) { 30 document.querySelectorAll('.custom-select.is-open').forEach(function (root) { 31 if (root !== except) close(root); 32 }); 33 } 34 35 function open(root) { 36 if (!root) return; 37 closeAll(root); 38 root.classList.add('is-open'); 39 var trigger = root.querySelector('.custom-select-trigger'); 40 if (trigger) trigger.setAttribute('aria-expanded', 'true'); 41 var active = root.querySelector('.custom-select-option.is-active'); 42 if (active) active.focus(); 43 openRoot = root; 44 } 45 46 function syncUI(select) { 47 var root = select.closest('.custom-select'); 48 if (!root) return; 49 var current = selectedOption(select); 50 var label = root.querySelector('.custom-select-label'); 51 if (label && current) label.textContent = (current.textContent || '').trim(); 52 root.querySelectorAll('.custom-select-option').forEach(function (item) { 53 var on = item.getAttribute('data-value') === select.value; 54 item.classList.toggle('is-active', on); 55 item.setAttribute('aria-selected', on ? 'true' : 'false'); 56 }); 57 } 58 59 function setValue(select, value) { 60 if (select.value !== value) { 61 select.value = value; 62 } 63 syncUI(select); 64 select.dispatchEvent(new Event('input', { bubbles: true })); 65 select.dispatchEvent(new Event('change', { bubbles: true })); 66 } 67 68 function optionButtons(root) { 69 return Array.prototype.slice.call(root.querySelectorAll('.custom-select-option:not([disabled])')); 70 } 71 72 function enhance(select) { 73 if (!select || select.dataset.customSelectReady === '1' || !select.options.length) return; 74 select.dataset.customSelectReady = '1'; 75 76 var root = document.createElement('div'); 77 root.className = 'custom-select'; 78 if (select.classList.contains('form-control') || select.classList.contains('profile-lang-select')) { 79 root.classList.add('custom-select--block'); 80 } 81 if (select.classList.contains('schedule-category-select') || select.dataset.menuAlign === 'end') { 82 root.classList.add('custom-select--end'); 83 } 84 85 select.parentNode.insertBefore(root, select); 86 root.appendChild(select); 87 select.classList.add('custom-select-native'); 88 select.setAttribute('tabindex', '-1'); 89 select.setAttribute('aria-hidden', 'true'); 90 91 var trigger = document.createElement('button'); 92 trigger.type = 'button'; 93 trigger.className = 'custom-select-trigger'; 94 select.className.split(/\s+/).forEach(function (cls) { 95 if (cls && cls !== 'js-custom-select' && cls !== 'custom-select-native') { 96 trigger.classList.add(cls); 97 } 98 }); 99 trigger.setAttribute('aria-haspopup', 'listbox'); 100 trigger.setAttribute('aria-expanded', 'false'); 101 if (select.getAttribute('aria-label')) { 102 trigger.setAttribute('aria-label', select.getAttribute('aria-label')); 103 } 104 105 var label = document.createElement('span'); 106 label.className = 'custom-select-label'; 107 var current = selectedOption(select); 108 label.textContent = current ? (current.textContent || '').trim() : ''; 109 trigger.appendChild(label); 110 111 var menu = document.createElement('div'); 112 menu.className = 'custom-select-menu'; 113 menu.setAttribute('role', 'listbox'); 114 115 Array.prototype.forEach.call(select.options, function (opt) { 116 var item = document.createElement('button'); 117 item.type = 'button'; 118 item.className = 'custom-select-option'; 119 item.setAttribute('role', 'option'); 120 item.setAttribute('data-value', opt.value); 121 item.textContent = (opt.textContent || '').trim(); 122 if (opt.disabled) { 123 item.disabled = true; 124 item.classList.add('is-disabled'); 125 } 126 var isSelected = opt.value === select.value; 127 item.classList.toggle('is-active', isSelected); 128 item.setAttribute('aria-selected', isSelected ? 'true' : 'false'); 129 item.addEventListener('click', function (e) { 130 e.preventDefault(); 131 e.stopPropagation(); 132 setValue(select, opt.value); 133 close(root); 134 trigger.focus(); 135 }); 136 menu.appendChild(item); 137 }); 138 139 trigger.addEventListener('click', function (e) { 140 e.preventDefault(); 141 e.stopPropagation(); 142 if (root.classList.contains('is-open')) close(root); 143 else open(root); 144 }); 145 146 trigger.addEventListener('keydown', function (e) { 147 if (e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ') { 148 e.preventDefault(); 149 if (!root.classList.contains('is-open')) open(root); 150 } 151 }); 152 153 menu.addEventListener('keydown', function (e) { 154 var items = optionButtons(root); 155 var index = items.indexOf(document.activeElement); 156 if (e.key === 'ArrowDown') { 157 e.preventDefault(); 158 items[(index + 1 + items.length) % items.length].focus(); 159 } else if (e.key === 'ArrowUp') { 160 e.preventDefault(); 161 items[(index - 1 + items.length) % items.length].focus(); 162 } else if (e.key === 'Home') { 163 e.preventDefault(); 164 items[0].focus(); 165 } else if (e.key === 'End') { 166 e.preventDefault(); 167 items[items.length - 1].focus(); 168 } 169 }); 170 171 select.addEventListener('focus', function () { 172 trigger.focus(); 173 }); 174 175 select.addEventListener('change', function () { 176 syncUI(select); 177 }); 178 179 root.appendChild(trigger); 180 root.appendChild(menu); 181 } 182 183 function init(scope) {
184 (scope || document).querySelectorAll(SELECTOR).forEach(enhance); 185 } 186 187 document.addEventListener('click', function (e) { 188 if (openRoot && !openRoot.contains(e.target)) close(openRoot); 189 }); 190 191 document.addEventListener('keydown', function (e) { 192 if (e.key === 'Escape' && openRoot) { 193 var trigger = openRoot.querySelector('.custom-select-trigger'); 194 close(openRoot); 195 if (trigger) trigger.focus(); 196 } 197 }); 198 199 window.CustomSelect = { init: init, enhance: enhance }; 200 201 if (document.readyState === 'loading') { 202 document.addEventListener('DOMContentLoaded', function () { init(); }); 203 } else { 204 init(); 205 } 206})();
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.