BibliographyBackbone: Difference between revisions
From Illustrations in German Translations of Mark Twain's Works
No edit summary |
No edit summary |
||
| Line 3: | Line 3: | ||
<button id="generateBtn" style=" | |||
<button id=" | |||
background-color: #008CBA; | background-color: #008CBA; | ||
color: white; | color: white; | ||
| Line 13: | Line 12: | ||
cursor: pointer; | cursor: pointer; | ||
margin-bottom: 1rem; | margin-bottom: 1rem; | ||
"> | ">Generate Bibliography HTML</button> | ||
<textarea id="bibOutput" style=" | <textarea id="bibOutput" style=" | ||
| Line 30: | Line 29: | ||
<script> | <script> | ||
(function() { | (function() { | ||
async function | function escapeHtml(text) { | ||
console.log(' | if (!text) return ''; | ||
const map = { | |||
'&': '&', | |||
'<': '<', | |||
'>': '>', | |||
'"': '"', | |||
"'": ''' | |||
}; | |||
return text.replace(/[&<>"']/g, m => map[m]); | |||
} | |||
function formatAuthors(authors) { | |||
if (!authors || authors.length === 0) return ''; | |||
if (authors.length === 1) { | |||
const a = authors[0]; | |||
return a.given ? `${a.family}, ${a.given}` : a.family; | |||
} | |||
if (authors.length === 2) { | |||
const a1 = authors[0]; | |||
const a2 = authors[1]; | |||
const name1 = a1.given ? `${a1.family}, ${a1.given}` : a1.family; | |||
const name2 = a2.given ? `${a2.family}, ${a2.given}` : a2.family; | |||
return `${name1}, and ${name2}`; | |||
} | |||
const a = authors[0]; | |||
const name = a.given ? `${a.family}, ${a.given}` : a.family; | |||
return `${name}, et al.`; | |||
} | |||
function formatMLA9(entry) { | |||
let citation = ''; | |||
// Autoren | |||
if (entry.authors && entry.authors.length > 0) { | |||
citation += formatAuthors(entry.authors) + '. '; | |||
} | |||
// Titel | |||
if (entry.title) { | |||
if (entry.type === 'bookSection' || entry.type === 'book') { | |||
citation += `<i>${escapeHtml(entry.title)}</i>. `; | |||
} else { | |||
citation += `"${escapeHtml(entry.title)}." `; | |||
} | |||
} | |||
// Container | |||
if (entry.container) { | |||
citation += `<i>${escapeHtml(entry.container)}</i>. `; | |||
} | |||
// Jahr | |||
if (entry.year) { | |||
citation += `${entry.year}. `; | |||
} | |||
// URL | |||
if (entry.url) { | |||
citation += `<a href="${escapeHtml(entry.url)}" target="_blank">${escapeHtml(entry.url)}</a>.`; | |||
} else { | |||
citation = citation.trim(); | |||
if (!citation.endsWith('.')) { | |||
citation += '.'; | |||
} | |||
} | |||
return citation; | |||
} | |||
function generateTagsAttribute(tags) { | |||
if (!tags || tags.length === 0) return ''; | |||
const normalized = tags | |||
.map(tag => tag.toLowerCase().replace(/\s+/g, '_')) | |||
.join(' '); | |||
return ` data-tags="${normalized}"`; | |||
} | |||
function generateTagSpans(tags) { | |||
if (!tags || tags.length === 0) return ''; | |||
return tags | |||
.map(tag => { | |||
const normalized = tag.toLowerCase().replace(/\s+/g, '_'); | |||
return `<span class="tag" data-tag="${normalized}">${escapeHtml(tag)}</span>`; | |||
}) | |||
.join('\n '); | |||
} | |||
function generateBibEntry(entry, index) { | |||
const mlaFormatted = formatMLA9(entry); | |||
const tagsAttr = generateTagsAttribute(entry.tags); | |||
const tagSpans = generateTagSpans(entry.tags); | |||
const abstract = entry.abstract ? escapeHtml(entry.abstract) : ''; | |||
return `<!-- ${index} --> | |||
<div class="bib-entry"${tagsAttr}> | |||
<h3>${mlaFormatted}</h3> | |||
<div class="bib-tags"> | |||
${tagSpans} | |||
</div> | |||
<p class="short-abstract">${abstract || '(No abstract available)'}</p> | |||
<button class="expand-btn">Show Abstract</button> | |||
<div class="abstract hidden"> | |||
<p>${abstract || 'No abstract available.'}</p> | |||
</div> | |||
</div>`; | |||
} | |||
async function generateBibliography() { | |||
console.log('generateBibliography aufgerufen'); | |||
const output = document.getElementById('bibOutput'); | const output = document.getElementById('bibOutput'); | ||
if (!output) { | if (!output) { | ||
console.error('bibOutput | console.error('bibOutput not found'); | ||
return; | return; | ||
} | } | ||
output.value = 'Lade...'; | output.value = 'Lade Daten...'; | ||
try { | try { | ||
const response = await fetch('/BibliographyData?action=raw'); | const response = await fetch('/BibliographyData?action=raw'); | ||
const | if (!response.ok) throw new Error(`HTTP ${response.status}`); | ||
output.value = | |||
console.log('Fertig - ' + | const entries = await response.json(); | ||
console.log('JSON geparst, ' + entries.length + ' Einträge'); | |||
// Filtere irrelevante Einträge | |||
const filtered = entries.filter(entry => { | |||
if (entry.tags && entry.tags.includes('Not relevant for Mark Twain')) { | |||
return false; | |||
} | |||
if (!entry.title || entry.title.trim() === 'Untitled') { | |||
return false; | |||
} | |||
return true; | |||
}); | |||
// Extrahiere alle Tags | |||
const allTags = new Set(); | |||
filtered.forEach(entry => { | |||
if (entry.tags && Array.isArray(entry.tags)) { | |||
entry.tags.forEach(tag => allTags.add(tag)); | |||
} | |||
}); | |||
// Generiere HTML | |||
const tagSpans = Array.from(allTags) | |||
.sort() | |||
.map(tag => { | |||
const normalized = tag.toLowerCase().replace(/\s+/g, '_'); | |||
return `<span class="tag" data-tag="${normalized}">${escapeHtml(tag)}</span>`; | |||
}) | |||
.join('\n '); | |||
const entryHTML = filtered | |||
.map((entry, i) => generateBibEntry(entry, i + 1)) | |||
.join('\n\n'); | |||
const html = `<div class="bib-tags"> | |||
${tagSpans} | |||
</div> | |||
<div id="listView" class="bibliography"> | |||
${entryHTML} | |||
</div> | |||
<div id="networkView" class="network hidden"></div>`; | |||
output.value = html; | |||
console.log('Fertig - ' + filtered.length + ' Einträge generiert'); | |||
} catch (error) { | } catch (error) { | ||
output.value = 'ERROR: ' + error.message; | output.value = 'ERROR: ' + error.message; | ||
| Line 52: | Line 205: | ||
document.addEventListener('DOMContentLoaded', function() { | document.addEventListener('DOMContentLoaded', function() { | ||
const btn = document.getElementById(' | const btn = document.getElementById('generateBtn'); | ||
if (btn) { | if (btn) { | ||
btn.addEventListener('click', | btn.addEventListener('click', generateBibliography); | ||
console.log('Button bereit'); | console.log('Generate Button bereit'); | ||
} | } | ||
}); | }); | ||
Revision as of 00:48, 12 May 2026
Bibliography Generator