1// Tools Table built from MAG_PIPELINES, similar layout/UX to table.js 2document.addEventListener('DOMContentLoaded', function() { 3 const section = document.getElementById('tools-table-section'); 4 const container = document.getElementById('tools-table-container'); 5 const openBtn = document.getElementById('tools-table-btn'); 6 const closeBtn = document.getElementById('close-tools-table-btn'); 7 8 if (!section || !container || !openBtn || !closeBtn) { 9 return; 10 } 11 12 // Config 13 const COLUMNS_PER_PAGE = 5; // show fewer because cells are longer text 14 let currentPage = 0; 15 const filterValues = {}; 16 17 // Back to top 18 const backToTopBtn = initializeBackToTopButton(section); 19 20 // Column definitions mapped to MAG_PIPELINES keys 21 const columnDefinitions = [ 22 { header: 'Number', key: 'index', noFilter: true }, 23 { header: 'Pipeline Name', key: 'name' }, 24 { header: 'QC', key: 'qc' }, 25 { header: 'Assembly', key: 'assembly' }, 26 { header: 'Binning', key: 'binning' }, 27 { header: 'Quality Assessment', key: 'qualityAssessment' }, 28 { header: 'Refinement', key: 'refinement' }, 29 { header: 'Taxonomy', key: 'taxonomy' }, 30 { header: 'Functional Annotation', key: 'functionalAnnotation' }, 31 { header: 'Other', key: 'other' } 32 ]; 33 34 function createTable() { 35 container.innerHTML = ''; 36 37 const navigationControls = document.createElement('div'); 38 navigationControls.className = 'table-navigation'; 39 40 const prevButton = document.createElement('button'); 41 prevButton.className = 'nav-control-btn'; 42 prevButton.textContent = 'â Previous Features'; 43 prevButton.addEventListener('click', () => changePage(-1)); 44 45 const nextButton = document.createElement('button'); 46 nextButton.className = 'nav-control-btn'; 47 nextButton.textContent = 'More Features â'; 48 nextButton.addEventListener('click', () => changePage(1)); 49 50 const pageInfo = document.createElement('span'); 51 pageInfo.className = 'page-info'; 52 53 navigationControls.appendChild(prevButton); 54 navigationControls.appendChild(pageInfo); 55 navigationControls.appendChild(nextButton); 56 container.appendChild(navigationControls); 57 58 const table = document.createElement('table'); 59 table.className = 'pipeline-table'; 60 61 const thead = document.createElement('thead'); 62 const headerRow = document.createElement('tr'); 63 64 columnDefinitions.forEach((col, index) => { 65 const th = document.createElement('th'); 66 th.dataset.columnIndex = index; 67 68 const headerText = document.createElement('div'); 69 headerText.textContent = col.header; 70 th.appendChild(headerText); 71 72 if (!col.noFilter) { 73 const filterInput = document.createElement('input'); 74 filterInput.type = 'text'; 75 filterInput.className = 'filter-input'; 76 filterInput.placeholder = 'Filter...'; 77 filterInput.addEventListener('input', filterTable); 78 th.appendChild(filterInput); 79 } 80 81 headerRow.appendChild(th); 82 }); 83 84 thead.appendChild(headerRow); 85 table.appendChild(thead); 86 87 const tbody = document.createElement('tbody'); 88 89 const DATA = (typeof window.MAG_PIPELINES_XLSX !== 'undefined') ? window.MAG_PIPELINES_XLSX : (typeof window.MAG_PIPELINES !== 'undefined' ? window.MAG_PIPELINES : []); 90 const sorted = [...DATA].sort((a, b) => (a.name || '').localeCompare(b.name || '', undefined, { sensitivity: 'base' })); 91 sorted.forEach((p, index) => { 92 const row = document.createElement('tr'); 93 columnDefinitions.forEach((col, colIndex) => { 94 const cell = document.createElement('td'); 95 cell.dataset.columnIndex = colIndex; 96 97 if (col.key === 'index') { 98 cell.textContent = index + 1; 99 } else if (col.key === 'name') { 100 const nameLink = document.createElement('a'); 101 nameLink.href = '#'; 102 nameLink.textContent = p.name || ''; 103 nameLink.addEventListener('click', (e) => { 104 e.preventDefault(); 105 hideToolsTable(); 106 const workflowSection = document.getElementById('workflow-section'); 107 const pipelineSelect = document.getElementById('pipeline-select'); 108 if (workflowSection && pipelineSelect) { 109 workflowSection.style.display = 'block'; 110 const id = mapNameToId(p.name); 111 if (id) { 112 pipelineSelect.value = id; 113 const event = new Event('change'); 114 pipelineSelect.dispatchEvent(event); 115 } 116 } 117 }); 118 cell.appendChild(nameLink); 119 } else { 120 const arr = p.attributes && Array.isArray(p.attributes[col.key]) ? p.attributes[col.key] : []; 121 cell.textContent = arr.length ? arr.join(', ') : ''; 122 } 123 124 row.appendChild(cell); 125 }); 126 tbody.appendChild(row); 127 }); 128 129 table.appendChild(tbody); 130 container.appendChild(table); 131 132 updatePageDisplay(); 133 } 134 135 function mapNameToId(name) { 136 if (typeof preLoadedObjects !== 'undefined') { 137 const match = preLoadedObjects.find(o => o.name.toLowerCase() === name.toLowerCase()); 138 return match ? match.id : ''; 139 } 140 return ''; 141 } 142 143 function changePage(delta) { 144 const totalColumns = document.querySelectorAll('#tools-table-section .pipeline-table th').length; 145 const totalPages = Math.ceil((totalColumns - 2) / (COLUMNS_PER_PAGE - 2)); 146 currentPage = Math.max(0, Math.min(currentPage + delta, totalPages - 1)); 147 updatePageDisplay(); 148 } 149 150 function updatePageDisplay() { 151 const tableEl = section.querySelector('.pipeline-table'); 152 if (!tableEl) return; 153 const totalColumns = tableEl.querySelectorAll('th').length; 154 const totalPages = Math.ceil((totalColumns - 2) / (COLUMNS_PER_PAGE - 2)); 155 156 const pageInfo = section.querySelector('.page-info'); 157 if (pageInfo) pageInfo.textContent = `Page ${currentPage + 1} of ${totalPages}`; 158 159 const startCol = currentPage * (COLUMNS_PER_PAGE - 2); 160 const endCol = Math.min(startCol + (COLUMNS_PER_PAGE - 2), totalColumns - 1); 161 162 section.querySelectorAll('.pipeline-table th, .pipeline-table td').forEach(element => { 163 const colIndex = parseInt(element.dataset.columnIndex); 164 if (colIndex <= 1) { 165 element.style.display = ''; 166 } else if (colIndex > startCol + 1 && colIndex <= endCol + 1) { 167 element.style.display = ''; 168 if (element.classList && element.classList.contains('filter-input')) { 169 element.value = filterValues[colIndex] || ''; 170 } 171 } else { 172 if (element.classList && element.classList.contains('filter-input')) { 173 filterValues[colIndex] = element.value; 174 } 175 element.style.display = 'none'; 176 } 177 }); 178 179 const prevButton = section.querySelector('.nav-control-btn:first-child'); 180 const nextButton = section.querySelector('.nav-control-btn:last-child'); 181 if (prevButton) prevButton.disabled = currentPage === 0; 182 if (nextButton) nextButton.disabled = currentPage === totalPages - 1; 183 } 184 185 function filterTable() { 186 const tableEl = section.querySelector('.pipeline-table'); 187 if (!tableEl) return; 188 const rows = tableEl.querySelectorAll('tbody tr'); 189 const allColumns = Array.from(tableEl.querySelectorAll('th')).map(th => parseInt(th.dataset.columnIndex)); 190 191 const filters = allColumns.map(colIndex => { 192 const filterInput = tableEl.querySelector(`th[data-column-index="${colIndex}"] .filter-input`); 193 if (filterInput) { 194 filterValues[colIndex] = filterInput.value; 195 return filterInput.value.toLowerCase(); 196 } 197 return filterValues[colIndex] ? filterValues[colIndex].toLowerCase() : ''; 198 }); 199 200 rows.forEach(row => { 201 const cells = Array.from(row.cells); 202 let show = true; 203 allColumns.forEach((colIndex, filterIndex) => { 204 const cell = cells[colIndex]; 205 const cellText = (cell.textContent || '').toLowerCase(); 206 const filterText = filters[filterIndex]; 207 if (filterText && !cellText.includes(filterText)) show = false;
208 }); 209 row.style.display = show ? '' : 'none'; 210 }); 211 } 212 213 function showToolsTable() { 214 section.style.display = 'block'; 215 document.body.style.overflow = 'hidden'; 216 // Reset state 217 currentPage = 0; 218 Object.keys(filterValues).forEach(k => delete filterValues[k]); 219 createTable(); 220 } 221 222 function hideToolsTable() { 223 section.style.display = 'none'; 224 document.body.style.overflow = 'auto'; 225 } 226 227 openBtn.addEventListener('click', showToolsTable); 228 closeBtn.addEventListener('click', hideToolsTable); 229 230 // Export 231 window.showToolsTable = showToolsTable; 232 window.hideToolsTable = hideToolsTable; 233}); 234 235
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.