feat: Complete HTML-first architecture implementation with API integration
- Replace value field with html_content for direct HTML storage - Add original_template field for style detection preservation - Remove all markdown processing from injector (delete markdown.go) - Fix critical content extraction/injection bugs in engine - Add missing UpdateContent PUT handler for content persistence - Fix API client field names and add updateContent() method - Resolve content type validation (only allow text/link types) - Add UUID-based ID generation to prevent collisions - Complete first-pass processing workflow for unprocessed elements - Verify end-to-end: Enhancement → Database → API → Editor → Persistence All 37 files updated for HTML-first content management system. Phase 3a implementation complete and production ready.
This commit is contained in:
@@ -12,7 +12,6 @@ import (
|
||||
type Injector struct {
|
||||
client ContentClient
|
||||
siteID string
|
||||
mdProcessor *MarkdownProcessor
|
||||
authProvider *AuthProvider
|
||||
}
|
||||
|
||||
@@ -21,7 +20,6 @@ func NewInjector(client ContentClient, siteID string) *Injector {
|
||||
return &Injector{
|
||||
client: client,
|
||||
siteID: siteID,
|
||||
mdProcessor: NewMarkdownProcessor(),
|
||||
authProvider: &AuthProvider{Type: "mock"}, // default
|
||||
}
|
||||
}
|
||||
@@ -34,7 +32,6 @@ func NewInjectorWithAuth(client ContentClient, siteID string, authProvider *Auth
|
||||
return &Injector{
|
||||
client: client,
|
||||
siteID: siteID,
|
||||
mdProcessor: NewMarkdownProcessor(),
|
||||
authProvider: authProvider,
|
||||
}
|
||||
}
|
||||
@@ -53,17 +50,8 @@ func (i *Injector) InjectContent(element *Element, contentID string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Replace element content based on type
|
||||
switch element.Type {
|
||||
case "text":
|
||||
i.injectTextContent(element.Node, contentItem.Value)
|
||||
case "markdown":
|
||||
i.injectMarkdownContent(element.Node, contentItem.Value)
|
||||
case "link":
|
||||
i.injectLinkContent(element.Node, contentItem.Value)
|
||||
default:
|
||||
i.injectTextContent(element.Node, contentItem.Value)
|
||||
}
|
||||
// Direct HTML injection for all content types
|
||||
i.injectHTMLContent(element.Node, contentItem.HTMLContent)
|
||||
|
||||
// Add data attributes for editor functionality
|
||||
i.AddContentAttributes(element.Node, contentID, element.Type)
|
||||
@@ -97,65 +85,13 @@ func (i *Injector) InjectBulkContent(elements []ElementWithID) error {
|
||||
continue
|
||||
}
|
||||
|
||||
// Replace content based on type
|
||||
switch elem.Element.Type {
|
||||
case "text":
|
||||
i.injectTextContent(elem.Element.Node, contentItem.Value)
|
||||
case "markdown":
|
||||
i.injectMarkdownContent(elem.Element.Node, contentItem.Value)
|
||||
case "link":
|
||||
i.injectLinkContent(elem.Element.Node, contentItem.Value)
|
||||
default:
|
||||
i.injectTextContent(elem.Element.Node, contentItem.Value)
|
||||
}
|
||||
// Direct HTML injection for all content types
|
||||
i.injectHTMLContent(elem.Element.Node, contentItem.HTMLContent)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// injectTextContent replaces text content in an element
|
||||
func (i *Injector) injectTextContent(node *html.Node, content string) {
|
||||
// Remove all child nodes
|
||||
for child := node.FirstChild; child != nil; {
|
||||
next := child.NextSibling
|
||||
node.RemoveChild(child)
|
||||
child = next
|
||||
}
|
||||
|
||||
// Add new text content
|
||||
textNode := &html.Node{
|
||||
Type: html.TextNode,
|
||||
Data: content,
|
||||
}
|
||||
node.AppendChild(textNode)
|
||||
}
|
||||
|
||||
// injectMarkdownContent handles markdown content - converts markdown to HTML
|
||||
func (i *Injector) injectMarkdownContent(node *html.Node, content string) {
|
||||
if content == "" {
|
||||
i.injectTextContent(node, "")
|
||||
return
|
||||
}
|
||||
|
||||
// Convert markdown to HTML using server processor
|
||||
htmlContent, err := i.mdProcessor.ToHTML(content)
|
||||
if err != nil {
|
||||
log.Printf("⚠️ Markdown conversion failed for content '%s': %v, falling back to text", content, err)
|
||||
i.injectTextContent(node, content)
|
||||
return
|
||||
}
|
||||
|
||||
// Inject the HTML content
|
||||
i.injectHTMLContent(node, htmlContent)
|
||||
}
|
||||
|
||||
// injectLinkContent handles link/button content with URL extraction
|
||||
func (i *Injector) injectLinkContent(node *html.Node, content string) {
|
||||
// For now, just inject the text content
|
||||
// TODO: Parse content for URL and text components
|
||||
i.injectTextContent(node, content)
|
||||
}
|
||||
|
||||
// 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) {
|
||||
@@ -172,8 +108,14 @@ func (i *Injector) injectHTMLContent(node *html.Node, htmlContent string) {
|
||||
// Parse HTML string
|
||||
doc, err := html.Parse(strings.NewReader(wrappedHTML))
|
||||
if err != nil {
|
||||
log.Printf("Failed to parse HTML content '%s': %v, falling back to text", htmlContent, err)
|
||||
i.injectTextContent(node, htmlContent)
|
||||
log.Printf("Failed to parse HTML content '%s': %v, falling back to text node", htmlContent, err)
|
||||
// Fallback: inject as text node
|
||||
i.clearNode(node)
|
||||
textNode := &html.Node{
|
||||
Type: html.TextNode,
|
||||
Data: htmlContent,
|
||||
}
|
||||
node.AppendChild(textNode)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user