1document.addEventListener("DOMContentLoaded", function () { 2 const apiUrl = 'https://mediatum.ub.tum.de/services/export/node/670506/allchildren?q=author=ladner%20or%20author-contrib=ladner%20or%20author.surname=ladner'; 3 const container = document.getElementById('publication-container'); 4 5 // Show placeholder cards while loading 6 function createPlaceholderCard() { 7 const cardDiv = document.createElement('div'); 8 cardDiv.className = 'card mb-4'; 9 cardDiv.innerHTML = ` 10 <div class="card-body placeholder-glow"> 11 <h5 class="card-title mb-3"><span class="placeholder col-8"></span></h5> 12 <p class="card-text mb-2"><span class="placeholder col-6"></span><br><small class="text-muted"><span class="placeholder col-4"></span></small></p> 13 <div> 14 <a class="btn btn-outline-primary btn-sm me-2 disabled"><i class="bi bi-link-45deg"></i> <span class="placeholder placeholder-sm" style="width: 25px;"></span></a> 15 <a class="btn btn-outline-secondary btn-sm me-2 disabled"><i class="bi bi-search"></i> <span class="placeholder placeholder-sm" style="width: 70px;"></span></a> 16 <a class="btn btn-outline-secondary btn-sm disabled"><i class="bi bi-file-earmark-pdf"></i> <span class="placeholder placeholder-sm" style="width: 25px;"></span></a> 17 </div> 18 </div> 19 `; 20 return cardDiv; 21 } 22 23 const yearHeader = document.createElement('h4'); 24 yearHeader.className = 'year-header placeholder-glow'; 25 yearHeader.innerHTML = '<span class="placeholder" style="width: 60px;"></span>'; 26 container.appendChild(yearHeader); 27 28 for (let i = 0; i < 3; i++) { 29 container.appendChild(createPlaceholderCard()); 30 } 31 32 fetch(apiUrl) 33 .then(response => response.text()) 34 .then(xmlText => { 35 const parser = new DOMParser(); 36 const xmlDoc = parser.parseFromString(xmlText, 'application/xml'); 37 const nodes = Array.from(xmlDoc.getElementsByTagName('node')); 38 39 // Extract all data once per node 40 const pubs = nodes.map(node => { 41 const title = node.querySelector("attribute[name='title-contrib']")?.textContent || node.querySelector("attribute[name='reporttitle']")?.textContent || node.querySelector("attribute[name='title']")?.textContent || 'No title available'; 42 const rawAuthors = (() => { 43 const a = node.querySelector("attribute[name='author-contrib']")?.textContent || node.querySelector("attribute[name='author']")?.textContent; 44 if (a) return a; 45 const firstName = node.querySelector("attribute[name='author.firstname']")?.textContent?.trim().split(/\s+/)[0]; 46 const lastName = node.querySelector("attribute[name='author.surname']")?.textContent?.trim(); 47 if (firstName && lastName) return `${firstName} ${lastName}`; 48 return 'No authors available'; 49 })(); 50 const venue = node.querySelector("attribute[name='journal-title']")?.textContent || 51 node.querySelector("attribute[name='congresstitle']")?.textContent || 52 node.querySelector("attribute[name='booktitle']")?.textContent || 53 node.querySelector("attribute[name='contracting-organization']")?.textContent || 54 (node.querySelector("attribute[name='pdf_subject']")?.textContent ? node.querySelector("attribute[name='pdf_subject']").textContent + ' · Technical University of Munich' : undefined) || 55 node.querySelector("attribute[name='type']")?.textContent || 'No venue available'; 56 const year = node.querySelector("attribute[name='year']")?.textContent?.split('-')[0] || 'No year available'; 57 const id = node.getAttribute('id'); 58 const isDiss = node.getAttribute('type') === 'document/diss'; 59 let doi = node.querySelector("attribute[name='doi']")?.textContent; 60 if (doi) doi = `https://doi.org/${doi}`; 61 if (!doi && isDiss) doi = `https://mediatum.ub.tum.de/${id}`; 62 let www = node.querySelector("attribute[name='www-address']")?.textContent; 63 const pdf = node.querySelector("file[mime-type='application/pdf']")?.getAttribute('filename'); 64 65 // Determine author priority: 66 // 0 = sole first author, 1 = shared first author, 2 = remaining, 3 = competition report 67 const isCompetition = /ARCH-COMP|VNN-COMP/i.test(title) || /ARCH-COMP|VNN-COMP/i.test(venue); 68 const isArxiv = /arxiv/i.test(venue); 69 let priority = 2; 70 let isFirstAuthored = false;
71 72 if (isCompetition) { 73 priority = 3; 74 } else if (rawAuthors.includes(';')) { 75 const authorList = rawAuthors.split(';').map(a => a.trim()); 76 const firstAuthor = authorList[0]; 77 const hasAsterisk = authorList.some(a => a.includes('*')); 78 if (/Ladner/.test(firstAuthor) && /Tobias/.test(firstAuthor)) { 79 priority = hasAsterisk ? 1 : 0; 80 isFirstAuthored = true; 81 } else if (authorList.some(a => a.includes('*') && /Ladner/.test(a) && /Tobias/.test(a))) { 82 priority = 1; 83 isFirstAuthored = true; 84 } 85 } else { 86 const firstPart = rawAuthors.split(',')[0].trim(); 87 if (/Tobias/.test(firstPart) && /Ladner/.test(firstPart)) { 88 priority = rawAuthors.includes('*') ? 1 : 0; 89 isFirstAuthored = true; 90 } else if (/Tobias/.test(rawAuthors) && /Ladner\s*\*/.test(rawAuthors)) { 91 priority = 1; 92 isFirstAuthored = true; 93 } 94 } 95 96 // Format authors 97 let authors = rawAuthors; 98 if (authors.includes(';')) { 99 authors = authors.split(';').map(name => { 100 let [last, first] = name.trim().split(', '); 101 if (!first) return last; 102 return `${first} ${last}`; 103 }).join(', '); 104 } 105 authors = authors.split(',').map(name => { 106 return name.split('*').map(part => (/Tobias/.test(part) && /Ladner/.test(part)) ? `<u>${part}</u>` : part).join('*'); 107 }); 108 if (authors.length === 2) { 109 authors = authors.join(' and '); 110 } else { 111 authors = authors.join(', ').replace(/, ([^,]+)$/, ', and $1'); 112 } 113 114 // Format links 115 let openreview = undefined; 116 if (www?.toLowerCase().includes('openreview')) { 117 openreview = www.split(';')[0]; 118 } else if (!doi && www) { 119 doi = www.split(';')[0]; 120 } else { 121 www = undefined; 122 } 123 124 return { 125 title, authors, venue, year, 126 yearNum: parseInt(year, 10) || 0, 127 doi, openreview, pdf, id, 128 priority, isArxiv: isArxiv ? 1 : 0, 129 isCompetition, isFirstAuthored, 130 isPreprint: isArxiv && !isCompetition, 131 }; 132 }); 133 134 // Sort: year (desc), author priority, arxiv last, title (asc) 135 pubs.sort((a, b) => { 136 if (a.yearNum !== b.yearNum) return b.yearNum - a.yearNum; 137 if (a.priority !== b.priority) return a.priority - b.priority; 138 if (a.isArxiv !== b.isArxiv) return a.isArxiv - b.isArxiv; 139 return a.title.toLowerCase().localeCompare(b.title.toLowerCase()); 140 }); 141 142 // Clear placeholders and render 143 container.innerHTML = ''; 144 let lastYear = null; 145 146 pubs.forEach(pub => { 147 if (pub.year !== lastYear) { 148 const yearHeader = document.createElement('h4'); 149 yearHeader.className = 'year-header'; 150 yearHeader.textContent = pub.year; 151 container.appendChild(yearHeader); 152 lastYear = pub.year; 153 } 154 155 const cardDiv = document.createElement('div'); 156 cardDiv.className = 'card mb-4'; 157 cardDiv.innerHTML = ` 158 <div class="card-body"> 159 <h5 class="card-title mb-3">${pub.title}</h5> 160 <p class="card-text mb-2">${pub.authors}<br><small class="text-muted">${pub.venue} · ${pub.year}</small></p> 161 <div> 162 ${pub.doi ? `<a href="${pub.doi}" target="_blank" class="btn btn-outline-primary btn-sm me-2"><i class="bi bi-link-45deg"></i> DOI</a>` : ''} 163 ${pub.openreview ? `<a href="${pub.openreview}" target="_blank" class="btn btn-outline-secondary btn-sm me-2"><i class="bi bi-search"></i> OpenReview</a>` : ''} 164 ${pub.pdf ? `<a href="https://mediatum.ub.tum.de/doc/${pub.id}/${pub.pdf}" target="_blank" class="btn btn-outline-secondary btn-sm"><i class="bi bi-file-earmark-pdf"></i> PDF</a>` : ''} 165 </div> 166 </div> 167 `; 168 container.appendChild(cardDiv); 169 }); 170 171 // Summary statistics 172 const firstAuthoredCount = pubs.filter(p => p.isFirstAuthored).length; 173 const preprintCount = pubs.filter(p => p.isPreprint).length; 174 const competitionCount = pubs.filter(p => p.isCompetition).length; 175 176 const summary = document.createElement('p'); 177 summary.className = 'text-center text-muted mt-3'; 178 summary.style.fontSize = '0.75rem'; 179 summary.textContent = `${pubs.length} publications · ${firstAuthoredCount} (co-)first-authored · ${preprintCount} preprints · ${competitionCount} competition reports`;
180 container.appendChild(summary); 181 }) 182 .catch(error => { 183 console.error('Error fetching or parsing XML:', error); 184 container.innerHTML = '<div class="alert alert-danger">Error loading publications. Please try again later.</div>'; 185 }); 186});
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.