PageSourceSearch

https://stefanolambiase.github.io/js/paperNewFilling.js

js stefanolambiase.github.io collected 2026-10-03 09:59:40 UTC 9,718 bytes, 235 lines download raw bytes

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.