1/* Progressive enhancement: both rankings remain readable without JavaScript. */ 2(function () { 3 'use strict'; 4 function init(root) { 5 const controls = root.querySelector('[data-ap-top-controls]'); 6 if (!controls || root.dataset.apTabsReady) return; 7 const list = controls.querySelector('.ap-top-ten__tabs'); 8 const buttons = Array.from(list.querySelectorAll('button')); 9 const panels = buttons.map(button => root.querySelector('#' + button.getAttribute('aria-controls'))); 10 if (buttons.length !== 2 || panels.some(panel => !panel)) return; 11 function select(index, focus) { 12 buttons.forEach((button, i) => { 13 button.setAttribute('aria-selected', String(i === index)); 14 button.tabIndex = i === index ? 0 : -1; 15 panels[i].hidden = i !== index; 16 }); 17 if (focus) buttons[index].focus(); 18 } 19 list.setAttribute('role', 'tablist'); 20 buttons.forEach((button, index) => { 21 button.setAttribute('role', 'tab'); 22 panels[index].setAttribute('role', 'tabpanel'); 23 panels[index].setAttribute('aria-labelledby', button.id); 24 panels[index].tabIndex = 0; 25 button.addEventListener('click', () => select(index, false)); 26 button.addEventListener('keydown', event => { 27 if (!['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) return; 28 event.preventDefault(); 29 const next = event.key === 'Home' ? 0 : event.key === 'End' ? buttons.length - 1 : (index + (event.key === 'ArrowRight' ? 1 : -1) + buttons.length) % buttons.length; 30 select(next, true); 31 }); 32 }); 33 root.dataset.apTabsReady = 'true'; 34 select(0, false); 35 controls.hidden = false; 36 } 37 function start() { document.querySelectorAll('[data-ap-top-tabs]').forEach(init); } 38 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start); 39 else start(); 40})();
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.