1// Papers Gallery functionality (similar to pipeline gallery) 2document.addEventListener('DOMContentLoaded', function() { 3 const papersSection = document.getElementById('papers-section'); 4 const papersContainer = document.getElementById('papers-container'); 5 const papersBtn = document.getElementById('papers-btn'); 6 const closePapersBtn = document.getElementById('close-papers-btn'); 7 8 if (!papersSection || !papersContainer || !papersBtn || !closePapersBtn || typeof window.PAPERS_REVIEW === 'undefined') { 9 return; 10 } 11 12 // Create category navigation menu (reuse styles) 13 const categoryNav = document.createElement('div'); 14 categoryNav.className = 'category-nav'; 15 const categoryMenu = document.createElement('div'); 16 categoryMenu.className = 'category-menu'; 17 categoryNav.appendChild(categoryMenu); 18 papersSection.insertBefore(categoryNav, papersContainer); 19 20 // Ensure a brief description card exists inside the container 21 function ensureDescription() { 22 let desc = document.getElementById('papers-description'); 23 if (!desc) { 24 desc = document.createElement('div'); 25 desc.id = 'papers-description'; 26 desc.className = 'workflow-info-content'; 27 desc.innerHTML = ` 28 <h3 style="color: var(--accent-color); margin-top: 0;">Important information</h3> 29 <p style="font-size: 1.1rem; line-height: 1.6;"> 30 This page lists benchmark studies and key literature relevant to MAG reconstruction. 31 When clicking on any paper, a view of its summary or an excerpt that describes the study, plus a key-figure, will be displayed. 32 Please keep in mind that this is not a comprehensive list, and you are invited to check the suggested papers completely to have a better overview of the work. 33 </p> 34 `; 35 // Insert inside the container so it shares the same width as sections 36 desc.style.gridColumn = '1 / -1'; 37 desc.style.width = '100%'; 38 } 39 // Attach to top of container 40 if (papersContainer.firstChild !== desc) { 41 papersContainer.insertBefore(desc, papersContainer.firstChild); 42 } 43 return desc; 44 } 45 46 // Back to top button 47 const backToTopBtn = initializeBackToTopButton(papersSection); 48 49 function handleScroll() { 50 const nav = papersSection.querySelector('.category-nav'); 51 const scrollPosition = papersSection.scrollTop; 52 if (scrollPosition > 300) nav.classList.add('hidden'); else nav.classList.remove('hidden'); 53 updateActiveCategory(); 54 } 55 papersSection.addEventListener('scroll', handleScroll); 56 57 // Build categories from data 58 const categories = Array.from(new Set(PAPERS_REVIEW.map(p => p.category))).sort((a, b) => a.localeCompare(b)); 59 60 let currentDetailCategory = null; 61 62 function createCategoryNav() { 63 categoryMenu.innerHTML = ''; 64 categories.forEach(category => { 65 const menuItem = document.createElement('a'); 66 menuItem.href = `#${category.toLowerCase().replace(/\s+/g, '-')}`; 67 menuItem.textContent = category; 68 menuItem.addEventListener('click', (e) => { 69 e.preventDefault(); 70 // If in detail view, rebuild list and expand the chosen category 71 if (currentDetailCategory !== null) { 72 createPapersItems(category); 73 currentDetailCategory = null; 74 } 75 // Scroll to the category header 76 setTimeout(() => { 77 const targetCategory = papersContainer.querySelector(`.gallery-category-header[data-category="${category}"]`); 78 if (targetCategory) { 79 targetCategory.scrollIntoView({ behavior: 'smooth' }); 80 categoryMenu.querySelectorAll('a').forEach(link => link.classList.remove('active')); 81 menuItem.classList.add('active'); 82 } 83 }, 0); 84 }); 85 categoryMenu.appendChild(menuItem); 86 }); 87 } 88 89 function updateActiveCategory() { 90 const headers = papersContainer.querySelectorAll('.gallery-category-header'); 91 const scrollPosition = papersSection.scrollTop;
92 headers.forEach(header => { 93 const category = header.dataset.category; 94 const headerTop = header.offsetTop - categoryNav.offsetHeight; 95 const headerBottom = headerTop + header.offsetHeight; 96 if (scrollPosition >= headerTop && scrollPosition < headerBottom) { 97 const menuItem = categoryMenu.querySelector(`a[href="#${category.toLowerCase().replace(/\s+/g, '-')}"]`); 98 if (menuItem) { 99 categoryMenu.querySelectorAll('a').forEach(link => link.classList.remove('active')); 100 menuItem.classList.add('active'); 101 } 102 } 103 }); 104 } 105 106 function createPapersItems(expandCategoryName) { 107 papersContainer.innerHTML = ''; 108 ensureDescription(); 109 // Group by category and sort by name 110 const byCategory = {}; 111 const sorted = [...PAPERS_REVIEW].sort((a, b) => (a.name || '').localeCompare(b.name || '', undefined, { sensitivity: 'base' })); 112 sorted.forEach(paper => { 113 const category = paper.category || 'Other'; 114 if (!byCategory[category]) byCategory[category] = []; 115 byCategory[category].push(paper); 116 }); 117 118 categories.forEach(category => { 119 if (byCategory[category] && byCategory[category].length > 0) { 120 // Category header with collapse/expand 121 const categoryHeader = document.createElement('div'); 122 categoryHeader.className = 'gallery-category-header'; 123 categoryHeader.dataset.category = category; 124 categoryHeader.innerHTML = `<h3>${category} <span class="category-hint" style="font-weight:400; opacity:0.8; font-size:0.9rem;">(click to expand)</span></h3>`; 125 papersContainer.appendChild(categoryHeader); 126 127 const listContainer = document.createElement('div'); 128 listContainer.className = 'papers-list-container'; 129 listContainer.style.display = 'none'; 130 // Make the list span the full gallery width 131 listContainer.style.gridColumn = '1 / -1'; 132 listContainer.style.width = '100%'; 133 papersContainer.appendChild(listContainer); 134 135 // Toggle category visibility when header clicked 136 categoryHeader.style.cursor = 'pointer'; 137 categoryHeader.addEventListener('click', () => { 138 const isHidden = listContainer.style.display === 'none'; 139 listContainer.style.display = isHidden ? 'block' : 'none'; 140 }); 141 142 // Build a simple list of paper titles 143 const ul = document.createElement('ul'); 144 ul.style.listStyle = 'none'; 145 ul.style.padding = '0'; 146 ul.style.margin = '0'; 147 ul.style.width = '100%'; 148 byCategory[category].forEach(paper => { 149 const li = document.createElement('li'); 150 li.style.margin = '0.25rem 0'; 151 li.style.width = '100%'; 152 const btn = document.createElement('button'); 153 btn.textContent = paper.name; 154 btn.style.width = '100%'; 155 btn.style.textAlign = 'left'; 156 btn.style.padding = '0.75rem 1rem'; 157 btn.style.border = '1px solid var(--border-color)'; 158 btn.style.background = 'var(--container-bg)'; 159 btn.style.color = 'var(--text-color)'; 160 btn.style.borderRadius = '8px'; 161 btn.style.cursor = 'pointer'; 162 btn.style.fontSize = '1.1rem'; 163 btn.addEventListener('mouseover', () => { btn.style.borderColor = 'var(--accent-color)'; }); 164 btn.addEventListener('mouseout', () => { btn.style.borderColor = 'var(--border-color)'; }); 165 btn.addEventListener('click', () => { 166 showPaperDetail(paper, category); 167 }); 168 li.appendChild(btn); 169 ul.appendChild(li); 170 }); 171 listContainer.appendChild(ul); 172 173 if (expandCategoryName && expandCategoryName === category) { 174 listContainer.style.display = 'block'; 175 } 176 } 177 }); 178 } 179 180 function showPaperDetail(paper, categoryToExpand) { 181 currentDetailCategory = categoryToExpand; 182 papersContainer.innerHTML = ''; 183 const detailWrapper = document.createElement('div'); 184 detailWrapper.className = 'gallery-item'; 185 const card = document.createElement('div'); 186 card.className = 'gallery-card'; 187 const content = document.createElement('div'); 188 content.className = 'gallery-content'; 189 content.innerHTML = ` 190 <h3>
190${paper.name}</h3> 191 <p style="margin:0 0 1rem 0;">${paper.abstract}</p> 192 <a href="${paper.link}" target="_blank" class="workflow-link"><i class="fas fa-external-link-alt"></i> Read paper</a> 193 `; 194 const img = document.createElement('img'); 195 img.src = `papers/${paper.id}.png`; 196 img.alt = paper.name; 197 img.className = 'paper-detail-image'; 198 img.onerror = function() { this.src = 'images/default-pipeline.png'; }; 199 200 const backBtn = document.createElement('a'); 201 backBtn.href = '#'; 202 backBtn.className = 'workflow-link'; 203 backBtn.style.marginTop = '1rem'; 204 backBtn.innerHTML = '<i class="fas fa-arrow-left"></i> Back to list'; 205 backBtn.addEventListener('click', (e) => { 206 e.preventDefault(); 207 createPapersItems(categoryToExpand); 208 const header = papersContainer.querySelector(`.gallery-category-header[data-category="${categoryToExpand}"]`); 209 if (header) header.scrollIntoView({ behavior: 'smooth' }); 210 }); 211 212 card.appendChild(content); 213 card.appendChild(img); 214 card.appendChild(backBtn); 215 detailWrapper.appendChild(card); 216 papersContainer.appendChild(detailWrapper); 217 } 218 219 function showPapers() { 220 papersSection.style.display = 'block'; 221 document.body.style.overflow = 'hidden'; 222 createPapersItems(); 223 } 224 225 function hidePapers() { 226 papersSection.style.display = 'none'; 227 document.body.style.overflow = 'auto'; 228 } 229 230 papersBtn.addEventListener('click', showPapers); 231 closePapersBtn.addEventListener('click', hidePapers); 232 233 // Initialize 234 createCategoryNav(); 235 createPapersItems(); 236}); 237 238
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.