feat: implement professional modal editing forms (Phase 1.2)

MAJOR UX IMPROVEMENT: Replace basic prompt() with professional forms

New Features:
- Professional modal overlays with backdrop and ESC/click-outside cancel
- Dynamic form generation based on content type and HTML element
- Smart field detection: H1-H6→text, P→textarea, A→link with URL
- Mobile-responsive form positioning and widths
- Complete CSS styling with focus states and transitions
- Proper save/cancel event handling

Technical Implementation:
- Created lib/src/ui/form-renderer.js with modern ES6+ modules
- Integrated into core editor.js with form renderer instance
- Support for text, textarea, markdown, and link field types
- XSS protection with HTML escaping
- Responsive design: mobile-first form sizing
- Professional styling matching prototype quality

Before: Basic browser prompt() for all editing
After: Content-aware professional modal forms

This brings the library from proof-of-concept to professional-grade
editing experience, closing the major UX gap with the archived prototype.

Phase 1.2  COMPLETED - Next: Authentication system (Phase 1.1)
This commit is contained in:
2025-09-03 19:32:01 +02:00
parent ca3df47451
commit 3f90bf9c3b
5 changed files with 1010 additions and 40 deletions

View File

@@ -1,3 +1,5 @@
import { InsertrFormRenderer } from '../ui/form-renderer.js';
/**
* InsertrEditor - Visual editing functionality
*/
@@ -6,6 +8,7 @@ export class InsertrEditor {
this.core = core;
this.options = options;
this.isActive = false;
this.formRenderer = new InsertrFormRenderer();
}
start() {
@@ -54,29 +57,64 @@ export class InsertrEditor {
}
openEditor(meta) {
const { contentId, contentType, element } = meta;
const currentContent = element.textContent.trim();
const { element } = meta;
const currentContent = this.extractCurrentContent(element);
// For now, use a simple prompt (will be replaced with proper modal)
const newContent = prompt(
`Edit ${contentType} content (ID: ${contentId}):`,
currentContent
// Show professional form instead of prompt
this.formRenderer.showEditForm(
meta,
currentContent,
(formData) => this.handleSave(meta, formData),
() => this.handleCancel(meta)
);
}
extractCurrentContent(element) {
// For links, extract both text and URL
if (element.tagName.toLowerCase() === 'a') {
return {
text: element.textContent.trim(),
url: element.getAttribute('href') || ''
};
}
if (newContent !== null && newContent !== currentContent) {
this.updateContent(meta, newContent);
// For other elements, just return text content
return element.textContent.trim();
}
handleSave(meta, formData) {
console.log('💾 Saving content:', meta.contentId, formData);
// Update element content based on type
this.updateElementContent(meta.element, formData);
// Close form
this.formRenderer.closeForm();
// TODO: Save to backend API
console.log(`✅ Content saved:`, meta.contentId, formData);
}
handleCancel(meta) {
console.log('❌ Edit cancelled:', meta.contentId);
}
updateElementContent(element, formData) {
if (element.tagName.toLowerCase() === 'a') {
// Update link element
if (formData.text !== undefined) {
element.textContent = formData.text;
}
if (formData.url !== undefined) {
element.setAttribute('href', formData.url);
}
} else {
// Update text content
element.textContent = formData.text || '';
}
}
updateContent(meta, newContent) {
const { element } = meta;
// Update the element content
element.textContent = newContent;
// TODO: Save to backend API
console.log(`💾 Content updated:`, meta.contentId, newContent);
}
// Legacy method - now handled by handleSave and updateElementContent
addEditorStyles() {
const styles = `