Fix edit form content extraction - show clean customer view

🐛 Problem: Edit forms showed client view with edit buttons/emojis
 Solution: Extract clean content without edit interface elements

🔧 Changes:
- extractContentFromElement() now properly removes all edit UI
- Improved htmlToMarkdown() for better rich content conversion
- setupEditableElement() preserves original clean content
- Enhanced whitespace normalization in markdown conversion
- Handles both simple text and rich markdown content types

🎯 User Experience:
- Client sees: Content with edit buttons (✏️)
- Edit form shows: Clean, properly formatted content
- Customer sees: Original clean content (no edit UI)

 Whitespace improvements:
- Removes excessive indentation and spacing
- Normalizes line breaks and paragraph spacing
- Clean, readable content in edit forms

Critical fix for proper edit-in-place functionality
This commit is contained in:
2025-08-29 23:01:55 +02:00
parent 1a0a6b3254
commit 04e669eb95

View File

@@ -66,6 +66,18 @@ class Insertr {
} }
setupEditableElement(element, contentId) { setupEditableElement(element, contentId) {
// Store original clean content before adding edit interface
if (!element.querySelector('.insertr-original-content')) {
const originalContent = element.cloneNode(true);
originalContent.classList.add('insertr-original-content');
originalContent.style.display = 'none';
element.appendChild(originalContent);
}
// Remove any existing edit buttons to avoid duplicates
const existingBtn = element.querySelector('.insertr-edit-btn');
if (existingBtn) existingBtn.remove();
// Add edit button // Add edit button
const editBtn = document.createElement('button'); const editBtn = document.createElement('button');
editBtn.className = 'insertr-edit-btn'; editBtn.className = 'insertr-edit-btn';
@@ -239,12 +251,42 @@ class Insertr {
} }
extractContentFromElement(element) { extractContentFromElement(element) {
const clone = element.cloneNode(true); // Get the original content without edit interface elements
// Remove edit button const originalContent = element.querySelector('.insertr-original-content');
const editBtn = clone.querySelector('.insertr-edit-btn');
if (editBtn) editBtn.remove();
return clone.textContent.trim() || clone.innerHTML.trim(); if (originalContent) {
// We have the original content stored, use that
const clone = originalContent.cloneNode(true);
// Remove any edit buttons from the clone
const editBtns = clone.querySelectorAll('.insertr-edit-btn');
editBtns.forEach(btn => btn.remove());
const contentType = element.getAttribute('data-content-type') || 'simple';
if (contentType === 'rich') {
// For rich content, convert back to markdown
return this.htmlToMarkdown(clone.innerHTML);
} else {
// For simple content, return clean text
return clone.textContent.trim();
}
} else {
// Fallback: extract from current element (first time editing)
const clone = element.cloneNode(true);
// Remove edit button and any insertr interface elements
const editBtns = clone.querySelectorAll('.insertr-edit-btn');
editBtns.forEach(btn => btn.remove());
const contentType = element.getAttribute('data-content-type') || 'simple';
if (contentType === 'rich') {
// For rich content, convert HTML to markdown
return this.htmlToMarkdown(clone.innerHTML);
} else {
// For simple content, return clean text
return clone.textContent.trim();
}
}
} }
setupAuthenticationControls() { setupAuthenticationControls() {
@@ -357,7 +399,46 @@ class Insertr {
// Remove edit buttons and other insertr elements // Remove edit buttons and other insertr elements
tempDiv.querySelectorAll('.insertr-edit-btn').forEach(btn => btn.remove()); tempDiv.querySelectorAll('.insertr-edit-btn').forEach(btn => btn.remove());
return tempDiv.textContent || tempDiv.innerText || ''; // Convert HTML back to markdown
let markdown = tempDiv.innerHTML;
// Convert headings
markdown = markdown.replace(/<h1[^>]*>(.*?)<\/h1>/gi, '# $1\n\n');
markdown = markdown.replace(/<h2[^>]*>(.*?)<\/h2>/gi, '## $1\n\n');
markdown = markdown.replace(/<h3[^>]*>(.*?)<\/h3>/gi, '### $1\n\n');
// Convert formatting
markdown = markdown.replace(/<strong[^>]*>(.*?)<\/strong>/gi, '**$1**');
markdown = markdown.replace(/<em[^>]*>(.*?)<\/em>/gi, '*$1*');
// Convert links
markdown = markdown.replace(/<a[^>]*href="([^"]*)"[^>]*>(.*?)<\/a>/gi, '[$2]($1)');
// Convert lists
markdown = markdown.replace(/<ul[^>]*>(.*?)<\/ul>/gis, (match, content) => {
return content.replace(/<li[^>]*>(.*?)<\/li>/gi, '- $1\n');
});
// Convert paragraphs and preserve structure
markdown = markdown.replace(/<p[^>]*class="lead"[^>]*>(.*?)<\/p>/gi, '\n$1\n\n');
markdown = markdown.replace(/<p[^>]*>(.*?)<\/p>/gi, '\n$1\n\n');
// Clean up HTML tags and entities
markdown = markdown.replace(/<[^>]*>/g, '');
markdown = markdown.replace(/&nbsp;/g, ' ');
markdown = markdown.replace(/&amp;/g, '&');
markdown = markdown.replace(/&lt;/g, '<');
markdown = markdown.replace(/&gt;/g, '>');
// Clean up excessive whitespace and normalize line breaks
markdown = markdown.replace(/[ \t]+/g, ' '); // Multiple spaces/tabs to single space
markdown = markdown.replace(/\n[ \t]+/g, '\n'); // Remove leading whitespace on lines
markdown = markdown.replace(/[ \t]+\n/g, '\n'); // Remove trailing whitespace on lines
markdown = markdown.replace(/\n\n\n+/g, '\n\n'); // Multiple blank lines to double
markdown = markdown.replace(/^\n+/, ''); // Remove leading newlines
markdown = markdown.replace(/\n+$/, ''); // Remove trailing newlines
return markdown.trim();
} }
getTextNodes(node) { getTextNodes(node) {