fix: preserve element attributes and styling during markdown injection
Critical fixes: - Fixed HTML injection to preserve original element attributes, classes, and styling - Updated markdown processor to generate inline content instead of wrapped paragraphs - Enhanced content type handling: database type now takes precedence over parser detection - Eliminated nested <p> tags issue that was causing invalid HTML Key improvements: - Elements like <p class='lead insertr' style='color: blue;'> now maintain all attributes - Markdown **bold**, *italic*, [links](url) inject as inline formatted content - Database content type (markdown/text/link) overrides parser auto-detection - Clean HTML output without structural corruption Before: <p class='lead'><p>**bold**</p></p> (broken) After: <p class='lead'>**bold text**</p> (clean) Server remains source of truth for markdown processing with zero runtime overhead.
This commit is contained in:
@@ -107,17 +107,23 @@ func (e *Enhancer) findAndInjectNodes(rootNode *html.Node, elem parser.Element,
|
||||
return
|
||||
}
|
||||
|
||||
// Determine content type: use database type if available, otherwise parser type
|
||||
contentType := string(elem.Type)
|
||||
if contentItem != nil {
|
||||
contentType = contentItem.Type // Database is source of truth
|
||||
}
|
||||
|
||||
// Inject content attributes for the correctly matched node
|
||||
e.injector.AddContentAttributes(targetNode, elem.ContentID, string(elem.Type))
|
||||
e.injector.AddContentAttributes(targetNode, elem.ContentID, contentType)
|
||||
|
||||
// Inject content if available
|
||||
if contentItem != nil {
|
||||
switch elem.Type {
|
||||
case parser.ContentText:
|
||||
switch contentItem.Type { // Use database type, not parser type
|
||||
case "text":
|
||||
e.injector.injectTextContent(targetNode, contentItem.Value)
|
||||
case parser.ContentMarkdown:
|
||||
case "markdown":
|
||||
e.injector.injectMarkdownContent(targetNode, contentItem.Value)
|
||||
case parser.ContentLink:
|
||||
case "link":
|
||||
e.injector.injectLinkContent(targetNode, contentItem.Value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,15 +142,16 @@ func (i *Injector) injectLinkContent(node *html.Node, content string) {
|
||||
}
|
||||
|
||||
// injectHTMLContent safely injects HTML content into a DOM node
|
||||
// Preserves the original element and only replaces its content
|
||||
func (i *Injector) injectHTMLContent(node *html.Node, htmlContent string) {
|
||||
// Clear existing content
|
||||
// Clear existing content but preserve the element itself
|
||||
i.clearNode(node)
|
||||
|
||||
if htmlContent == "" {
|
||||
return
|
||||
}
|
||||
|
||||
// Wrap content to create valid HTML document for parsing
|
||||
// Wrap content for safe parsing
|
||||
wrappedHTML := "<div>" + htmlContent + "</div>"
|
||||
|
||||
// Parse HTML string
|
||||
@@ -168,7 +169,7 @@ func (i *Injector) injectHTMLContent(node *html.Node, htmlContent string) {
|
||||
return
|
||||
}
|
||||
|
||||
// Move parsed nodes to target element
|
||||
// Move parsed nodes to target element (preserving original element)
|
||||
for child := wrapper.FirstChild; child != nil; {
|
||||
next := child.NextSibling
|
||||
wrapper.RemoveChild(child)
|
||||
|
||||
@@ -3,6 +3,7 @@ package content
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/yuin/goldmark"
|
||||
"github.com/yuin/goldmark/parser"
|
||||
@@ -57,11 +58,19 @@ func (mp *MarkdownProcessor) ToHTML(markdown string) (string, error) {
|
||||
|
||||
html := buf.String()
|
||||
|
||||
// Clean up goldmark's paragraph wrapping - we want inline content
|
||||
// Remove <p> and </p> tags if the content is wrapped in a single paragraph
|
||||
if len(html) > 7 && html[:3] == "<p>" && html[len(html)-4:] == "</p>" {
|
||||
html = html[3 : len(html)-4]
|
||||
// Clean up goldmark's paragraph wrapping for inline content
|
||||
// If content is wrapped in a single <p> tag, extract just the inner content
|
||||
html = strings.TrimSpace(html)
|
||||
|
||||
if strings.HasPrefix(html, "<p>") && strings.HasSuffix(html, "</p>") {
|
||||
// Check if this is a single paragraph (no other <p> tags inside)
|
||||
inner := html[3 : len(html)-4] // Remove <p> and </p>
|
||||
if !strings.Contains(inner, "<p>") {
|
||||
// Single paragraph - return just the inner content for inline injection
|
||||
return inner, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Multiple paragraphs or other block content - return as-is
|
||||
return html, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user