@@ -26,6 +26,7 @@ document.addEventListener('DOMContentLoaded', function() {
2626 // Initialize theme first
2727 initializeTheme ( ) ;
2828 initializeVersionSelector ( ) ;
29+ initializeStickyHeader ( ) ; // Add this line
2930 loadTestResults ( ) ;
3031} ) ;
3132
@@ -413,6 +414,151 @@ function renderOverallTable(bundlersNames, latestResults) {
413414 } ) ;
414415}
415416
417+ // Sticky header management
418+ let stickyHeader = null ;
419+ let perTestTable = null ;
420+ let perTestTableHead = null ;
421+ let stickyTableHead = null ;
422+ let perTestTableContainer = null ;
423+ let stickyTableContainer = null ;
424+ let isStickyHeaderVisible = false ;
425+ let isScrolling = false ; // Prevent infinite scroll loops
426+
427+ function initializeStickyHeader ( ) {
428+ stickyHeader = document . getElementById ( 'stickyHeader' ) ;
429+ perTestTable = document . getElementById ( 'perTestTable' ) ;
430+ perTestTableHead = document . getElementById ( 'perTestTableHead' ) ;
431+ stickyTableHead = document . getElementById ( 'stickyTableHead' ) ;
432+ perTestTableContainer = document . getElementById ( 'perTestTableContainer' ) ;
433+ stickyTableContainer = document . getElementById ( 'stickyTableContainer' ) ;
434+
435+ if ( ! stickyHeader || ! perTestTable || ! perTestTableHead || ! stickyTableHead || ! perTestTableContainer || ! stickyTableContainer ) {
436+ console . warn ( 'Sticky header elements not found' ) ;
437+ return ;
438+ }
439+
440+ // Add scroll event listeners
441+ window . addEventListener ( 'scroll' , handleVerticalScroll ) ;
442+ perTestTableContainer . addEventListener ( 'scroll' , handleHorizontalScroll ) ;
443+ stickyTableContainer . addEventListener ( 'scroll' , handleStickyHorizontalScroll ) ;
444+
445+ // Add resize event listener to update column widths
446+ window . addEventListener ( 'resize' , updateStickyHeaderWidths ) ;
447+ }
448+
449+ function handleVerticalScroll ( ) {
450+ if ( ! perTestTable || ! stickyHeader ) return ;
451+
452+ const tableRect = perTestTable . getBoundingClientRect ( ) ;
453+ const tableTop = tableRect . top ;
454+ const tableBottom = tableRect . bottom ;
455+ const headerHeight = perTestTableHead . offsetHeight ;
456+
457+ // Show sticky header when original header is out of view
458+ if ( tableTop < 0 && tableBottom > headerHeight ) {
459+ if ( ! isStickyHeaderVisible ) {
460+ showStickyHeader ( ) ;
461+ }
462+ } else {
463+ if ( isStickyHeaderVisible ) {
464+ hideStickyHeader ( ) ;
465+ }
466+ }
467+ }
468+
469+ function handleHorizontalScroll ( ) {
470+ if ( ! stickyTableContainer || isScrolling ) return ;
471+
472+ isScrolling = true ;
473+ stickyTableContainer . scrollLeft = perTestTableContainer . scrollLeft ;
474+
475+ // Reset the flag after a short delay
476+ setTimeout ( ( ) => {
477+ isScrolling = false ;
478+ } , 10 ) ;
479+ }
480+
481+ function handleStickyHorizontalScroll ( ) {
482+ if ( ! perTestTableContainer || isScrolling ) return ;
483+
484+ isScrolling = true ;
485+ perTestTableContainer . scrollLeft = stickyTableContainer . scrollLeft ;
486+
487+ // Reset the flag after a short delay
488+ setTimeout ( ( ) => {
489+ isScrolling = false ;
490+ } , 10 ) ;
491+ }
492+
493+ function showStickyHeader ( ) {
494+ if ( ! stickyHeader ) return ;
495+
496+ stickyHeader . classList . remove ( 'hidden' ) ;
497+ isStickyHeaderVisible = true ;
498+
499+ // Update column widths to match the original table
500+ updateStickyHeaderWidths ( ) ;
501+
502+ // Sync the horizontal scroll position
503+ if ( perTestTableContainer && stickyTableContainer ) {
504+ stickyTableContainer . scrollLeft = perTestTableContainer . scrollLeft ;
505+ }
506+ }
507+
508+ function hideStickyHeader ( ) {
509+ if ( ! stickyHeader ) return ;
510+
511+ stickyHeader . classList . add ( 'hidden' ) ;
512+ isStickyHeaderVisible = false ;
513+ }
514+
515+ function updateStickyHeaderWidths ( ) {
516+ if ( ! perTestTableHead || ! stickyTableHead ) return ;
517+
518+ // Copy the header structure from the original table
519+ stickyTableHead . innerHTML = perTestTableHead . innerHTML ;
520+
521+ // Get all header cells from both tables
522+ const originalHeaders = perTestTableHead . querySelectorAll ( 'th' ) ;
523+ const stickyHeaders = stickyTableHead . querySelectorAll ( 'th' ) ;
524+
525+ // Match the widths of each column
526+ for ( let i = 0 ; i < originalHeaders . length ; i ++ ) {
527+ if ( stickyHeaders [ i ] ) {
528+ const originalWidth = originalHeaders [ i ] . offsetWidth ;
529+ stickyHeaders [ i ] . style . width = `${ originalWidth } px` ;
530+ stickyHeaders [ i ] . style . minWidth = `${ originalWidth } px` ;
531+ }
532+ }
533+
534+ // Ensure both containers have the same scroll width
535+ if ( perTestTableContainer && stickyTableContainer ) {
536+ stickyTableContainer . style . width = `${ perTestTableContainer . offsetWidth } px` ;
537+ }
538+ }
539+
540+ // Add this to the existing functions for better performance
541+ function debounce ( func , wait ) {
542+ let timeout ;
543+ return function executedFunction ( ...args ) {
544+ const later = ( ) => {
545+ clearTimeout ( timeout ) ;
546+ func ( ...args ) ;
547+ } ;
548+ clearTimeout ( timeout ) ;
549+ timeout = setTimeout ( later , wait ) ;
550+ } ;
551+ }
552+
553+ // Use debounced scroll handlers for better performance
554+ const debouncedHandleHorizontalScroll = debounce ( handleHorizontalScroll , 5 ) ;
555+ const debouncedHandleStickyHorizontalScroll = debounce ( handleStickyHorizontalScroll , 5 ) ;
556+
557+ // Update the event listeners
558+ perTestTableContainer . addEventListener ( 'scroll' , debouncedHandleHorizontalScroll ) ;
559+ stickyTableContainer . addEventListener ( 'scroll' , debouncedHandleStickyHorizontalScroll ) ;
560+
561+ // Modify the existing renderPerTestTable function to also update sticky header
416562function renderPerTestTable ( bundlersNames , bundlersPerTestResults ) {
417563 const tableHead = document . getElementById ( 'perTestTableHead' ) ;
418564 const tableBody = document . getElementById ( 'perTestTableBody' ) ;
@@ -468,6 +614,13 @@ function renderPerTestTable(bundlersNames, bundlersPerTestResults) {
468614
469615 tableBody . appendChild ( row ) ;
470616 } ) ;
617+
618+ // Update sticky header after a short delay to ensure table is rendered
619+ setTimeout ( ( ) => {
620+ if ( isStickyHeaderVisible ) {
621+ updateStickyHeaderWidths ( ) ;
622+ }
623+ } , 100 ) ;
471624}
472625
473626function getTestResultDisplayEmoji ( result ) {
0 commit comments