diff --git a/Core.js b/Core.js index 75e60fa..e2df6d8 100644 --- a/Core.js +++ b/Core.js @@ -1,5 +1,5 @@ /** - * SimonUp Core Compiler (Core.js) - Version 1.2.1 + * SimonUp Core Compiler (Core.js) - Version 1.2b.001 * Eine moderne, fluss- und blockorientierte Auszeichnungssprache. */ class SimonUp { @@ -65,6 +65,7 @@ class SimonUp { for (let i = 0; i < lines.length; i++) { let line = lines[i]; + // Block-Start erkennen (&typ meta) if (!inBlock && line.startsWith('&') && line.trim().length > 1) { inBlock = true; const fullHeader = line.substring(1).trim(); @@ -81,7 +82,8 @@ class SimonUp { continue; } - if (inBlock && line.trim().replace(/\u00A0/g, ' ') === '&') { + // Block-Ende erkennen mit /& (Spezifikation V1.2b) + if (inBlock && line.trim().replace(/\u00A0/g, ' ') === '/&') { result.push(this._renderBlock(blockType, blockMeta, blockBuffer)); inBlock = false; blockType = null; @@ -166,50 +168,52 @@ class SimonUp { } /** - * INTERN: Hilfsfunktion zum Rendern von Multi-line-Tabellen und Galerien + * INTERN: Robustes Rendern von Multi-line-Tabellen und Galerien (V1.2b) */ _renderTable(meta, lines) { let tableHtml = '\n'; - let currentCells = []; - let cellBuffer = []; - let self = this; - - for (let i = 0; i < lines.length; i++) { - let line = lines[i]; - let parts = line.split('|'); - for (let j = 0; j < parts.length; j++) { - let part = parts[j]; - - if (j === parts.length - 1) { - if (part.trim() !== '') { - cellBuffer.push(part); - } - if (line.endsWith('|') && cellBuffer.length > 0) { - currentCells.push(cellBuffer.join('\n')); - cellBuffer = []; - } - } else { - cellBuffer.push(part); - currentCells.push(cellBuffer.join('\n')); - cellBuffer = []; - } - } - - if (line.endsWith('|') && currentCells.length > 0) { - let rowContent = currentCells.map(function(c) { - let parsedCell = self._parseInline(c.trim()).replace(/\n/g, '
'); - return ``; - }).join('\n'); - tableHtml += `\n${rowContent}\n\n`; - currentCells = []; + + let colCount = 0; + if (meta) { + let metaParts = meta.trim().split(/\s+/); + if (metaParts.length === 1 && metaParts[0].endsWith('x')) { + colCount = parseInt(metaParts[0]); + } else { + colCount = metaParts.length; } } - tableHtml += '
${parsedCell}
'; + + let fullContent = lines.join('\n'); + let rawCells = fullContent.split('|'); + + if (rawCells.length > 1 && rawCells[rawCells.length - 1].trim() === '') { + rawCells.pop(); + } + + let currentConfiguredCols = colCount || 1; + let cellIndex = 0; + + tableHtml += '\n'; + + for (let i = 0; i < rawCells.length; i++) { + let cellText = rawCells[i].trim(); + let parsedCell = this._parseInline(cellText).replace(/\n/g, '
'); + tableHtml += ` ${parsedCell}\n`; + + cellIndex++; + + if (cellIndex === currentConfiguredCols && i < rawCells.length - 1) { + tableHtml += '\n\n'; + cellIndex = 0; + } + } + + tableHtml += '\n'; return tableHtml; } /** - * INTERN: Verarbeitet Fluss-Formatierungen (Inline) mittels V1.2-RegEx + * INTERN: Verarbeitet Fluss-Formatierungen (Inline) */ _parseInline(text) { if (!text) return ''; @@ -223,15 +227,37 @@ class SimonUp { html = html.replace(/\/\/(( \s|$))/g, '$1'); - // 1. ZUERST: Die kritischen Doppel-Sterne (fett) verarbeiten + // Überschriften-Parsing via .replace() zur Verhinderung von Index-Shifts + html = html.replace(/^([1-6])x#\s*(.*)/gm, (match, level, titleAndRest) => { + let { title, rest } = this._extractHeadingRest(titleAndRest); + const numStr = this._getAutoNumber(parseInt(level)); + const fullTitle = `${numStr} ${title}`; + const id = this._slugify(fullTitle); + this.headings.push({ level: parseInt(level), text: title, id: id }); + return `${fullTitle}${rest}`; + }); + + html = html.replace(/^([1-6])-#\s*(.*)/gm, (match, level, titleAndRest) => { + let { title, rest } = this._extractHeadingRest(titleAndRest); + return `${title}${rest}`; + }); + + html = html.replace(/^([1-6])#\s*(.*)/gm, (match, level, titleAndRest) => { + let { title, rest } = this._extractHeadingRest(titleAndRest); + const id = this._slugify(title); + this.headings.push({ level: parseInt(level), text: title, id: id }); + return `${title}${rest}`; + }); + + // Kritische Doppel-Sterne (fett) html = html.replace(/\*\*(.+?)\\\*\*/g, '$1'); html = html.replace(/\*\*(.+?)(?=\*\*|$)/g, '$1'); - // 2. DANACH: Das einzelne Sternchen (medium) separat behandeln, damit es keine Tags beschädigt + // Einzelne Sternchen (medium) html = html.replace(/\*(.+?)\\\*/g, '$1'); html = html.replace(/\*(.+?)(?=\*|$)/g, '$1'); - // 3. Restliche Standard Text-Inline-Rules parsen + // Standard Text-Inline-Rules const inlineRules = [ { tag: 'em', symbol: '%' }, { tag: 'u', symbol: '_' }, @@ -253,47 +279,7 @@ class SimonUp { html = html.replace(resetRegex, `<${rule.tag}>$1`); } - // 4. Überschriften generieren - let self = this; - const processHeading = function(pattern, callback) { - let match; - while ((match = pattern.exec(html)) !== null) { - const fullMatch = match[0]; - const level = parseInt(match[1]); - const titleAndRest = match[2]; - - let title = titleAndRest; - let rest = ""; - const closeIdx = titleAndRest.indexOf('/#'); - if (closeIdx !== -1) { - title = titleAndRest.substring(0, closeIdx); - rest = titleAndRest.substring(closeIdx + 2); - } - - const result = callback(level, title.trim(), rest); - html = html.substring(0, match.index) + result + html.substring(match.index + fullMatch.length); - } - }; - - processHeading(/^([1-6])x#\s*(.*)/g, function(level, title, rest) { - const numStr = self._getAutoNumber(level); - const fullTitle = `${numStr} ${title}`; - const id = self._slugify(fullTitle); - self.headings.push({ level: level, text: title, id: id }); - return `${fullTitle}${rest}`; - }); - - processHeading(/^([1-6])-#\s*(.*)/g, function(level, title, rest) { - return `${title}${rest}`; - }); - - processHeading(/^([1-6])#\s*(.*)/g, function(level, title, rest) { - const id = self._slugify(title); - self.headings.push({ level: level, text: title, id: id }); - return `${title}${rest}`; - }); - - // 5. RESTLICHE STRUKTUREN (Ausrichtungen, Links, Medien) + // Ausrichtungen, Links, Medien const alignMap = { 'l': 'left', 'r': 'right', 'c': 'center', 'j': 'justify' }; html = html.replace(/>([lrcj])\s+(.+?)\s*\/>/g, function(m, dir, content) { return `
${content}
`; @@ -314,6 +300,20 @@ class SimonUp { return html; } + /** + * INTERN: Hilfsmethode zur Extraktion des optionalen /# Abschlusses bei Überschriften + */ + _extractHeadingRest(text) { + let title = text; + let rest = ""; + const closeIdx = text.indexOf('/#'); + if (closeIdx !== -1) { + title = text.substring(0, closeIdx); + rest = text.substring(closeIdx + 2); + } + return { title: title.trim(), rest: rest }; + } + /** * INTERN: Errechnet die nächste fortlaufende Kapitelnummer */