1/** 2 * Secondary nav horizontal controls. 3 * Adds left/right arrow buttons to .secondary-nav and scrolls menu track. 4 */ 5(function () { 6 'use strict'; 7 8 function getTrack(root) { 9 return root.querySelector('.menu-container') || root.querySelector('ul.kb-navigation.menu'); 10 } 11 12 function updateState(root, track, prevBtn, nextBtn) { 13 var maxScrollLeft = Math.max(0, track.scrollWidth - track.clientWidth); 14 var scrollLeft = track.scrollLeft; 15 var nearStart = scrollLeft <= 2; 16 var nearEnd = scrollLeft >= maxScrollLeft - 2; 17 var hasOverflow = maxScrollLeft > 2; 18 19 root.classList.toggle('has-overflow', hasOverflow); 20 root.classList.toggle('show-left-fade', hasOverflow && !nearStart); 21 root.classList.toggle('show-right-fade', hasOverflow && !nearEnd); 22 root.classList.toggle('hide-left-arrow', !hasOverflow || nearStart); 23 root.classList.toggle('hide-right-arrow', !hasOverflow || nearEnd); 24 25 prevBtn.disabled = !hasOverflow || nearStart; 26 nextBtn.disabled = !hasOverflow || nearEnd; 27 } 28 29 function createButton(direction) { 30 var button = document.createElement('button'); 31 button.type = 'button'; 32 button.className = 'pubx-secondary-nav-control is-' + direction; 33 button.setAttribute('aria-label', direction === 'prev' ? 'Scroll secondary menu left' : 'Scroll secondary menu right'); 34 return button; 35 } 36 37 function initSecondaryNav(root) { 38 if (!root || root.dataset.pubxSecondaryNavReady === '1') { 39 return; 40 } 41 42 var track = getTrack(root); 43 if (!track) { 44 return; 45 } 46 47 var prevBtn = createButton('prev'); 48 var nextBtn = createButton('next'); 49 var stepPx = 100; 50 var initialResetDone = false; 51 52 function scrollByStep(dir) { 53 root.classList.add('has-interacted'); 54 var maxScrollLeft = Math.max(0, track.scrollWidth - track.clientWidth); 55 var amount = stepPx * dir; 56 var targetLeft = Math.max(0, Math.min(maxScrollLeft, track.scrollLeft + amount)); 57 track.scrollTo({ left: targetLeft, behavior: 'smooth' }); 58 } 59 60 prevBtn.addEventListener('click', function () { 61 scrollByStep(-1); 62 }); 63 64 nextBtn.addEventListener('click', function () { 65 scrollByStep(1); 66 }); 67 68 track.addEventListener('scroll', function () { 69 if (track.scrollLeft > 2) { 70 root.classList.add('has-interacted'); 71 } 72 updateState(root, track, prevBtn, nextBtn); 73 }); 74 75 track.addEventListener('wheel', function () { 76 root.classList.add('has-interacted'); 77 }, { passive: true }); 78 79 track.addEventListener('touchstart', function () { 80 root.classList.add('has-interacted'); 81 }, { passive: true }); 82 83 track.addEventListener('pointerdown', function () { 84 root.classList.add('has-interacted'); 85 }); 86 87 window.addEventListener('resize', function () { 88 updateState(root, track, prevBtn, nextBtn); 89 }); 90 91 root.appendChild(prevBtn); 92 root.appendChild(nextBtn); 93 root.dataset.pubxSecondaryNavReady = '1'; 94 95 // Force a stable initial left start so first menu items are reachable. 96 requestAnimationFrame(function () { 97 if (!initialResetDone) { 98 track.scrollLeft = 0; 99 initialResetDone = true; 100 } 101 updateState(root, track, prevBtn, nextBtn); 102 }); 103 } 104 105 function init() { 106 var navs = document.querySelectorAll('.secondary-nav'); 107 navs.forEach(initSecondaryNav); 108 } 109 110 if (document.readyState === 'loading') { 111 document.addEventListener('DOMContentLoaded', init); 112 } else { 113 init(); 114 } 115})();
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.