1// paperNewFilling.js 2 3// Fetch papersNEW.json and generate the two-column paper cards with filtering 4fetch('jsons/papersNEW.json') 5 .then(response => { 6 if (!response.ok) { 7 throw new Error('Network response was not ok'); 8 } 9 return response.json(); 10 }) 11 .then(data => { 12 const container = document.getElementById('publications_wip_inner'); 13 const papers = data.publications; 14 15 // Assign publication numbers (J1, J2... C1, C2...) sorted by year ascending 16 const paperLabels = new Map(); 17 const journalsByYear = papers.filter(p => p.type === 'journal').sort((a, b) => a.year - b.year); 18 const conferencesByYear = papers.filter(p => p.type === 'conference').sort((a, b) => a.year - b.year); 19 const preprintsByYear = papers.filter(p => p.type === 'preprint').sort((a, b) => a.year - b.year); 20 journalsByYear.forEach((p, i) => paperLabels.set(p, `J${i + 1}`)); 21 conferencesByYear.forEach((p, i) => paperLabels.set(p, `C${i + 1}`)); 22 preprintsByYear.forEach((p, i) => paperLabels.set(p, `P${i + 1}`)); 23 24 // Badge colour by publication type 25 const typeBadgeClass = (type) => 26 type === 'journal' ? 'bg-success' 27 : type === 'preprint' ? 'bg-warning text-dark' 28 : 'bg-info'; 29 30 // Sort papers for display: by year descending, mixing journals and conferences 31 // Within the same year, sort by label number descending (highest first) 32 const allPapers = [...papers]; 33 allPapers.sort((a, b) => { 34 if (a.year !== b.year) return b.year - a.year; 35 // Within same year, sort by label number descending 36 const numA = parseInt((paperLabels.get(a) || 'X0').slice(1)); 37 const numB = parseInt((paperLabels.get(b) || 'X0').slice(1)); 38 return numB - numA; 39 }); 40 const sortedPapers = allPapers; 41 42 // Track selected years (empty set = all years shown) 43 const selectedYears = new Set(); 44 45 // Populate year badges 46 const yearsContainer = document.getElementById('filter-years-container'); 47 const years = [...new Set(sortedPapers.map(p => p.year))].sort((a, b) => b - a); 48 years.forEach(year => { 49 const badge = document.createElement('span'); 50 badge.classList.add('badge', 'bg-secondary', 'me-2', 'mb-1'); 51 badge.style.cursor = 'pointer'; 52 badge.style.fontSize = '0.9em'; 53 badge.style.padding = '6px 12px'; 54 badge.textContent = year; 55 badge.dataset.year = year; 56 57 badge.addEventListener('click', () => { 58 if (selectedYears.has(year)) { 59 selectedYears.delete(year); 60 badge.classList.remove('bg-dark'); 61 badge.classList.add('bg-secondary'); 62 } else { 63 selectedYears.add(year); 64 badge.classList.remove('bg-secondary'); 65 badge.classList.add('bg-dark'); 66 } 67 applyFilters(); 68 }); 69 70 yearsContainer.appendChild(badge); 71 }); 72 73 // Render papers into the container 74 function renderPapers(filteredPapers) { 75 container.innerHTML = ''; 76 77 if (filteredPapers.length === 0) { 78 container.innerHTML = '<div class="col-lg-8 text-center text-muted py-4">No papers match the current filters.</div>'; 79 return; 80 } 81 82 filteredPapers.forEach((paper, index) => { 83 // Format authors: bold "Stefano Lambiase" in the list 84 const authorsFormatted = paper.authors 85 .map(a => a === 'Stefano Lambiase' ? '<strong>S. Lambiase</strong>' : a) 86 .join(', '); 87 88 // Build the download button only if a link is available 89 const downloadBtn = paper.downloadLink 90 ? `<a class="btn btn-success btn-sm" href="${paper.downloadLink}" download>Download</a>` 91 : `<button class="btn btn-success btn-sm disabled" type="button" disabled>Not available</button>`; 92 93 // Build the DOI button if available 94 const doiBtn = paper.doi 95 ? `<a class="btn btn-primary btn-sm" href="https://doi.org/${paper.doi}" target="_blank" rel="noopener noreferrer">DOI</a>` 96 : ''; 97 98 // Build the Google Scholar search button 99 const scholarQuery = encodeURIComponent(paper.title); 100 const scholarBtn = `<a class="btn btn-warning btn-sm" href="https://scholar.google.com/scholar?q=${scholarQuery}" target="_blank" rel="noopener noreferrer">Scholar</a>`; 101 102 const col = document.createElement('div'); 103 col.classList.add('col-lg-6', 'pb-3'); 104 105 col.innerHTML = ` 106 <div class="card h-100"> 107 <div class="card-body d-flex flex-column"> 108 <div class="mb-2">
109 <span class="badge ${typeBadgeClass(paper.type)}">${paper.type}</span> 110 <span class="badge ${typeBadgeClass(paper.type)}">${paperLabels.get(paper)}</span> 111 <span class="badge bg-secondary">${paper.year}</span> 112 </div> 113 <h6 class="card-title"><strong>${paper.title}</strong></h6> 114 <p class="card-text text-muted small mb-1">${paper.venue}</p> 115 <p class="card-text small mt-auto pt-2">${authorsFormatted}</p> 116 <hr class="my-2"> 117 <div class="d-flex justify-content-end gap-2"> 118 ${doiBtn} 119 ${scholarBtn} 120 ${downloadBtn} 121 </div> 122 </div> 123 </div> 124 `; 125 126 container.appendChild(col); 127 }); 128 } 129 130 // Filter logic 131 function applyFilters() { 132 const textQuery = document.getElementById('filter-text').value.toLowerCase().trim(); 133 const typeFilter = document.getElementById('filter-type').value; 134 135 const filtered = sortedPapers.filter(paper => { 136 // Text filter: search in title, venue, and authors 137 if (textQuery) { 138 const searchable = [ 139 paper.title, 140 paper.venue, 141 paper.authors.join(' ') 142 ].join(' ').toLowerCase(); 143 if (!searchable.includes(textQuery)) return false; 144 } 145 146 // Year filter (if any years are selected, only show those) 147 if (selectedYears.size > 0 && !selectedYears.has(paper.year)) return false; 148 149 // Type filter 150 if (typeFilter && paper.type !== typeFilter) return false; 151 152 return true; 153 }); 154 155 renderPapers(filtered); 156 } 157 158 // Attach event listeners 159 document.getElementById('filter-text').addEventListener('input', applyFilters); 160 document.getElementById('filter-type').addEventListener('change', applyFilters); 161 162 // Initial render with all papers 163 renderPapers(sortedPapers); 164 165 // Selected Work / Featured papers â hand-picked via `featured: true` in 166 // the JSON. They render above the filters, keep the regular card 167 // structure but with a red accent border, a FEATURED badge, and an 168 // optional italic `featuredNote` under the authors. Featured papers 169 // also remain in the full list below. 170 const featuredPapers = papers 171 .filter(p => p.featured) 172 .sort((a, b) => b.year - a.year); 173 174 const featuredSection = document.getElementById('publications_featured_section'); 175 const featuredContainer = document.getElementById('publications_featured_inner'); 176 177 if (featuredSection && featuredContainer && featuredPapers.length > 0) { 178 featuredSection.style.display = ''; 179 renderFeatured(featuredPapers); 180 } 181 182 function renderFeatured(list) { 183 featuredContainer.innerHTML = ''; 184 list.forEach(paper => { 185 const authorsFormatted = paper.authors 186 .map(a => a === 'Stefano Lambiase' ? '<strong>S. Lambiase</strong>' : a) 187 .join(', '); 188 189 const downloadBtn = paper.downloadLink 190 ? `<a class="btn btn-success btn-sm" href="${paper.downloadLink}" download>Download</a>` 191 : `<button class="btn btn-success btn-sm disabled" type="button" disabled>Not available</button>`; 192 193 const doiBtn = paper.doi 194 ? `<a class="btn btn-primary btn-sm" href="https://doi.org/${paper.doi}" target="_blank" rel="noopener noreferrer">DOI</a>` 195 : ''; 196 197 const scholarQuery = encodeURIComponent(paper.title); 198 const scholarBtn = `<a class="btn btn-warning btn-sm" href="https://scholar.google.com/scholar?q=${scholarQuery}" target="_blank" rel="noopener noreferrer">Scholar</a>`; 199 200 const featuredNoteHtml = paper.featuredNote 201 ? `<p class="paper-featured-note small fst-italic text-muted mb-2">${paper.featuredNote}</p>` 202 : ''; 203 204 const col = document.createElement('div'); 205 col.classList.add('col-lg-10', 'pb-3'); 206 207 col.innerHTML = ` 208 <div class="card paper-featured h-100"> 209 <div class="card-body d-flex flex-column"> 210 <div class="mb-2 d-flex justify-content-between align-items-start flex-wrap gap-1"> 211 <div>
212 <span class="badge ${typeBadgeClass(paper.type)}">${paper.type}</span> 213 <span class="badge ${typeBadgeClass(paper.type)}">${paperLabels.get(paper)}</span> 214 <span class="badge bg-secondary">${paper.year}</span> 215 </div> 216 <span class="badge paper-featured-badge">Featured</span> 217 </div> 218 <h6 class="card-title"><strong>${paper.title}</strong></h6> 219 <p class="card-text text-muted small mb-1">${paper.venue}</p> 220 <p class="card-text small mb-1">${authorsFormatted}</p> 221 ${featuredNoteHtml} 222 <hr class="my-2"> 223 <div class="d-flex justify-content-end gap-2"> 224 ${doiBtn} 225 ${scholarBtn} 226 ${downloadBtn} 227 </div> 228 </div> 229 </div> 230 `; 231 featuredContainer.appendChild(col); 232 }); 233 } 234 }) 235 .catch(error => console.error(error));
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.