Untitled

 avatar
unknown
javascript
11 days ago
5.2 kB
4
Indexable
/**
 * Stores only the original vertical position of each header cell.
 * If the screen width is below 992px, resets the header tile positions.
 */
const initializeHeaderTilePositions = () => {
    if (!window.matchMedia('(min-width: 992px)').matches) {
        resetHeaderTilePositions();
        return;
    }

    const headerCells = document.querySelectorAll('thead .bundle-table__wrapper--cell');
    if (!headerCells.length) return;

    headerCells.forEach(headerCell => {
        const cellRect = headerCell.getBoundingClientRect();
        headerCell.dataset.originalTop = Math.round(cellRect.top + window.scrollY);
        headerCell.style.setProperty('--fixed-header-height', `${Math.round(cellRect.height)}px`);
    });
};

/**
 * Removes stored originalTop positions from the dataset.
 */
const resetHeaderTilePositions = () => {
    const headerCells = document.querySelectorAll('thead .bundle-table__wrapper--cell');
    if (!headerCells.length) return;

    headerCells.forEach(headerCell => {
        delete headerCell.dataset.originalTop;
        delete headerCell.dataset.originalBottom;
        headerCell.style.removeProperty('--fixed-header-height');
    });
};

/**
 * Indicates whether the user is currently scrolling.
 */
let isUserScrolling = false;

/**
 * Updates the position of header tiles for a sticky header effect.
 */
const updateHeaderTilePositions = () => {
    // Prevent reentry if already scrolling
    if (isUserScrolling) return;
    isUserScrolling = true;

    requestAnimationFrame(() => {
        const headerCells = document.querySelectorAll('thead .bundle-table__wrapper--cell');
        const tableContainer = document.querySelector('.bundle-table-container');
        const priceCell = document.querySelector('.bundle-table__wrapper--cell--price');

        if (!headerCells.length || !tableContainer || !priceCell) {
            isUserScrolling = false;
            return;
        }

        const containerRect = tableContainer.getBoundingClientRect();
        const priceRect = priceCell.getBoundingClientRect();
        const priceDistanceToTop = Math.round(priceRect.top);

        headerCells.forEach(headerCell => {
            const headerTile = headerCell.querySelector('.bundle-table__header-tile');
            const originalTop = parseFloat(headerCell.dataset.originalTop);

            if (!headerTile || isNaN(originalTop)) return;

            const cellRect = headerCell.getBoundingClientRect();
            const cellHeight = cellRect.height;
            const offsetLeft = cellRect.left - containerRect.left;

            const shouldFixHeader = window.scrollY > originalTop;
            headerTile.classList.toggle('fixed', shouldFixHeader);

            if (shouldFixHeader) {
                // variable for parent left padding
                const LEFT_OFFSET = 6;
                headerTile.style.setProperty('--fixed-header-left', `${offsetLeft + LEFT_OFFSET}px`);
            } else {
                headerTile.style.removeProperty('--fixed-header-left');
            }

            const heightDifference = priceDistanceToTop - cellHeight;

            if (cellHeight > priceDistanceToTop) {
                const fixedHeaderTop = Math.max(heightDifference, -cellHeight);
                headerTile.style.setProperty('--fixed-header-top', `${fixedHeaderTop}px`);
            } else {
                headerTile.style.removeProperty('--fixed-header-top');
            }
        });

        isUserScrolling = false;
    });
};


/**
 * Monitors scroll events in the table container and updates header tiles accordingly.
 */
const monitorTableContainerScroll = () => {
    const tableContainer = document.querySelector('.bundle-table-container');
    if (!tableContainer) return;

    tableContainer.addEventListener('scroll', () => {
        if (window.matchMedia('(min-width: 992px)').matches) {
            initializeHeaderTilePositions();
            updateHeaderTilePositions();
        } else {
            resetHeaderTilePositions();
            resetHeaderTileStyles();
        }
    });
};

/**
 * Resets the styles applied to header tiles (removes the 'fixed' class and inline styles).
 */
const resetHeaderTileStyles = () => {
    const headerCells = document.querySelectorAll('thead .bundle-table__wrapper--cell');
    if (!headerCells.length) return;

    headerCells.forEach(headerCell => {
        const headerTile = headerCell.querySelector('.bundle-table__header-tile');
        if (!headerTile) return;

        headerTile.classList.remove('fixed');
        headerTile.style.removeProperty('--fixed-header-left');
        headerTile.style.removeProperty('--fixed-header-top');
    });
};

/**
 * Handles window resize events to re-initialize or reset header tile positions/styles.
 */
const handleWindowResize = () => {
    if (window.matchMedia('(min-width: 992px)').matches) {
        initializeHeaderTilePositions();
        updateHeaderTilePositions();
    } else {
        resetHeaderTilePositions();
        resetHeaderTileStyles();
    }
};
Leave a Comment