Improve Satzung content loading and HTML conversion process
This commit ensures that the Satzung content is loaded as a string, enhancing reliability. Additionally, it refines the HTML conversion function by improving the handling of line breaks, merging related lines, and removing empty paragraphs. These changes enhance the overall quality and readability of the generated HTML content.
This commit is contained in:
@@ -183,12 +183,15 @@ async function loadCurrentSatzung() {
|
||||
lastUpdated.value = new Date().toLocaleDateString('de-DE')
|
||||
}
|
||||
if (satzung?.content) {
|
||||
satzungContent.value = satzung.content
|
||||
// Stelle sicher, dass der Inhalt als String geladen wird
|
||||
const content = typeof satzung.content === 'string' ? satzung.content : String(satzung.content || '')
|
||||
satzungContent.value = content
|
||||
} else {
|
||||
satzungContent.value = ''
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Fehler beim Laden der aktuellen Satzung:', e)
|
||||
satzungContent.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -161,74 +161,154 @@ export default defineEventHandler(async (event) => {
|
||||
// PDF-Text zu HTML konvertieren
|
||||
function convertTextToHtml(text) {
|
||||
// Text bereinigen und strukturieren
|
||||
let html = text
|
||||
let cleaned = text
|
||||
.replace(/\r\n/g, '\n') // Windows-Zeilenumbrüche normalisieren
|
||||
.replace(/\r/g, '\n') // Mac-Zeilenumbrüche normalisieren
|
||||
.replace(/\n\s*\n/g, '\n\n') // Mehrfache Zeilenumbrüche reduzieren
|
||||
.trim()
|
||||
|
||||
// Seitenzahlen und Seitenfuß entfernen (z.B. "Seite 2 von 4", "-2-")
|
||||
html = html
|
||||
// Seitenzahlen und Seitenfuß entfernen
|
||||
cleaned = cleaned
|
||||
.replace(/^Seite\s+\d+\s+von\s+\d+.*$/gm, '')
|
||||
.replace(/^-+\d+-+\s*$/gm, '')
|
||||
.replace(/\n\s*-+\d+-+\s*\n/g, '\n')
|
||||
.replace(/\s*-+\d+-+\s*/g, '')
|
||||
.replace(/zuletzt geändert am \d{2}\.\d{2}\.\d{4}.*$/gm, '')
|
||||
|
||||
// Überschriften erkennen und formatieren
|
||||
html = html.replace(/^(Vereinssatzung|Satzung)$/gm, '<h1>$1</h1>')
|
||||
html = html.replace(/^(§\s*\d+[^§\n]*)$/gm, '<h2>$1</h2>')
|
||||
// Zeilenweise aufteilen und leere Zeilen filtern
|
||||
let rawLines = cleaned.split('\n').map(l => l.trim()).filter(l => {
|
||||
if (!l || l.length === 0) return false
|
||||
if (/^-+\d+-+$/.test(l)) return false
|
||||
if (/^Seite\s+\d+\s+von\s+\d+/.test(l)) return false
|
||||
return true
|
||||
})
|
||||
|
||||
// Absätze erstellen
|
||||
html = html.split('\n\n').map(paragraph => {
|
||||
paragraph = paragraph.trim()
|
||||
if (!paragraph) return ''
|
||||
// ============================================================
|
||||
// SCHRITT 1: Zusammengehörige Zeilen zusammenführen
|
||||
// pdftotext trennt oft Nummer/Prefix und Inhalt auf zwei Zeilen
|
||||
// ============================================================
|
||||
const merged = []
|
||||
for (let j = 0; j < rawLines.length; j++) {
|
||||
const line = rawLines[j]
|
||||
const next = j + 1 < rawLines.length ? rawLines[j + 1] : null
|
||||
|
||||
// Überschriften nicht als Paragraphen behandeln
|
||||
if (paragraph.match(/^<h[1-6]>/) || paragraph.match(/^§\s*\d+/)) {
|
||||
return paragraph
|
||||
// Fall 1: "§ 1" (nur Paragraphennummer) + nächste Zeile ist der Titel
|
||||
// z.B. "§ 1" + "Name, Sitz und Zweck" → "§ 1 Name, Sitz und Zweck"
|
||||
if (/^§\s*\d+\s*$/.test(line) && next && !next.match(/^§/) && !next.match(/^\d+\.\s/)) {
|
||||
merged.push(line + ' ' + next)
|
||||
j++ // nächste Zeile überspringen
|
||||
continue
|
||||
}
|
||||
|
||||
// Spezielle Behandlung für Aufzählungen mit a), b), c) ...
|
||||
if (paragraph.match(/^[a-z]\)\s*$/mi)) {
|
||||
const lines = paragraph.split('\n').map(l => l.trim()).filter(Boolean)
|
||||
const items = []
|
||||
let current = ''
|
||||
// Fall 2: "1." (nur Nummer mit Punkt) + nächste Zeile ist der Text
|
||||
// z.B. "1." + "Der Harheimer TC..." → "1. Der Harheimer TC..."
|
||||
if (/^\d+\.\s*$/.test(line) && next) {
|
||||
merged.push(line + ' ' + next)
|
||||
j++
|
||||
continue
|
||||
}
|
||||
|
||||
for (const line of lines) {
|
||||
if (/^[a-z]\)\s*$/i.test(line)) {
|
||||
// neuer Aufzählungspunkt, vorherigen abschließen
|
||||
if (current) items.push(current.trim())
|
||||
current = line
|
||||
} else {
|
||||
// Text zum aktuellen Aufzählungspunkt hinzufügen
|
||||
current += (current ? ' ' : '') + line
|
||||
// Fall 3: "a)" (nur Buchstabe mit Klammer) + nächste Zeile ist der Text
|
||||
// z.B. "a)" + "Die Bestimmungen..." → "a) Die Bestimmungen..."
|
||||
if (/^[a-z]\)\s*$/i.test(line) && next) {
|
||||
merged.push(line + ' ' + next)
|
||||
j++
|
||||
continue
|
||||
}
|
||||
|
||||
// Keine Zusammenführung nötig
|
||||
merged.push(line)
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// SCHRITT 2: HTML-Elemente erzeugen
|
||||
// ============================================================
|
||||
const result = []
|
||||
let i = 0
|
||||
|
||||
while (i < merged.length) {
|
||||
const line = merged[i]
|
||||
|
||||
// Überschriften erkennen (§1, § 2, etc.)
|
||||
if (line.match(/^§\s*\d+/)) {
|
||||
result.push(`<h2>${line}</h2>`)
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
// Prüfe ob wir eine Liste mit a), b), c) haben
|
||||
// Suche nach einem Muster wie "2. Text:" gefolgt von "a) ...", "b) ...", etc.
|
||||
if (line.match(/^\d+\.\s+.*:$/) && i + 1 < merged.length && merged[i + 1].match(/^[a-z]\)\s+/i)) {
|
||||
// Einleitender Text für die Liste (ohne Nummer)
|
||||
const introText = line.replace(/^\d+\.\s+/, '')
|
||||
const listItems = []
|
||||
i++
|
||||
|
||||
// Sammle alle Listenpunkte a), b), c) ...
|
||||
while (i < merged.length && merged[i].match(/^[a-z]\)\s+/i)) {
|
||||
const itemText = merged[i].replace(/^[a-z]\)\s+/i, '').trim()
|
||||
if (itemText) {
|
||||
listItems.push(itemText)
|
||||
}
|
||||
i++
|
||||
}
|
||||
if (current) items.push(current.trim())
|
||||
|
||||
const listItems = items.map(item => {
|
||||
return `<li>${item}</li>`
|
||||
}).join('')
|
||||
|
||||
return `<ul>${listItems}</ul>`
|
||||
if (listItems.length > 0) {
|
||||
const listHtml = listItems.map(item => `<li>${item}</li>`).join('')
|
||||
result.push(`<p><strong>${introText}</strong></p><ul>${listHtml}</ul>`)
|
||||
} else {
|
||||
result.push(`<p>${line}</p>`)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Allgemeine Listen erkennen (Bullet "•", Bindestrich- oder Nummern-Listen)
|
||||
if (paragraph.includes('•') || paragraph.match(/^[\-•]\s/m) || paragraph.match(/^\d+\.\s/m)) {
|
||||
const listItems = paragraph.split(/\n/).map(item => {
|
||||
item = item.trim()
|
||||
if (item.match(/^[•-]\s/) || item.match(/^\d+\.\s/)) {
|
||||
return `<li>${item.replace(/^[•-]\s/, '').replace(/^\d+\.\s/, '')}</li>`
|
||||
// Einzelne Listenpunkte a), b), c) erkennen
|
||||
if (line.match(/^[a-z]\)\s+/i)) {
|
||||
const items = []
|
||||
while (i < merged.length && merged[i].match(/^[a-z]\)\s+/i)) {
|
||||
const itemText = merged[i].replace(/^[a-z]\)\s+/i, '').trim()
|
||||
if (itemText) {
|
||||
items.push(itemText)
|
||||
}
|
||||
return item ? `<li>${item}</li>` : ''
|
||||
}).filter(Boolean).join('')
|
||||
return `<ul>${listItems}</ul>`
|
||||
i++
|
||||
}
|
||||
if (items.length > 0) {
|
||||
const listHtml = items.map(item => `<li>${item}</li>`).join('')
|
||||
result.push(`<ul>${listHtml}</ul>`)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Nummerierte Listen (1., 2., 3.) - aber nur wenn mehrere aufeinander folgen
|
||||
if (line.match(/^\d+\.\s+/) && i + 1 < merged.length && merged[i + 1].match(/^\d+\.\s+/)) {
|
||||
const items = []
|
||||
while (i < merged.length && merged[i].match(/^\d+\.\s+/)) {
|
||||
const itemText = merged[i].replace(/^\d+\.\s+/, '').trim()
|
||||
// Prüfe ob es eine Einleitung für eine Unterliste ist (endet mit ":")
|
||||
if (itemText.endsWith(':') && i + 1 < merged.length && merged[i + 1].match(/^[a-z]\)\s+/i)) {
|
||||
break // Wird oben als Einleitung + Unterliste behandelt
|
||||
}
|
||||
if (itemText) {
|
||||
items.push(itemText)
|
||||
}
|
||||
i++
|
||||
}
|
||||
if (items.length > 0) {
|
||||
const listHtml = items.map(item => `<li>${item}</li>`).join('')
|
||||
result.push(`<ol>${listHtml}</ol>`)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Normale Absätze
|
||||
return `<p>${paragraph.replace(/\n/g, '<br>')}</p>`
|
||||
}).join('\n')
|
||||
result.push(`<p>${line}</p>`)
|
||||
i++
|
||||
}
|
||||
|
||||
// Mehrfache Zeilenumbrüche entfernen
|
||||
html = html.replace(/\n{3,}/g, '\n\n')
|
||||
let html = result.join('\n')
|
||||
|
||||
return html
|
||||
// Leere Absätze entfernen
|
||||
html = html.replace(/<p>\s*<\/p>/g, '')
|
||||
html = html.replace(/<p><\/p>/g, '')
|
||||
|
||||
return html.trim()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user