BibliographyBackbone: Difference between revisions
From Illustrations in German Translations of Mark Twain's Works
No edit summary |
No edit summary |
||
| Line 1: | Line 1: | ||
{{Seitenkopf|Bibliography Generator}} | {{Seitenkopf|Bibliography Generator}} | ||
< | |||
<button id=" | <div style="max-width: 1000px; margin: 0 auto;"> | ||
<p>Klicke auf den Button, um die Zotero-Einträge von <code>BibliographyData</code> zu laden und als MLA9-formatiertes HTML zu generieren.</p> | |||
<button id="generateBtn" style=" | |||
background-color: #008CBA; | background-color: #008CBA; | ||
color: white; | color: white; | ||
| Line 10: | Line 14: | ||
cursor: pointer; | cursor: pointer; | ||
margin-bottom: 1rem; | margin-bottom: 1rem; | ||
"> | ">Generate Bibliography HTML</button> | ||
<p id="bibStatus" style="font-size: 0.9rem; color: #666; margin-bottom: 1rem;"></p> | |||
<h3>Raw HTML Output</h3> | |||
<p style="font-size: 0.85rem; color: #999;">Kopiere den kompletten Inhalt und füge ihn in die <code>Bibliography</code>-Seite zwischen den <code><html></code>-Tags ein.</p> | |||
<textarea id="bibOutput" style=" | <textarea id="bibOutput" style=" | ||
width: 100%; | width: 100%; | ||
height: | height: 700px; | ||
font-family: 'Courier New', monospace; | font-family: 'Courier New', monospace; | ||
font-size: 0. | font-size: 0.8rem; | ||
padding: 10px; | padding: 10px; | ||
border: 2px solid #ddd; | border: 2px solid #ddd; | ||
| Line 24: | Line 33: | ||
overflow: auto; | overflow: auto; | ||
"></textarea> | "></textarea> | ||
</div> | |||
<script> | <script> | ||
/** | /** | ||
* | * Bibliography Generator für Mark Twain Wiki | ||
* MLA9-Formatierung mit Tags und Abstracts | |||
*/ | */ | ||
| Line 33: | Line 45: | ||
'use strict'; | 'use strict'; | ||
async function | async function generateBibliography() { | ||
const output = document.getElementById('bibOutput'); | const output = document.getElementById('bibOutput'); | ||
output.value = ' | output.value = 'Lade BibliographyData...'; | ||
try { | try { | ||
// Fetch JSON | |||
const response = await fetch('/BibliographyData'); | const response = await fetch('/BibliographyData?action=raw'); | ||
if (!response.ok) throw new Error(`HTTP ${response.status}`); | |||
const | const entries = await response.json(); | ||
output.value | // Filtere irrelevante Einträge | ||
} catch ( | const filtered = entries.filter(entry => { | ||
output.value | 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 html = generateHTML(filtered, Array.from(allTags).sort()); | |||
output.value = html; | |||
const status = document.getElementById('bibStatus'); | |||
if (status) { | |||
status.textContent = `✓ ${filtered.length} Einträge generiert (${allTags.size} Tags)`; | |||
status.style.color = '#4caf50'; | |||
} | |||
} catch (error) { | |||
output.value = `ERROR: ${error.message}`; | |||
output.style.borderColor = '#d32f2f'; | |||
} | } | ||
} | |||
/** | |||
* Generiert komplettes HTML | |||
*/ | |||
function generateHTML(entries, allTags) { | |||
const tagSpans = allTags | |||
.map(tag => { | |||
const normalized = tag.toLowerCase().replace(/\s+/g, '_'); | |||
return `<span class="tag" data-tag="${normalized}">${escapeHtml(tag)}</span>`; | |||
}) | |||
.join('\n '); | |||
const entryHTML = entries | |||
.map((entry, i) => generateBibEntry(entry, i + 1)) | |||
.join('\n\n'); | |||
return `<div class="bib-tags"> | |||
${tagSpans} | |||
</div> | |||
<div id="listView" class="bibliography"> | |||
${entryHTML} | |||
</div> | |||
<div id="networkView" class="network hidden"></div>`; | |||
} | |||
/** | |||
* Generiert einen einzelnen Biblio-Eintrag in MLA9-Format | |||
*/ | |||
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>`; | |||
} | |||
/** | |||
* Formatiert einen Eintrag in MLA9 | |||
* MLA9: Author(s). "Title." Container. Year. Other info. | |||
*/ | |||
function formatMLA9(entry) { | |||
let citation = ''; | |||
// Autoren | |||
if (entry.authors && entry.authors.length > 0) { | |||
citation += formatAuthors(entry.authors) + '. '; | |||
} | } | ||
// | // Titel | ||
if (entry.title) { | |||
// Bücher sind kursiv, Artikel in Anführungszeichen | |||
if (entry.type === 'bookSection' || entry.type === 'book') { | |||
citation += `<i>${escapeHtml(entry.title)}</i>. `; | |||
} else { | |||
citation += `"${escapeHtml(entry.title)}." `; | |||
} | } | ||
} | } | ||
// Container (Zeitschrift, Sammelband, etc.) | |||
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 { | |||
// Entferne den letzten Punkt, falls schon vorhanden | |||
citation = citation.trim(); | |||
if (!citation.endsWith('.')) { | |||
citation += '.'; | |||
} | } | ||
} | } | ||
return citation; | |||
} | |||
/** | |||
* Formatiert Autoren | |||
* MLA9: "Last, First, and Last, First" | |||
*/ | |||
function formatAuthors(authors) { | |||
if (authors.length === 0) return ''; | |||
if (authors.length === 1) { | |||
return formatAuthor(authors[0]); | |||
} | |||
if (authors.length === 2) { | |||
return `${formatAuthor(authors[0])}, and ${formatAuthor(authors[1])}`; | |||
} | |||
// 3+ Autoren: Nur first + et al. | |||
return `${formatAuthor(authors[0])}, et al.`; | |||
} | } | ||
/** | |||
* Formatiert einen einzelnen Autor | |||
*/ | |||
function formatAuthor(author) { | |||
if (!author) return ''; | |||
const family = author.family || ''; | |||
const given = author.given || ''; | |||
if (!family) return given; | |||
if (!given) return family; | |||
return `${family}, ${given}`; | |||
} | |||
/** | |||
* Generiert data-tags Attribut | |||
*/ | |||
function generateTagsAttribute(tags) { | |||
if (!tags || tags.length === 0) return ''; | |||
const normalized = tags | |||
.map(tag => tag.toLowerCase().replace(/\s+/g, '_')) | |||
.join(' '); | |||
return ` data-tags="${normalized}"`; | |||
} | |||
/** | |||
* Generiert Tag-Spans | |||
*/ | |||
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(''); | |||
} | |||
/** | |||
* HTML-Escape | |||
*/ | |||
function escapeHtml(text) { | |||
if (!text) return ''; | |||
const map = { | |||
'&': '&', | |||
'<': '<', | |||
'>': '>', | |||
'"': '"', | |||
"'": ''' | |||
}; | |||
return text.replace(/[&<>"']/g, m => map[m]); | |||
} | |||
/** | |||
* Initialisierung | |||
*/ | |||
function init() { | function init() { | ||
const btn = document.getElementById(' | const btn = document.getElementById('generateBtn'); | ||
if (btn) { | if (btn) { | ||
btn.addEventListener('click', | btn.addEventListener('click', generateBibliography); | ||
console.log(' | console.log('Bibliography Generator bereit'); | ||
} | } | ||
} | } | ||
| Line 113: | Line 272: | ||
})(); | })(); | ||
</script> | </script> | ||
Revision as of 00:25, 12 May 2026
Bibliography Generator
Klicke auf den Button, um die Zotero-Einträge von BibliographyData zu laden und als MLA9-formatiertes HTML zu generieren.
<button id="generateBtn" style="
background-color: #008CBA; color: white; padding: 10px 20px; border: none; border-radius: 5px; font-size: 1rem; cursor: pointer; margin-bottom: 1rem;
">Generate Bibliography HTML</button>
Raw HTML Output
Kopiere den kompletten Inhalt und füge ihn in die Bibliography-Seite zwischen den <html>-Tags ein.
<textarea id="bibOutput" style="
width: 100%; height: 700px; font-family: 'Courier New', monospace; font-size: 0.8rem; padding: 10px; border: 2px solid #ddd; border-radius: 5px; box-sizing: border-box; white-space: pre; overflow: auto;
"></textarea>
<script> /**
* Bibliography Generator für Mark Twain Wiki * MLA9-Formatierung mit Tags und Abstracts */
(function() {
'use strict';
async function generateBibliography() {
const output = document.getElementById('bibOutput');
output.value = 'Lade BibliographyData...';
try {
// Fetch JSON
const response = await fetch('/BibliographyData?action=raw');
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const entries = await response.json();
// 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 html = generateHTML(filtered, Array.from(allTags).sort());
output.value = html;
const status = document.getElementById('bibStatus');
if (status) {
status.textContent = `✓ ${filtered.length} Einträge generiert (${allTags.size} Tags)`;
status.style.color = '#4caf50';
}
} catch (error) {
output.value = `ERROR: ${error.message}`;
output.style.borderColor = '#d32f2f';
}
}
/**
* Generiert komplettes HTML
*/
function generateHTML(entries, allTags) {
const tagSpans = allTags
.map(tag => {
const normalized = tag.toLowerCase().replace(/\s+/g, '_');
return `${escapeHtml(tag)}`;
})
.join('\n ');
const entryHTML = entries
.map((entry, i) => generateBibEntry(entry, i + 1))
.join('\n\n');
return `
${entryHTML}
`;
}
/**
* Generiert einen einzelnen Biblio-Eintrag in MLA9-Format
*/
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 `
${mlaFormatted}
${abstract || '(No abstract available)'}
<button class="expand-btn">Show Abstract</button>
`;
}
/**
* Formatiert einen Eintrag in MLA9
* MLA9: Author(s). "Title." Container. Year. Other info.
*/
function formatMLA9(entry) {
let citation = ;
// Autoren
if (entry.authors && entry.authors.length > 0) {
citation += formatAuthors(entry.authors) + '. ';
}
// Titel
if (entry.title) {
// Bücher sind kursiv, Artikel in Anführungszeichen
if (entry.type === 'bookSection' || entry.type === 'book') {
citation += `${escapeHtml(entry.title)}. `;
} else {
citation += `"${escapeHtml(entry.title)}." `;
}
}
// Container (Zeitschrift, Sammelband, etc.)
if (entry.container) {
citation += `${escapeHtml(entry.container)}. `;
}
// Jahr
if (entry.year) {
citation += `${entry.year}. `;
}
// URL
if (entry.url) {
citation += `<a href="${escapeHtml(entry.url)}" target="_blank">${escapeHtml(entry.url)}</a>.`;
} else {
// Entferne den letzten Punkt, falls schon vorhanden
citation = citation.trim();
if (!citation.endsWith('.')) {
citation += '.';
}
}
return citation; }
/**
* Formatiert Autoren
* MLA9: "Last, First, and Last, First"
*/
function formatAuthors(authors) {
if (authors.length === 0) return ;
if (authors.length === 1) {
return formatAuthor(authors[0]);
}
if (authors.length === 2) {
return `${formatAuthor(authors[0])}, and ${formatAuthor(authors[1])}`;
}
// 3+ Autoren: Nur first + et al.
return `${formatAuthor(authors[0])}, et al.`;
}
/**
* Formatiert einen einzelnen Autor
*/
function formatAuthor(author) {
if (!author) return ;
const family = author.family || ;
const given = author.given || ;
if (!family) return given; if (!given) return family;
return `${family}, ${given}`;
}
/**
* Generiert data-tags Attribut
*/
function generateTagsAttribute(tags) {
if (!tags || tags.length === 0) return ;
const normalized = tags
.map(tag => tag.toLowerCase().replace(/\s+/g, '_'))
.join(' ');
return ` data-tags="${normalized}"`;
}
/**
* Generiert Tag-Spans
*/
function generateTagSpans(tags) {
if (!tags || tags.length === 0) return ;
return tags
.map(tag => {
const normalized = tag.toLowerCase().replace(/\s+/g, '_');
return `${escapeHtml(tag)}`;
})
.join();
}
/**
* HTML-Escape
*/
function escapeHtml(text) {
if (!text) return ;
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return text.replace(/[&<>"']/g, m => map[m]);
}
/**
* Initialisierung
*/
function init() {
const btn = document.getElementById('generateBtn');
if (btn) {
btn.addEventListener('click', generateBibliography);
console.log('Bibliography Generator bereit');
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})(); </script>