/** * This script handles a scroll-based tab activation feature. * As the user scrolls through a designated 'wrapper' section, it * programmatically clicks on corresponding 'tab' links. * * How it works: * 1. It identifies a wrapper element with `[scrollingsticky="wrapper"]` and * tab elements with `[scrollingsticky="tab1"]`, `[scrollingsticky="tab2"]`, etc. * 2. It divides the vertical height of the wrapper into equal zones, one for each tab. * 3. It listens to the window's scroll event. * 4. It determines which zone the center of the user's viewport is currently in. * 5. If the user scrolls into a new zone, it triggers a `click()` event on the * corresponding tab link. This works for scrolling both down and up. * 6. It maintains a state to ensure a tab is only clicked once when its zone is entered, * not on every single pixel of scrolling. */ document.addEventListener('DOMContentLoaded', () => { // --- 1. SELECT ELEMENTS --- // Find the main container and the tab elements using their 'scrollingsticky' attribute. const scrollWrapper = document.querySelector('[scrollingsticky="wrapper"]'); const tabs = [ document.querySelector('[scrollingsticky="tab1"]'), document.querySelector('[scrollingsticky="tab2"]'), document.querySelector('[scrollingsticky="tab3"]'), ]; // --- 2. VALIDATION --- // If any of the required elements are not found on the page, log an error and stop the script. if (!scrollWrapper || tabs.some(tab => !tab)) { console.error( 'Scrolling Sticky Tab Error: One or more required elements with "scrollingsticky" attributes were not found.' ); return; } // --- 3. STATE MANAGEMENT --- // This variable will store the index of the currently active tab (0, 1, or 2). // We initialize it to -1 to signify that no tab is active initially. let currentlyActiveTabIndex = -1; // --- 4. THE SCROLL HANDLER FUNCTION --- const handleScrollActivation = () => { // Get the position and dimensions of the wrapper element relative to the viewport. const wrapperRect = scrollWrapper.getBoundingClientRect(); // Calculate the height of each "trigger zone". // The wrapper's total height is divided by the number of tabs. const zoneHeight = wrapperRect.height / tabs.length; // We use the vertical center of the viewport as our "trigger point". // This feels more natural than using the top edge. const viewportCenter = window.innerHeight / 2; // Determine how far the viewport center is from the top of the wrapper. // A negative value means the center is above the wrapper. // A positive value means the center is inside or below the wrapper. const scrollDistanceIntoWrapper = viewportCenter - wrapperRect.top; let targetIndex; // Check if our trigger point is within the bounds of the wrapper element. if ( scrollDistanceIntoWrapper >= 0 && scrollDistanceIntoWrapper <= wrapperRect.height ) { // If we are inside, calculate which zone we are in. // Math.floor() ensures we get an integer index (0, 1, or 2). targetIndex = Math.floor(scrollDistanceIntoWrapper / zoneHeight); } else if (scrollDistanceIntoWrapper > wrapperRect.height) { // If the trigger point has scrolled past the bottom of the wrapper, // the last tab should be considered active. targetIndex = tabs.length - 1; } else { // If the trigger point is above the wrapper, no tab is active. // We set the index to -1, which will not match any tab. targetIndex = -1; } // --- 5. TRIGGER CLICK EVENT --- // Only proceed if the calculated target tab is different from the currently active one. // This is a crucial optimization to prevent firing 'click' events on every scroll pixel. if (targetIndex !== currentlyActiveTabIndex) { // Update the state to the new active tab index. currentlyActiveTabIndex = targetIndex; // If the new index corresponds to a valid tab (i.e., not -1), // programmatically click it. if (currentlyActiveTabIndex !== -1 && tabs[currentlyActiveTabIndex]) { console.log( `Scrolling activated: Clicking on Tab ${currentlyActiveTabIndex + 1}` ); tabs[currentlyActiveTabIndex].click(); } } }; // --- 6. ATTACH EVENT LISTENER --- // Add the scroll event listener to the window. // The { passive: true } option is a performance optimization, telling the browser // that this listener will not prevent the default scroll behavior. window.addEventListener('scroll', handleScrollActivation, { passive: true }); // --- 7. INITIAL CHECK --- // Run the function once on page load. This ensures the correct tab is active // if the page loads with the wrapper already in view. handleScrollActivation(); });