fa0fdadb2fe50750c9a4087c59711039174ba5c2 jcasper Mon Jun 1 21:57:25 2026 -0700 Part of making metadata tables in faceted composites get a horizontal scrollbar, refs #36320 diff --git src/hg/js/facetedComposite.js src/hg/js/facetedComposite.js index c3e8641ac03..170169d36b6 100644 --- src/hg/js/facetedComposite.js +++ src/hg/js/facetedComposite.js @@ -207,31 +207,34 @@ // otherwise fall back to the first data column. let defaultSortCol = 1; // column 0 is checkboxes, 1 is first data col if (embeddedData.defaultSortField) { const target = embeddedData.defaultSortField.replace(/^_+/, "").toLowerCase(); const idx = colNames.findIndex( c => c.replace(/^_+/, "").toLowerCase() === target); if (idx >= 0) defaultSortCol = idx + 1; // +1 for the checkbox column } const table = $("#theMetaDataTable").DataTable({ data: metadata, deferRender: true, // seems faster columns: columns, columnDefs: [ { targets:0, render: DataTable.render.select() } ], - responsive: true, + // 'responsive' (collapsing overflow columns) is intentionally off: + // a wide table instead gets an internal horizontal scrollbar via + // the .table-xscroll wrapper added at the end of initTable. + responsive: false, layout: { topStart: 'pageLength', topEnd: null, // omit global search bottomStart: 'info', bottomEnd: 'paging' }, order: [[defaultSortCol, "asc"]], pageLength: 25, // show 25 rows per page by default lengthMenu: [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]], language: { lengthMenu: `Show _MENU_ ${itemLabel}`, select: { rows: { 0: "", 1: `1 ${singularLabel} selected`, @@ -407,30 +410,42 @@ const row = table.row(dataIndex); return row.select && row.selected(); }); // implement the 'select all' at the top of the checkbox column $("#select-all").closest("label").attr( "title", `Select all filtered ${itemLabel}`); $("#theMetaDataTable thead").on("click", "#select-all", function () { const rowIsChecked = this.checked; if (rowIsChecked) { table.rows({ search: "applied" }).select(); } else { table.rows({ search: "applied" }).deselect(); } }); + + // Wrap the table in a horizontally-scrolling box. When the metadata has + // many fields the table is wider than the viewport; this gives it its + // own internal X scrollbar instead of letting it spill off the right + // edge of the screen (which also dragged the "Show N" / paging controls + // off-screen). The toolbar rows stay outside this box, so they remain + // visible at the wrapper's width regardless of how wide the table gets. + const scrollBox = document.createElement("div"); + scrollBox.className = "table-xscroll"; + tableEl.parentNode.insertBefore(scrollBox, tableEl); + scrollBox.appendChild(tableEl); + return table; } // end initTable // Map of colName -> Map of unescapedValue -> spanElement, for dynamic counts const countSpans = new Map(); // Filter state for cross-facet count computation const checkboxFilters = new Map(); // colName -> Set<string> (raw values) const textFilters = new Map(); // colName -> lowercase string function updateFacetCounts(metadata) { // For each facet, count values among rows that pass all OTHER filters // (excluding this facet's own checkbox filter). This way, unchecked // values show how many rows would be added if you checked them. for (const [facetCol, valMap] of countSpans) {