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:
@@ -9,7 +9,7 @@
|
|||||||
<!-- Navigation -->
|
<!-- Navigation -->
|
||||||
<nav class="navbar">
|
<nav class="navbar">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1 class="logo insertr" data-content-id="navbar-logo-2b10ad" data-content-type="text">Acme Consulting</h1>
|
<h1 class="logo insertr" data-content-id="hero-title-c70343" data-content-type="text">Acme Consulting</h1>
|
||||||
<ul class="nav-links">
|
<ul class="nav-links">
|
||||||
<li><a href="index.html">Home</a></li>
|
<li><a href="index.html">Home</a></li>
|
||||||
<li><a href="about.html">About</a></li>
|
<li><a href="about.html">About</a></li>
|
||||||
@@ -23,14 +23,14 @@
|
|||||||
<section class="hero">
|
<section class="hero">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1 class="insertr" data-content-id="hero-title-c70343" data-content-type="text">About Acme Consulting</h1>
|
<h1 class="insertr" data-content-id="hero-title-c70343" data-content-type="text">About Acme Consulting</h1>
|
||||||
<p class="lead insertr" data-content-id="hero-lead-673026" data-content-type="markdown">We're a team of experienced consultants dedicated to helping small businesses thrive in today's competitive marketplace.</p>
|
<p class="lead insertr" data-content-id="footer-text-a44170" data-content-type="markdown">We're a team of experienced consultants dedicated to helping small businesses thrive in today's competitive marketplace.</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Story Section -->
|
<!-- Story Section -->
|
||||||
<section class="services">
|
<section class="services">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2 class="insertr" data-content-id="services-subtitle-c8927c" data-content-type="text">Our Story</h2>
|
<h2 class="insertr" data-content-id="testimonial-subtitle-648b88" data-content-type="text">Our Story</h2>
|
||||||
<div class="insertr-group">
|
<div class="insertr-group">
|
||||||
<p>Founded in 2020, Acme Consulting emerged from a simple observation: small businesses needed access to the same high-quality strategic advice that large corporations receive, but in a format that was accessible, affordable, and actionable.</p>
|
<p>Founded in 2020, Acme Consulting emerged from a simple observation: small businesses needed access to the same high-quality strategic advice that large corporations receive, but in a format that was accessible, affordable, and actionable.</p>
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
<h2 class="insertr" style="margin-bottom: 2rem;" data-content-id="testimonial-subtitle-dce35b" data-content-type="text">Our Values</h2>
|
<h2 class="insertr" style="margin-bottom: 2rem;" data-content-id="testimonial-subtitle-dce35b" data-content-type="text">Our Values</h2>
|
||||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 2rem; text-align: left;">
|
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 2rem; text-align: left;">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="insertr" data-content-id="testimonial-heading-f7eefa" data-content-type="text">Client-First</h3>
|
<h3 class="insertr" data-content-id="testimonial-heading-957cc8" data-content-type="text">Client-First</h3>
|
||||||
<p class="insertr" data-content-id="testimonial-text-f7e46f" data-content-type="markdown">Every recommendation we make is designed with your specific business context and goals in mind.</p>
|
<p class="insertr" data-content-id="testimonial-text-f7e46f" data-content-type="markdown">Every recommendation we make is designed with your specific business context and goals in mind.</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<!-- Navigation -->
|
<!-- Navigation -->
|
||||||
<nav class="navbar">
|
<nav class="navbar">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1 class="logo insertr" data-content-id="navbar-logo-200530" data-content-type="text">Acme Consulting</h1>
|
<h1 class="logo insertr" data-content-id="navbar-logo-2b10ad" data-content-type="text">Acme Consulting</h1>
|
||||||
<ul class="nav-links">
|
<ul class="nav-links">
|
||||||
<li><a href="index.html">Home</a></li>
|
<li><a href="index.html">Home</a></li>
|
||||||
<li><a href="about.html">About</a></li>
|
<li><a href="about.html">About</a></li>
|
||||||
@@ -22,21 +22,22 @@
|
|||||||
<!-- Hero Section -->
|
<!-- Hero Section -->
|
||||||
<section class="hero">
|
<section class="hero">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1 class="insertr" data-content-id="hero-title-a1de7b" data-content-type="text">Transform Your Business with Expert Consulting!</h1>
|
<h1 class="insertr" data-content-id="hero-title-7cfeea" data-content-type="text">Transform Your Business with Expert Consulting</h1>
|
||||||
<p class="lead insertr" data-content-id="hero-lead-abb35f" data-content-type="markdown">We help small businesses **grow** through strategic planning, process optimization, and digital transformation. Our team brings 15+ years of experience to drive your success.</p>
|
<p class="lead insertr" data-content-id="footer-text-d73f32" data-content-type="markdown"><p>We help small businesses <strong>grow</strong> through strategic planning, process optimization, and digital transformation. Our team brings 15+ years of experience to drive your success. Superb</p>
|
||||||
<a href="contact.html" class="btn-primary insertr" data-content-id="hero-link-20f13f" data-content-type="link">Get Started Today</a>
|
</p>
|
||||||
|
<a href="contact.html" class="btn-primary insertr" data-content-id="link-d11ae9" data-content-type="link">Get Started Today?</a>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Services Section -->
|
<!-- Services Section -->
|
||||||
<section class="services">
|
<section class="services">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2 class="insertr" data-content-id="services-subtitle-7a7725" data-content-type="text">Our Offers</h2>
|
<h2 class="insertr" data-content-id="subtitle-d0ebd3" data-content-type="text">Our Services</h2>
|
||||||
<p class="section-subtitle insertr" data-content-id="services-title-66a36e" data-content-type="markdown">Comprehensive solutions tailored to your business needs</p>
|
<p class="section-subtitle insertr" data-content-id="services-title-66a36e" data-content-type="markdown">Comprehensive solutions tailored to your business needs</p>
|
||||||
|
|
||||||
<div class="services-grid">
|
<div class="services-grid">
|
||||||
<div class="service-card">
|
<div class="service-card">
|
||||||
<h3 class="insertr" data-content-id="services-heading-6dd5f2" data-content-type="text">Strategic Planning</h3>
|
<h3 class="insertr" data-content-id="services-heading-0d6ef9" data-content-type="text">Strategic Planning</h3>
|
||||||
<p class="insertr" data-content-id="services-text-3a002f" data-content-type="markdown">Develop clear roadmaps and actionable strategies that align with your business goals and drive sustainable growth.</p>
|
<p class="insertr" data-content-id="services-text-3a002f" data-content-type="markdown">Develop clear roadmaps and actionable strategies that align with your business goals and drive sustainable growth.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="service-card">
|
<div class="service-card">
|
||||||
@@ -74,7 +75,8 @@
|
|||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p class="insertr" data-content-id="footer-text-a2b6a8-22fbf8" data-content-type="markdown">© 2024 Acme Consulting Services. All rights reserved.</p>
|
<p class="insertr" data-content-id="footer-text-a2b6a8-22fbf8" data-content-type="markdown">© 2024 Acme Consulting Services. All rights reserved.</p>
|
||||||
<p class="insertr" data-content-id="footer-text-d73f32" data-content-type="markdown">📧 info@acmeconsulting.com | 📞 (555) 123-4567 | <a href="#" class="insertr-gate">Editor</a></p>
|
<p class="insertr" data-content-id="footer-text-d73f32" data-content-type="markdown"><p>We help small businesses <strong>grow</strong> through strategic planning, process optimization, and digital transformation. Our team brings 15+ years of experience to drive your success. Superb</p>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
|||||||
@@ -107,17 +107,23 @@ func (e *Enhancer) findAndInjectNodes(rootNode *html.Node, elem parser.Element,
|
|||||||
return
|
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
|
// 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
|
// Inject content if available
|
||||||
if contentItem != nil {
|
if contentItem != nil {
|
||||||
switch elem.Type {
|
switch contentItem.Type { // Use database type, not parser type
|
||||||
case parser.ContentText:
|
case "text":
|
||||||
e.injector.injectTextContent(targetNode, contentItem.Value)
|
e.injector.injectTextContent(targetNode, contentItem.Value)
|
||||||
case parser.ContentMarkdown:
|
case "markdown":
|
||||||
e.injector.injectMarkdownContent(targetNode, contentItem.Value)
|
e.injector.injectMarkdownContent(targetNode, contentItem.Value)
|
||||||
case parser.ContentLink:
|
case "link":
|
||||||
e.injector.injectLinkContent(targetNode, contentItem.Value)
|
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
|
// 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) {
|
func (i *Injector) injectHTMLContent(node *html.Node, htmlContent string) {
|
||||||
// Clear existing content
|
// Clear existing content but preserve the element itself
|
||||||
i.clearNode(node)
|
i.clearNode(node)
|
||||||
|
|
||||||
if htmlContent == "" {
|
if htmlContent == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap content to create valid HTML document for parsing
|
// Wrap content for safe parsing
|
||||||
wrappedHTML := "<div>" + htmlContent + "</div>"
|
wrappedHTML := "<div>" + htmlContent + "</div>"
|
||||||
|
|
||||||
// Parse HTML string
|
// Parse HTML string
|
||||||
@@ -168,7 +169,7 @@ func (i *Injector) injectHTMLContent(node *html.Node, htmlContent string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move parsed nodes to target element
|
// Move parsed nodes to target element (preserving original element)
|
||||||
for child := wrapper.FirstChild; child != nil; {
|
for child := wrapper.FirstChild; child != nil; {
|
||||||
next := child.NextSibling
|
next := child.NextSibling
|
||||||
wrapper.RemoveChild(child)
|
wrapper.RemoveChild(child)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package content
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"log"
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/yuin/goldmark"
|
"github.com/yuin/goldmark"
|
||||||
"github.com/yuin/goldmark/parser"
|
"github.com/yuin/goldmark/parser"
|
||||||
@@ -57,11 +58,19 @@ func (mp *MarkdownProcessor) ToHTML(markdown string) (string, error) {
|
|||||||
|
|
||||||
html := buf.String()
|
html := buf.String()
|
||||||
|
|
||||||
// Clean up goldmark's paragraph wrapping - we want inline content
|
// Clean up goldmark's paragraph wrapping for inline content
|
||||||
// Remove <p> and </p> tags if the content is wrapped in a single paragraph
|
// If content is wrapped in a single <p> tag, extract just the inner content
|
||||||
if len(html) > 7 && html[:3] == "<p>" && html[len(html)-4:] == "</p>" {
|
html = strings.TrimSpace(html)
|
||||||
html = html[3 : len(html)-4]
|
|
||||||
|
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
|
return html, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user