PageSourceSearch

https://toladner.github.io/js/publications.js

js toladner.github.io collected 2026-10-03 10:05:27 UTC 10,527 bytes, 186 lines download raw bytes

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.