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}}
<html>
 
<button id="testBtn" style="
<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;
">Test Fetch</button>
">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>&lt;html&gt;</code>-Tags ein.</p>


<textarea id="bibOutput" style="
<textarea id="bibOutput" style="
   width: 100%;
   width: 100%;
   height: 600px;
   height: 700px;
   font-family: 'Courier New', monospace;
   font-family: 'Courier New', monospace;
   font-size: 0.85rem;
   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>
/**
/**
  * Minimales Test-Script für BibliographyData
  * Bibliography Generator für Mark Twain Wiki
* MLA9-Formatierung mit Tags und Abstracts
  */
  */


Line 33: Line 45:
   'use strict';
   'use strict';


   async function testFetch() {
   async function generateBibliography() {
     const output = document.getElementById('bibOutput');
     const output = document.getElementById('bibOutput');
     output.value = 'Versuche zu laden...\n';
     output.value = 'Lade BibliographyData...';


    // Test 1: Normales Fetch
     try {
     try {
       output.value += '\n=== Test 1: Normales Fetch ===\n';
       // Fetch JSON
       const response = await fetch('/BibliographyData');
       const response = await fetch('/BibliographyData?action=raw');
       output.value += `Status: ${response.status}\n`;
       if (!response.ok) throw new Error(`HTTP ${response.status}`);
       const text = await response.text();
       const entries = await response.json();
       output.value += `Länge: ${text.length} Zeichen\n`;
 
       output.value += `Erste 500 Zeichen:\n${text.substring(0, 500)}\n`;
      // Filtere irrelevante Einträge
     } catch (err) {
       const filtered = entries.filter(entry => {
       output.value += `Fehler: ${err.message}\n`;
        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';
     }
     }
  }


    // Test 2: Mit ?action=raw
  /**
    try {
  * Generiert komplettes HTML
      output.value += '\n=== Test 2: Mit ?action=raw ===\n';
  */
      const response = await fetch('/BibliographyData?action=raw');
  function generateHTML(entries, allTags) {
      output.value += `Status: ${response.status}\n`;
    const tagSpans = allTags
      const text = await response.text();
      .map(tag => {
      output.value += `Länge: ${text.length} Zeichen\n`;
        const normalized = tag.toLowerCase().replace(/\s+/g, '_');
      output.value += `Erste 500 Zeichen:\n${text.substring(0, 500)}\n`;
        return `<span class="tag" data-tag="${normalized}">${escapeHtml(tag)}</span>`;
     } catch (err) {
      })
       output.value += `Fehler: ${err.message}\n`;
      .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) + '. ';
     }
     }


     // Test 3: Versuche JSON zu parsen
     // Titel
     try {
     if (entry.title) {
       output.value += '\n=== Test 3: JSON Parse ===\n';
       // Bücher sind kursiv, Artikel in Anführungszeichen
      const response = await fetch('/BibliographyData?action=raw');
      if (entry.type === 'bookSection' || entry.type === 'book') {
      const text = await response.text();
        citation += `<i>${escapeHtml(entry.title)}</i>. `;
     
       } else {
      // Versuche direkt zu parsen
         citation += `"${escapeHtml(entry.title)}." `;
      const json = JSON.parse(text);
      output.value += `✓ JSON erfolgreich geparst!\n`;
      output.value += `Anzahl Einträge: ${json.length}\n`;
       if (json.length > 0) {
         output.value += `Erster Eintrag: ${JSON.stringify(json[0], null, 2)}\n`;
       }
       }
     } catch (err) {
     }
       output.value += `Fehler beim JSON Parse: ${err.message}\n`;
 
     
    // Container (Zeitschrift, Sammelband, etc.)
      // Versuche die nowiki zu entfernen
    if (entry.container) {
      try {
       citation += `<i>${escapeHtml(entry.container)}</i>. `;
        output.value += '\n--- Versuche <nowiki> zu entfernen ---\n';
    }
        const response = await fetch('/BibliographyData?action=raw');
 
        let text = await response.text();
    // Jahr
       
    if (entry.year) {
        // Entferne <nowiki> Tags
      citation += `${entry.year}. `;
        text = text.replace(/<\/?nowiki>/g, '');
    }
        output.value += `Nach Entfernung von nowiki, erste 500 Zeichen:\n${text.substring(0, 500)}\n`;
 
       
    // URL
        const json = JSON.parse(text);
    if (entry.url) {
        output.value += `✓ JSON erfolgreich geparst!\n`;
      citation += `<a href="${escapeHtml(entry.url)}" target="_blank">${escapeHtml(entry.url)}</a>.`;
        output.value += `Anzahl Einträge: ${json.length}\n`;
    } else {
      } catch (err2) {
      // Entferne den letzten Punkt, falls schon vorhanden
         output.value += `Immer noch Fehler: ${err2.message}\n`;
      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 = {
      '&': '&amp;',
      '<': '&lt;',
      '>': '&gt;',
      '"': '&quot;',
      "'": '&#039;'
    };
    return text.replace(/[&<>"']/g, m => map[m]);
  }
  /**
  * Initialisierung
  */
   function init() {
   function init() {
     const btn = document.getElementById('testBtn');
     const btn = document.getElementById('generateBtn');
     if (btn) {
     if (btn) {
       btn.addEventListener('click', testFetch);
       btn.addEventListener('click', generateBibliography);
       console.log('Test-Script bereit');
       console.log('Bibliography Generator bereit');
    } else {
      console.error('Button nicht gefunden');
     }
     }
   }
   }
Line 113: Line 272:
})();
})();
</script>
</script>
</html>

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 `

 ${tagSpans}

${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}

   ${tagSpans}

${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>