timeline-svg/engine.js

897 lines
33 KiB
JavaScript
Raw Normal View History

2025-11-18 21:36:59 +01:00
window.timelineEngine = {
config: null,
template: null,
csvOverride: false,
cssOverride: false,
feat: add inline file editing with modification tracking and save functionality Add comprehensive inline editing capabilities for all project files with visual modification tracking and batch save functionality. Features: - Edit buttons next to each file load button (Project, SVG, CSS, CSV) - Modal editor with syntax validation for JSON files - Real-time preview updates after applying changes - Visual "MODIFIED" badges on edited files - "Save Changes" button to download all modified files - Keyboard shortcuts (Escape to close editor) Implementation: - file-editor.js: New module handling all editor functionality - Editor modal with textarea for content editing - Modification tracking using Set data structure - File-specific validation (JSON syntax checking) - Batch download of all modified files - Visual badge updates for modified state - index.html: UI updates - Edit buttons added to all file items - Modal HTML structure for editor - Save Changes button in controls area - CSS styling for editor modal and modified badges - engine.js: Integration and data storage - Store CSV and CSS content when loaded (for editing) - Enable edit buttons when files are successfully loaded - Works with all loading methods (folder picker, individual files, auto-load) - CSS now loaded via fetch to store content (changed from link href) - Makefile: Include file-editor.js in distribution build User workflow: 1. Load project files (folder picker or individual files) 2. Click "✏️ Edit" button next to any file 3. Make changes in modal editor 4. Click "Apply Changes" to update and see immediate preview 5. Modified files show orange "MODIFIED" badge 6. Click "💾 Save Changes" to download all modified files at once Technical details: - Edit buttons start disabled, enabled when file loads - JSON validation prevents saving invalid configurations - Changes apply immediately to in-memory data - Timeline regenerates automatically after edits - Modified state persists until files are saved - Optional clearing of modified state after download Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 17:15:36 +01:00
csvData: null, // Store current CSV text
cssData: null, // Store current CSS text
2025-11-18 21:36:59 +01:00
projectBasePath: '',
showTemplatePreview() {
if (!this.template) return;
console.log("Showing template preview");
// Detect template theme for appropriate colors
const isEnhanced = this.template.includes('Enhanced');
const isBlueTheme = this.template.includes('My Project');
const isGreenTheme = this.template.includes('Example');
// Color scheme selection
let primaryColor = '#0A4D8C'; // default
let secondaryColor = '#5C6B7A'; // default
if (isEnhanced) {
if (isBlueTheme) {
primaryColor = '#3b82f6';
secondaryColor = '#60a5fa';
} else if (isGreenTheme) {
primaryColor = '#2d8659';
secondaryColor = '#4a9b6b';
}
}
// Create sample month graphics matching the template style
const sampleMonths = isEnhanced ? `
<line x1="240" y1="75" x2="240" y2="300" stroke="${secondaryColor}" stroke-width="2" opacity="0.6" />
<rect x="210" y="70" width="60" height="25" fill="${primaryColor}" opacity="0.1" rx="4" />
<text x="244" y="90" fill="${primaryColor}" font-size="13" font-weight="600">Jan 25</text>
<line x1="360" y1="75" x2="360" y2="300" stroke="${secondaryColor}" stroke-width="2" opacity="0.6" />
<rect x="330" y="70" width="60" height="25" fill="${primaryColor}" opacity="0.1" rx="4" />
<text x="364" y="90" fill="${primaryColor}" font-size="13" font-weight="600">Feb 25</text>
<line x1="480" y1="75" x2="480" y2="300" stroke="${secondaryColor}" stroke-width="2" opacity="0.6" />
<rect x="450" y="70" width="60" height="25" fill="${primaryColor}" opacity="0.1" rx="4" />
<text x="484" y="90" fill="${primaryColor}" font-size="13" font-weight="600">Mar 25</text>
<line x1="600" y1="75" x2="600" y2="300" stroke="${secondaryColor}" stroke-width="2" opacity="0.6" />
<rect x="570" y="70" width="60" height="25" fill="${primaryColor}" opacity="0.1" rx="4" />
<text x="604" y="90" fill="${primaryColor}" font-size="13" font-weight="600">Apr 25</text>
` : `
<line x1="240" y1="75" x2="240" y2="300" stroke="#E3E8EF" />
<text x="244" y="90" fill="#5C6B7A" font-size="12">Jan 25</text>
<line x1="360" y1="75" x2="360" y2="300" stroke="#E3E8EF" />
<text x="364" y="90" fill="#5C6B7A" font-size="12">Feb 25</text>
<line x1="480" y1="75" x2="480" y2="300" stroke="#E3E8EF" />
<text x="484" y="90" fill="#5C6B7A" font-size="12">Mar 25</text>
<line x1="600" y1="75" x2="600" y2="300" stroke="#E3E8EF" />
<text x="604" y="90" fill="#5C6B7A" font-size="12">Apr 25</text>
`;
// Create sample lane content matching the template style
const sampleLanes = isEnhanced ? `
<rect x="40" y="116" width="640" height="80" fill="rgba(255,255,255,0.7)" stroke="${secondaryColor}" stroke-width="1" opacity="0.5" rx="8" />
<text x="56" y="136" fill="${primaryColor}" font-size="14" font-weight="700">Example Epic</text>
<circle cx="270" cy="156" r="6" fill="${primaryColor}" stroke="${secondaryColor}" stroke-width="2" />
<text x="282" y="160" font-size="12" fill="${primaryColor}" font-weight="500">
<tspan class="item-id">EX-1: </tspan>
<tspan class="item-title" fill="${primaryColor === '#3b82f6' ? '#1e40af' : '#1e5a3d'}">Sample Task Preview</tspan>
</text>
<rect x="40" y="212" width="640" height="80" fill="rgba(255,255,255,0.7)" stroke="${secondaryColor}" stroke-width="1" opacity="0.5" rx="8" />
<text x="56" y="232" fill="${primaryColor}" font-size="14" font-weight="700">Another Epic</text>
<circle cx="390" cy="252" r="6" fill="${primaryColor}" stroke="${secondaryColor}" stroke-width="2" />
<text x="402" y="256" font-size="12" fill="${primaryColor}" font-weight="500">
<tspan class="item-id">EX-2: </tspan>
<tspan class="item-title" fill="${primaryColor === '#3b82f6' ? '#1e40af' : '#1e5a3d'}">Template Preview</tspan>
</text>
` : `
<rect x="40" y="116" width="640" height="80" fill="#FFFFFF" stroke="#E3E8EF" rx="10" />
<text x="56" y="136" fill="#0B1F3B" font-size="14" font-weight="600">Example Epic</text>
<circle cx="270" cy="156" r="5" fill="#0A4D8C" />
<text x="282" y="160" font-size="12" fill="#0B1F3B">
<tspan class="item-id">EX-1: </tspan>
<tspan class="item-title">Sample Task Preview</tspan>
</text>
<rect x="40" y="212" width="640" height="80" fill="#FFFFFF" stroke="#E3E8EF" rx="10" />
<text x="56" y="232" fill="#0B1F3B" font-size="14" font-weight="600">Another Epic</text>
<circle cx="390" cy="252" r="5" fill="#0A4D8C" />
<text x="402" y="256" font-size="12" fill="#0B1F3B">
<tspan class="item-id">EX-2: </tspan>
<tspan class="item-title">Template Preview</tspan>
</text>
`;
// Replace placeholders with sample data
let previewSvg = this.template
.replace("{{MONTHS}}", sampleMonths)
.replace("{{LANES}}", sampleLanes);
// Add dimensions for proper preview display (using reasonable default size)
const previewWidth = 720;
const previewHeight = 360;
previewSvg = previewSvg.replace(
/<svg([^>]*?)>/,
`<svg$1 width="${previewWidth}" height="${previewHeight}" viewBox="0 0 ${previewWidth} ${previewHeight}">`
);
document.getElementById("viewer").innerHTML = previewSvg;
// Initialize zoom functionality for the preview
if (window.svgViewer) {
window.svgViewer.resetZoom();
window.svgViewer.updateZoomControls();
}
console.log("Template preview displayed with theme:", { isEnhanced, isBlueTheme, isGreenTheme });
},
updateFileStatus(fileType, filename, status = 'loaded') {
const statusElement = document.getElementById(`${fileType}File`);
if (statusElement) {
if (filename && status === 'loaded') {
statusElement.textContent = filename;
statusElement.style.color = '#28a745';
statusElement.title = `Loaded: ${filename}`;
} else if (filename && status === 'error') {
statusElement.textContent = `Error: ${filename}`;
statusElement.style.color = '#dc3545';
statusElement.title = `Failed to load: ${filename}`;
} else {
statusElement.textContent = 'Not loaded';
statusElement.style.color = '#6c757d';
statusElement.title = 'No file loaded';
}
}
// Add visual feedback with brief highlight animation
if (statusElement && filename) {
statusElement.style.transform = 'scale(1.05)';
setTimeout(() => {
statusElement.style.transform = 'scale(1)';
}, 200);
}
},
resolveProjectPath(relativePath) {
if (!relativePath) return relativePath;
// If path is already absolute (starts with http/https) or has no base path, return as-is
if (relativePath.startsWith('http') || !this.projectBasePath) {
return relativePath;
}
const resolvedPath = this.projectBasePath + relativePath;
console.log("Resolved path:", relativePath, "->", resolvedPath);
return resolvedPath;
},
2025-11-18 21:36:59 +01:00
async autoLoadDefaultProject() {
console.log("Starting autoLoadDefaultProject");
// Try projects in order: binect, my-project, example
const candidates = [
{ path: "binect/project.json", basePath: "binect/" },
{ path: "my-project/project.json", basePath: "my-project/" },
{ path: "example/project.json", basePath: "example/" }
];
for (const candidate of candidates) {
2025-11-18 21:36:59 +01:00
try {
const res = await fetch(candidate.path);
2025-11-18 21:36:59 +01:00
if (!res.ok) continue;
const cfg = await res.json();
this.projectBasePath = candidate.basePath;
2025-11-18 21:36:59 +01:00
await this.loadProjectConfigObject(cfg);
console.log("Project loaded successfully from:", candidate.path);
2025-11-18 21:36:59 +01:00
return;
} catch (e) {
continue;
}
}
console.log("No project could be auto-loaded");
2025-11-18 21:36:59 +01:00
},
async loadProjectConfigObject(cfg) {
this.config = cfg;
const name = cfg.name || "Timeline";
document.getElementById("projectName").textContent = name;
document.getElementById("projectSubtitle").textContent =
2025-11-18 21:36:59 +01:00
cfg.description || "Projektkonfiguration geladen.";
// Update project status
this.updateFileStatus('project', name, 'loaded');
feat: add inline file editing with modification tracking and save functionality Add comprehensive inline editing capabilities for all project files with visual modification tracking and batch save functionality. Features: - Edit buttons next to each file load button (Project, SVG, CSS, CSV) - Modal editor with syntax validation for JSON files - Real-time preview updates after applying changes - Visual "MODIFIED" badges on edited files - "Save Changes" button to download all modified files - Keyboard shortcuts (Escape to close editor) Implementation: - file-editor.js: New module handling all editor functionality - Editor modal with textarea for content editing - Modification tracking using Set data structure - File-specific validation (JSON syntax checking) - Batch download of all modified files - Visual badge updates for modified state - index.html: UI updates - Edit buttons added to all file items - Modal HTML structure for editor - Save Changes button in controls area - CSS styling for editor modal and modified badges - engine.js: Integration and data storage - Store CSV and CSS content when loaded (for editing) - Enable edit buttons when files are successfully loaded - Works with all loading methods (folder picker, individual files, auto-load) - CSS now loaded via fetch to store content (changed from link href) - Makefile: Include file-editor.js in distribution build User workflow: 1. Load project files (folder picker or individual files) 2. Click "✏️ Edit" button next to any file 3. Make changes in modal editor 4. Click "Apply Changes" to update and see immediate preview 5. Modified files show orange "MODIFIED" badge 6. Click "💾 Save Changes" to download all modified files at once Technical details: - Edit buttons start disabled, enabled when file loads - JSON validation prevents saving invalid configurations - Changes apply immediately to in-memory data - Timeline regenerates automatically after edits - Modified state persists until files are saved - Optional clearing of modified state after download Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 17:15:36 +01:00
// Enable project edit button
if (window.fileEditor) {
window.fileEditor.enableEditButton('project');
}
// Show field mappings in debug panel
this.showFieldMappings();
// Track loading errors for user feedback
const loadingErrors = [];
2025-11-18 21:36:59 +01:00
// Stylesheet
if (cfg.stylesheet && !this.cssOverride) {
const stylesheetPath = this.resolveProjectPath(cfg.stylesheet);
feat: add inline file editing with modification tracking and save functionality Add comprehensive inline editing capabilities for all project files with visual modification tracking and batch save functionality. Features: - Edit buttons next to each file load button (Project, SVG, CSS, CSV) - Modal editor with syntax validation for JSON files - Real-time preview updates after applying changes - Visual "MODIFIED" badges on edited files - "Save Changes" button to download all modified files - Keyboard shortcuts (Escape to close editor) Implementation: - file-editor.js: New module handling all editor functionality - Editor modal with textarea for content editing - Modification tracking using Set data structure - File-specific validation (JSON syntax checking) - Batch download of all modified files - Visual badge updates for modified state - index.html: UI updates - Edit buttons added to all file items - Modal HTML structure for editor - Save Changes button in controls area - CSS styling for editor modal and modified badges - engine.js: Integration and data storage - Store CSV and CSS content when loaded (for editing) - Enable edit buttons when files are successfully loaded - Works with all loading methods (folder picker, individual files, auto-load) - CSS now loaded via fetch to store content (changed from link href) - Makefile: Include file-editor.js in distribution build User workflow: 1. Load project files (folder picker or individual files) 2. Click "✏️ Edit" button next to any file 3. Make changes in modal editor 4. Click "Apply Changes" to update and see immediate preview 5. Modified files show orange "MODIFIED" badge 6. Click "💾 Save Changes" to download all modified files at once Technical details: - Edit buttons start disabled, enabled when file loads - JSON validation prevents saving invalid configurations - Changes apply immediately to in-memory data - Timeline regenerates automatically after edits - Modified state persists until files are saved - Optional clearing of modified state after download Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 17:15:36 +01:00
// Load CSS via fetch to store content for editing
try {
const cssResponse = await fetch(stylesheetPath);
if (cssResponse.ok) {
const cssText = await cssResponse.text();
feat: add inline file editing with modification tracking and save functionality Add comprehensive inline editing capabilities for all project files with visual modification tracking and batch save functionality. Features: - Edit buttons next to each file load button (Project, SVG, CSS, CSV) - Modal editor with syntax validation for JSON files - Real-time preview updates after applying changes - Visual "MODIFIED" badges on edited files - "Save Changes" button to download all modified files - Keyboard shortcuts (Escape to close editor) Implementation: - file-editor.js: New module handling all editor functionality - Editor modal with textarea for content editing - Modification tracking using Set data structure - File-specific validation (JSON syntax checking) - Batch download of all modified files - Visual badge updates for modified state - index.html: UI updates - Edit buttons added to all file items - Modal HTML structure for editor - Save Changes button in controls area - CSS styling for editor modal and modified badges - engine.js: Integration and data storage - Store CSV and CSS content when loaded (for editing) - Enable edit buttons when files are successfully loaded - Works with all loading methods (folder picker, individual files, auto-load) - CSS now loaded via fetch to store content (changed from link href) - Makefile: Include file-editor.js in distribution build User workflow: 1. Load project files (folder picker or individual files) 2. Click "✏️ Edit" button next to any file 3. Make changes in modal editor 4. Click "Apply Changes" to update and see immediate preview 5. Modified files show orange "MODIFIED" badge 6. Click "💾 Save Changes" to download all modified files at once Technical details: - Edit buttons start disabled, enabled when file loads - JSON validation prevents saving invalid configurations - Changes apply immediately to in-memory data - Timeline regenerates automatically after edits - Modified state persists until files are saved - Optional clearing of modified state after download Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 17:15:36 +01:00
this.cssData = cssText; // Store for editing
// Apply CSS
const blob = new Blob([cssText], { type: "text/css" });
const linkElement = document.getElementById("dynamicCss");
linkElement.href = URL.createObjectURL(blob);
this.updateFileStatus('css', cfg.stylesheet + ' ✨', 'loaded');
// Enable CSS edit button
if (window.fileEditor) {
window.fileEditor.enableEditButton('css');
}
console.log("Stylesheet loaded successfully:", stylesheetPath);
} else {
throw new Error(`HTTP ${cssResponse.status}`);
feat: add inline file editing with modification tracking and save functionality Add comprehensive inline editing capabilities for all project files with visual modification tracking and batch save functionality. Features: - Edit buttons next to each file load button (Project, SVG, CSS, CSV) - Modal editor with syntax validation for JSON files - Real-time preview updates after applying changes - Visual "MODIFIED" badges on edited files - "Save Changes" button to download all modified files - Keyboard shortcuts (Escape to close editor) Implementation: - file-editor.js: New module handling all editor functionality - Editor modal with textarea for content editing - Modification tracking using Set data structure - File-specific validation (JSON syntax checking) - Batch download of all modified files - Visual badge updates for modified state - index.html: UI updates - Edit buttons added to all file items - Modal HTML structure for editor - Save Changes button in controls area - CSS styling for editor modal and modified badges - engine.js: Integration and data storage - Store CSV and CSS content when loaded (for editing) - Enable edit buttons when files are successfully loaded - Works with all loading methods (folder picker, individual files, auto-load) - CSS now loaded via fetch to store content (changed from link href) - Makefile: Include file-editor.js in distribution build User workflow: 1. Load project files (folder picker or individual files) 2. Click "✏️ Edit" button next to any file 3. Make changes in modal editor 4. Click "Apply Changes" to update and see immediate preview 5. Modified files show orange "MODIFIED" badge 6. Click "💾 Save Changes" to download all modified files at once Technical details: - Edit buttons start disabled, enabled when file loads - JSON validation prevents saving invalid configurations - Changes apply immediately to in-memory data - Timeline regenerates automatically after edits - Modified state persists until files are saved - Optional clearing of modified state after download Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 17:15:36 +01:00
}
} catch (e) {
console.error("Stylesheet could not be loaded:", e);
this.updateFileStatus('css', cfg.stylesheet, 'error');
loadingErrors.push(`Stylesheet: ${cfg.stylesheet}`);
feat: add inline file editing with modification tracking and save functionality Add comprehensive inline editing capabilities for all project files with visual modification tracking and batch save functionality. Features: - Edit buttons next to each file load button (Project, SVG, CSS, CSV) - Modal editor with syntax validation for JSON files - Real-time preview updates after applying changes - Visual "MODIFIED" badges on edited files - "Save Changes" button to download all modified files - Keyboard shortcuts (Escape to close editor) Implementation: - file-editor.js: New module handling all editor functionality - Editor modal with textarea for content editing - Modification tracking using Set data structure - File-specific validation (JSON syntax checking) - Batch download of all modified files - Visual badge updates for modified state - index.html: UI updates - Edit buttons added to all file items - Modal HTML structure for editor - Save Changes button in controls area - CSS styling for editor modal and modified badges - engine.js: Integration and data storage - Store CSV and CSS content when loaded (for editing) - Enable edit buttons when files are successfully loaded - Works with all loading methods (folder picker, individual files, auto-load) - CSS now loaded via fetch to store content (changed from link href) - Makefile: Include file-editor.js in distribution build User workflow: 1. Load project files (folder picker or individual files) 2. Click "✏️ Edit" button next to any file 3. Make changes in modal editor 4. Click "Apply Changes" to update and see immediate preview 5. Modified files show orange "MODIFIED" badge 6. Click "💾 Save Changes" to download all modified files at once Technical details: - Edit buttons start disabled, enabled when file loads - JSON validation prevents saving invalid configurations - Changes apply immediately to in-memory data - Timeline regenerates automatically after edits - Modified state persists until files are saved - Optional clearing of modified state after download Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 17:15:36 +01:00
}
2025-11-18 21:36:59 +01:00
}
// SVG template
if (cfg.svgTemplate) {
try {
const templatePath = this.resolveProjectPath(cfg.svgTemplate);
console.log("Attempting to fetch SVG template from:", templatePath);
const svgResponse = await fetch(templatePath);
console.log("SVG template fetch response:", svgResponse.status, svgResponse.statusText);
if (!svgResponse.ok) {
throw new Error(`HTTP ${svgResponse.status}: ${svgResponse.statusText}`);
}
this.template = await svgResponse.text();
console.log("SVG template loaded, length:", this.template.length);
this.updateFileStatus('svg', cfg.svgTemplate, 'loaded');
feat: add inline file editing with modification tracking and save functionality Add comprehensive inline editing capabilities for all project files with visual modification tracking and batch save functionality. Features: - Edit buttons next to each file load button (Project, SVG, CSS, CSV) - Modal editor with syntax validation for JSON files - Real-time preview updates after applying changes - Visual "MODIFIED" badges on edited files - "Save Changes" button to download all modified files - Keyboard shortcuts (Escape to close editor) Implementation: - file-editor.js: New module handling all editor functionality - Editor modal with textarea for content editing - Modification tracking using Set data structure - File-specific validation (JSON syntax checking) - Batch download of all modified files - Visual badge updates for modified state - index.html: UI updates - Edit buttons added to all file items - Modal HTML structure for editor - Save Changes button in controls area - CSS styling for editor modal and modified badges - engine.js: Integration and data storage - Store CSV and CSS content when loaded (for editing) - Enable edit buttons when files are successfully loaded - Works with all loading methods (folder picker, individual files, auto-load) - CSS now loaded via fetch to store content (changed from link href) - Makefile: Include file-editor.js in distribution build User workflow: 1. Load project files (folder picker or individual files) 2. Click "✏️ Edit" button next to any file 3. Make changes in modal editor 4. Click "Apply Changes" to update and see immediate preview 5. Modified files show orange "MODIFIED" badge 6. Click "💾 Save Changes" to download all modified files at once Technical details: - Edit buttons start disabled, enabled when file loads - JSON validation prevents saving invalid configurations - Changes apply immediately to in-memory data - Timeline regenerates automatically after edits - Modified state persists until files are saved - Optional clearing of modified state after download Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 17:15:36 +01:00
// Enable SVG edit button
if (window.fileEditor) {
window.fileEditor.enableEditButton('svg');
}
// Show template fields in debug panel
this.showTemplateFields();
// Show template preview if no CSV data is loaded yet
if (!this.csvOverride && document.querySelector("#viewer").innerHTML.includes("Keine Timeline verfügbar")) {
this.showTemplatePreview();
}
2025-11-18 21:36:59 +01:00
} catch (e) {
console.error("SVG template could not be loaded:", e);
console.error("Failed SVG template path was:", this.resolveProjectPath(cfg.svgTemplate));
this.updateFileStatus('svg', cfg.svgTemplate, 'error');
loadingErrors.push(`SVG template: ${cfg.svgTemplate}`);
2025-11-18 21:36:59 +01:00
}
}
// CSV data
if (cfg.dataSource && !this.csvOverride) {
try {
const csvPath = this.resolveProjectPath(cfg.dataSource);
console.log("Attempting to fetch CSV from:", csvPath);
const csvResponse = await fetch(csvPath);
console.log("CSV fetch response:", csvResponse.status, csvResponse.statusText);
if (!csvResponse.ok) {
throw new Error(`HTTP ${csvResponse.status}: ${csvResponse.statusText}`);
}
const csvText = await csvResponse.text();
console.log("CSV text loaded, length:", csvText.length);
console.log("CSV preview:", csvText.substring(0, 200));
this.updateFileStatus('csv', cfg.dataSource, 'loaded');
feat: add inline file editing with modification tracking and save functionality Add comprehensive inline editing capabilities for all project files with visual modification tracking and batch save functionality. Features: - Edit buttons next to each file load button (Project, SVG, CSS, CSV) - Modal editor with syntax validation for JSON files - Real-time preview updates after applying changes - Visual "MODIFIED" badges on edited files - "Save Changes" button to download all modified files - Keyboard shortcuts (Escape to close editor) Implementation: - file-editor.js: New module handling all editor functionality - Editor modal with textarea for content editing - Modification tracking using Set data structure - File-specific validation (JSON syntax checking) - Batch download of all modified files - Visual badge updates for modified state - index.html: UI updates - Edit buttons added to all file items - Modal HTML structure for editor - Save Changes button in controls area - CSS styling for editor modal and modified badges - engine.js: Integration and data storage - Store CSV and CSS content when loaded (for editing) - Enable edit buttons when files are successfully loaded - Works with all loading methods (folder picker, individual files, auto-load) - CSS now loaded via fetch to store content (changed from link href) - Makefile: Include file-editor.js in distribution build User workflow: 1. Load project files (folder picker or individual files) 2. Click "✏️ Edit" button next to any file 3. Make changes in modal editor 4. Click "Apply Changes" to update and see immediate preview 5. Modified files show orange "MODIFIED" badge 6. Click "💾 Save Changes" to download all modified files at once Technical details: - Edit buttons start disabled, enabled when file loads - JSON validation prevents saving invalid configurations - Changes apply immediately to in-memory data - Timeline regenerates automatically after edits - Modified state persists until files are saved - Optional clearing of modified state after download Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 17:15:36 +01:00
// Enable CSV edit button
if (window.fileEditor) {
window.fileEditor.enableEditButton('csv');
}
2025-11-18 21:36:59 +01:00
this.processCsv(csvText);
} catch (e) {
console.error("CSV could not be loaded:", e);
console.error("Failed CSV path was:", this.resolveProjectPath(cfg.dataSource));
this.updateFileStatus('csv', cfg.dataSource, 'error');
loadingErrors.push(`CSV data: ${cfg.dataSource}`);
2025-11-18 21:36:59 +01:00
}
}
// Show user feedback if there were loading errors
if (loadingErrors.length > 0) {
setTimeout(() => {
const viewer = document.getElementById("viewer");
if (viewer && !viewer.innerHTML.includes('<svg')) {
viewer.innerHTML = `
<div style="text-align:center; padding:40px 20px; color:#6c757d;">
<div style="font-size:48px; margin-bottom:16px;"></div>
<h4 style="margin:0 0 8px 0; color:#dc3545;">Projektdateien konnten nicht geladen werden</h4>
<p style="margin:0 0 12px 0; font-size:14px;">
<strong>Fehlgeschlagene Dateien:</strong><br>
${loadingErrors.map(err => `${err}`).join('<br>')}
</p>
<p style="margin:0; font-size:12px; color:#6c757d;">
💡 <strong>Tipp:</strong> Lade die Dateien manuell mit den Load-Buttons oben oder
verwende einen lokalen Server (<code>make serve</code>).
</p>
</div>
`;
}
}, 500); // Small delay to let other operations complete
}
2025-11-18 21:36:59 +01:00
},
processCsv(text) {
console.log("processCsv called with text length:", text?.length);
feat: add inline file editing with modification tracking and save functionality Add comprehensive inline editing capabilities for all project files with visual modification tracking and batch save functionality. Features: - Edit buttons next to each file load button (Project, SVG, CSS, CSV) - Modal editor with syntax validation for JSON files - Real-time preview updates after applying changes - Visual "MODIFIED" badges on edited files - "Save Changes" button to download all modified files - Keyboard shortcuts (Escape to close editor) Implementation: - file-editor.js: New module handling all editor functionality - Editor modal with textarea for content editing - Modification tracking using Set data structure - File-specific validation (JSON syntax checking) - Batch download of all modified files - Visual badge updates for modified state - index.html: UI updates - Edit buttons added to all file items - Modal HTML structure for editor - Save Changes button in controls area - CSS styling for editor modal and modified badges - engine.js: Integration and data storage - Store CSV and CSS content when loaded (for editing) - Enable edit buttons when files are successfully loaded - Works with all loading methods (folder picker, individual files, auto-load) - CSS now loaded via fetch to store content (changed from link href) - Makefile: Include file-editor.js in distribution build User workflow: 1. Load project files (folder picker or individual files) 2. Click "✏️ Edit" button next to any file 3. Make changes in modal editor 4. Click "Apply Changes" to update and see immediate preview 5. Modified files show orange "MODIFIED" badge 6. Click "💾 Save Changes" to download all modified files at once Technical details: - Edit buttons start disabled, enabled when file loads - JSON validation prevents saving invalid configurations - Changes apply immediately to in-memory data - Timeline regenerates automatically after edits - Modified state persists until files are saved - Optional clearing of modified state after download Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 17:15:36 +01:00
// Store CSV data for editing
this.csvData = text;
2025-11-18 21:36:59 +01:00
if (!this.config || !this.config.fieldMapping) {
console.error("No config or fieldMapping found.");
return;
}
if (typeof Papa === 'undefined') {
console.error("Papa Parse library not available");
document.getElementById("viewer").innerHTML =
"<em style='color:#dc3545;'>Fehler: CSV Parser nicht verfügbar.</em>";
return;
}
2025-11-18 21:36:59 +01:00
const m = this.config.fieldMapping;
const self = this; // Capture 'this' context
2025-11-18 21:36:59 +01:00
Papa.parse(text, {
header: true,
skipEmptyLines: true,
complete: (res) => {
console.log("Papa.parse complete, found", res.data.length, "rows");
2025-11-18 21:36:59 +01:00
const rows = res.data;
// Show CSV preview in debug panel
self.showCSVPreview(text, rows);
2025-11-18 21:36:59 +01:00
const items = rows.map((r) => {
const dueField = (m.due || []).find(f => r[f]);
const item = {
2025-11-18 21:36:59 +01:00
id: m.id ? r[m.id] : (r["ID"] || ""),
title: m.title ? r[m.title] : (r["Title"] || ""),
lane: m.lane ? (r[m.lane] || "Ohne Epic") : (r["Lane"] || "Default"),
due: self.parseDate(dueField ? r[dueField] : null)
2025-11-18 21:36:59 +01:00
};
return item;
2025-11-18 21:36:59 +01:00
}).filter(i => i.title && i.due);
console.log("Filtered to", items.length, "valid items");
2025-11-18 21:36:59 +01:00
if (!items.length) {
document.getElementById("viewer").innerHTML =
"<em style='color:#999;'>Keine gültigen Items gefunden.</em>";
return;
}
// Ensure generator is available
if (!window.timelineGenerator) {
console.error("Timeline generator not available");
document.getElementById("viewer").innerHTML =
"<em style='color:#dc3545;'>Fehler: Timeline Generator nicht verfügbar.</em>";
return;
}
try {
console.log("Generating timeline with:", items, self.config, self.template ? "template loaded" : "no template");
// Auto-detect template type: prototype-based (new) or template-based (old)
const isPrototypeBased = self.template && (
self.template.includes('id="month-proto"') ||
self.template.includes('id="lane-proto"') ||
self.template.includes('id="item-proto"')
);
let svg;
if (isPrototypeBased && window.timelineGeneratorDOM) {
console.log("Using DOM-based generator (prototype templates)");
svg = window.timelineGeneratorDOM.generate(items, self.config, self.template);
} else if (window.timelineGenerator) {
console.log("Using string-based generator (template-v2)");
svg = window.timelineGenerator.generate(items, self.config, self.template);
} else {
throw new Error("No timeline generator available");
}
document.getElementById("viewer").innerHTML = svg;
const dlBtn = document.getElementById("downloadSvg");
dlBtn.disabled = false;
dlBtn.style.opacity = 1;
// Initialize zoom functionality for the new SVG
if (window.svgViewer) {
window.svgViewer.resetZoom();
window.svgViewer.updateZoomControls();
}
console.log("Timeline generated successfully");
} catch (error) {
console.error("Error generating timeline:", error);
document.getElementById("viewer").innerHTML =
"<em style='color:#dc3545;'>Fehler beim Generieren der Timeline: " + error.message + "</em>";
}
2025-11-18 21:36:59 +01:00
}
});
},
parseDate(str) {
if (!str) return null;
str = String(str).trim();
let d = null;
// YYYY/MM/DD oder YYYY-MM-DD
let m = str.match(/^(\d{4})[\/-](\d{1,2})[\/-](\d{1,2})$/);
if (m) {
const [_, yy, mm, dd] = m;
d = new Date(Number(yy), Number(mm) - 1, Number(dd));
return isNaN(d.getTime()) ? null : d;
}
// DD.MM.YYYY
m = str.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/);
if (m) {
const [_, dd, mm, yy] = m;
d = new Date(Number(yy), Number(mm) - 1, Number(dd));
return isNaN(d.getTime()) ? null : d;
}
// Fallback
d = new Date(str);
return isNaN(d.getTime()) ? null : d;
},
// --------- Debug Display Functions ---------
showFieldMappings() {
if (!this.config || !this.config.fieldMapping) return;
const debugInfo = document.getElementById("debugInfo");
const fieldMappingInfo = document.getElementById("fieldMappingInfo");
const fieldMappingDisplay = document.getElementById("fieldMappingDisplay");
if (debugInfo && fieldMappingInfo && fieldMappingDisplay) {
debugInfo.style.display = "block";
fieldMappingInfo.style.display = "block";
const mapping = this.config.fieldMapping;
let display = "CSV Column → Timeline Field\n";
display += "━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
display += `ID: ${JSON.stringify(mapping.id)}\n`;
display += `Title: ${JSON.stringify(mapping.title)}\n`;
display += `Lane: ${JSON.stringify(mapping.lane)}\n`;
display += `Due: ${JSON.stringify(mapping.due)}\n`;
if (mapping.epic) display += `Epic: ${JSON.stringify(mapping.epic)}\n`;
if (mapping.type) display += `Type: ${JSON.stringify(mapping.type)}\n`;
if (mapping.color) display += `Color: ${JSON.stringify(mapping.color)}\n`;
fieldMappingDisplay.textContent = display;
}
},
showTemplateFields() {
if (!this.template) return;
const debugInfo = document.getElementById("debugInfo");
const templateFieldsInfo = document.getElementById("templateFieldsInfo");
const templateFieldsDisplay = document.getElementById("templateFieldsDisplay");
if (debugInfo && templateFieldsInfo && templateFieldsDisplay) {
debugInfo.style.display = "block";
templateFieldsInfo.style.display = "block";
// Extract placeholders from template
const placeholders = new Set();
const placeholderRegex = /\{\{([A-Z_]+)\}\}/g;
let match;
while ((match = placeholderRegex.exec(this.template)) !== null) {
placeholders.add(match[1]);
}
let display = "Required Template Placeholders:\n";
display += "━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
// Group by category
const monthFields = Array.from(placeholders).filter(p => p.includes('MONTH'));
const laneFields = Array.from(placeholders).filter(p => p.includes('LANE'));
const taskFields = Array.from(placeholders).filter(p => p.includes('TASK') || p.includes('TEXT'));
const otherFields = Array.from(placeholders).filter(p =>
!monthFields.includes(p) && !laneFields.includes(p) && !taskFields.includes(p)
);
if (monthFields.length > 0) {
display += "\nMonth Fields:\n";
monthFields.forEach(f => display += `${f}\n`);
}
if (laneFields.length > 0) {
display += "\nLane Fields:\n";
laneFields.forEach(f => display += `${f}\n`);
}
if (taskFields.length > 0) {
display += "\nTask Fields:\n";
taskFields.forEach(f => display += `${f}\n`);
}
if (otherFields.length > 0) {
display += "\nOther Fields:\n";
otherFields.forEach(f => display += `${f}\n`);
}
templateFieldsDisplay.textContent = display;
}
},
showCSVPreview(csvText, parsedData) {
const debugInfo = document.getElementById("debugInfo");
const csvDataInfo = document.getElementById("csvDataInfo");
const csvDataDisplay = document.getElementById("csvDataDisplay");
if (debugInfo && csvDataInfo && csvDataDisplay) {
debugInfo.style.display = "block";
csvDataInfo.style.display = "block";
const lines = csvText.trim().split('\n');
const headers = lines[0] ? lines[0].split(',') : [];
const firstDataLine = lines[1] ? lines[1].split(',') : [];
let display = "CSV Structure Preview:\n";
display += "━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
display += `Headers: ${headers.join(', ')}\n\n`;
if (firstDataLine.length > 0) {
display += "First Data Row:\n";
headers.forEach((header, i) => {
display += ` ${header}: "${firstDataLine[i] || ''}"\n`;
});
}
if (parsedData) {
display += `\nParsed Rows: ${parsedData.length}\n`;
const validCount = parsedData.filter(r => {
const mapping = this.config?.fieldMapping || {};
const titleField = mapping.title;
const dueField = Array.isArray(mapping.due) ? mapping.due.find(f => r[f]) : mapping.due;
return r[titleField] && r[dueField];
}).length;
display += `Valid Items: ${validCount}\n`;
if (validCount === 0 && parsedData.length > 0) {
display += "\n⚠ WARNING: No valid items found!\n";
display += "Check that:\n";
display += " • CSV headers match field mappings\n";
display += " • Title and Due fields have values\n";
display += " • Date format is parseable (e.g., YYYY-MM-DD)\n";
}
}
csvDataDisplay.textContent = display;
}
2025-11-18 21:36:59 +01:00
}
};
// --------- SVG Viewer with Zoom functionality ---------
window.svgViewer = {
currentZoom: 1,
minZoom: 0.25,
maxZoom: 3,
zoomStep: 0.25,
initializeZoom() {
const viewer = document.getElementById("viewer");
const zoomControls = document.getElementById("zoomControls");
const zoomIn = document.getElementById("zoomIn");
const zoomOut = document.getElementById("zoomOut");
const zoomReset = document.getElementById("zoomReset");
if (!viewer || !zoomControls || !zoomIn || !zoomOut || !zoomReset) {
console.warn("Zoom controls not found in DOM");
return;
}
// Show zoom controls when SVG is present
this.updateZoomControls();
// Zoom in
zoomIn.addEventListener("click", () => {
this.zoomIn();
});
// Zoom out
zoomOut.addEventListener("click", () => {
this.zoomOut();
});
// Reset zoom
zoomReset.addEventListener("click", () => {
this.resetZoom();
});
// Mouse wheel zoom (with Ctrl key)
viewer.addEventListener("wheel", (e) => {
if (e.ctrlKey || e.metaKey) {
e.preventDefault();
if (e.deltaY < 0) {
this.zoomIn();
} else {
this.zoomOut();
}
}
});
console.log("SVG zoom functionality initialized");
},
showZoomControls() {
const zoomControls = document.getElementById("zoomControls");
if (zoomControls) {
zoomControls.style.display = "block";
}
},
hideZoomControls() {
const zoomControls = document.getElementById("zoomControls");
if (zoomControls) {
zoomControls.style.display = "none";
}
},
zoomIn() {
if (this.currentZoom < this.maxZoom) {
this.currentZoom = Math.min(this.maxZoom, this.currentZoom + this.zoomStep);
this.applyZoom();
}
},
zoomOut() {
if (this.currentZoom > this.minZoom) {
this.currentZoom = Math.max(this.minZoom, this.currentZoom - this.zoomStep);
this.applyZoom();
}
},
resetZoom() {
this.currentZoom = 1;
this.applyZoom();
},
applyZoom() {
const viewer = document.getElementById("viewer");
const container = document.getElementById("viewerContainer");
if (viewer && container) {
viewer.style.transform = `scale(${this.currentZoom})`;
// Adjust container overflow behavior based on zoom level
if (this.currentZoom !== 1) {
viewer.classList.add("zoomed");
container.style.overflow = "auto";
} else {
viewer.classList.remove("zoomed");
container.style.overflow = "hidden";
}
this.updateZoomControls();
}
},
updateZoomControls() {
const zoomIn = document.getElementById("zoomIn");
const zoomOut = document.getElementById("zoomOut");
const zoomReset = document.getElementById("zoomReset");
if (zoomIn && zoomOut && zoomReset) {
// Update button states
zoomIn.disabled = this.currentZoom >= this.maxZoom;
zoomOut.disabled = this.currentZoom <= this.minZoom;
// Update zoom percentage display
const percentage = Math.round(this.currentZoom * 100);
zoomReset.textContent = `${percentage}%`;
// Show/hide controls based on whether SVG is present
const hasSvg = document.querySelector("#viewer svg") !== null;
if (hasSvg) {
this.showZoomControls();
} else {
this.hideZoomControls();
}
}
}
};
2025-11-18 21:36:59 +01:00
// --------- UI event handlers ---------
window.setupEventHandlers = function() {
// Handler for loading entire project folder
const folderInput = document.getElementById("folderInput");
if (folderInput) {
folderInput.addEventListener("change", async (ev) => {
const files = Array.from(ev.target.files);
if (!files.length) return;
console.log("Folder selected with", files.length, "files");
try {
// Find project.json in the uploaded files
const projectFile = files.find(f => f.name === 'project.json');
if (!projectFile) {
alert('No project.json found in selected folder. Please select a folder containing a project.json file.');
return;
}
// Parse project.json
const projectText = await projectFile.text();
const cfg = JSON.parse(projectText);
console.log("Loaded project configuration:", cfg);
// Clear projectBasePath since we're loading from uploaded files
window.timelineEngine.projectBasePath = '';
// Update project status
window.timelineEngine.updateFileStatus('project', projectFile.name, 'loaded');
feat: add inline file editing with modification tracking and save functionality Add comprehensive inline editing capabilities for all project files with visual modification tracking and batch save functionality. Features: - Edit buttons next to each file load button (Project, SVG, CSS, CSV) - Modal editor with syntax validation for JSON files - Real-time preview updates after applying changes - Visual "MODIFIED" badges on edited files - "Save Changes" button to download all modified files - Keyboard shortcuts (Escape to close editor) Implementation: - file-editor.js: New module handling all editor functionality - Editor modal with textarea for content editing - Modification tracking using Set data structure - File-specific validation (JSON syntax checking) - Batch download of all modified files - Visual badge updates for modified state - index.html: UI updates - Edit buttons added to all file items - Modal HTML structure for editor - Save Changes button in controls area - CSS styling for editor modal and modified badges - engine.js: Integration and data storage - Store CSV and CSS content when loaded (for editing) - Enable edit buttons when files are successfully loaded - Works with all loading methods (folder picker, individual files, auto-load) - CSS now loaded via fetch to store content (changed from link href) - Makefile: Include file-editor.js in distribution build User workflow: 1. Load project files (folder picker or individual files) 2. Click "✏️ Edit" button next to any file 3. Make changes in modal editor 4. Click "Apply Changes" to update and see immediate preview 5. Modified files show orange "MODIFIED" badge 6. Click "💾 Save Changes" to download all modified files at once Technical details: - Edit buttons start disabled, enabled when file loads - JSON validation prevents saving invalid configurations - Changes apply immediately to in-memory data - Timeline regenerates automatically after edits - Modified state persists until files are saved - Optional clearing of modified state after download Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 17:15:36 +01:00
// Enable project edit button
if (window.fileEditor) {
window.fileEditor.enableEditButton('project');
}
// Load referenced files from the folder
const errors = [];
// Load stylesheet
if (cfg.stylesheet) {
const cssFile = files.find(f => f.name === cfg.stylesheet || f.webkitRelativePath.endsWith(cfg.stylesheet));
if (cssFile) {
const cssText = await cssFile.text();
feat: add inline file editing with modification tracking and save functionality Add comprehensive inline editing capabilities for all project files with visual modification tracking and batch save functionality. Features: - Edit buttons next to each file load button (Project, SVG, CSS, CSV) - Modal editor with syntax validation for JSON files - Real-time preview updates after applying changes - Visual "MODIFIED" badges on edited files - "Save Changes" button to download all modified files - Keyboard shortcuts (Escape to close editor) Implementation: - file-editor.js: New module handling all editor functionality - Editor modal with textarea for content editing - Modification tracking using Set data structure - File-specific validation (JSON syntax checking) - Batch download of all modified files - Visual badge updates for modified state - index.html: UI updates - Edit buttons added to all file items - Modal HTML structure for editor - Save Changes button in controls area - CSS styling for editor modal and modified badges - engine.js: Integration and data storage - Store CSV and CSS content when loaded (for editing) - Enable edit buttons when files are successfully loaded - Works with all loading methods (folder picker, individual files, auto-load) - CSS now loaded via fetch to store content (changed from link href) - Makefile: Include file-editor.js in distribution build User workflow: 1. Load project files (folder picker or individual files) 2. Click "✏️ Edit" button next to any file 3. Make changes in modal editor 4. Click "Apply Changes" to update and see immediate preview 5. Modified files show orange "MODIFIED" badge 6. Click "💾 Save Changes" to download all modified files at once Technical details: - Edit buttons start disabled, enabled when file loads - JSON validation prevents saving invalid configurations - Changes apply immediately to in-memory data - Timeline regenerates automatically after edits - Modified state persists until files are saved - Optional clearing of modified state after download Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 17:15:36 +01:00
window.timelineEngine.cssData = cssText; // Store for editing
window.timelineEngine.cssOverride = true;
const blob = new Blob([cssText], { type: "text/css" });
document.getElementById("dynamicCss").href = URL.createObjectURL(blob);
window.timelineEngine.updateFileStatus('css', cssFile.name, 'loaded');
feat: add inline file editing with modification tracking and save functionality Add comprehensive inline editing capabilities for all project files with visual modification tracking and batch save functionality. Features: - Edit buttons next to each file load button (Project, SVG, CSS, CSV) - Modal editor with syntax validation for JSON files - Real-time preview updates after applying changes - Visual "MODIFIED" badges on edited files - "Save Changes" button to download all modified files - Keyboard shortcuts (Escape to close editor) Implementation: - file-editor.js: New module handling all editor functionality - Editor modal with textarea for content editing - Modification tracking using Set data structure - File-specific validation (JSON syntax checking) - Batch download of all modified files - Visual badge updates for modified state - index.html: UI updates - Edit buttons added to all file items - Modal HTML structure for editor - Save Changes button in controls area - CSS styling for editor modal and modified badges - engine.js: Integration and data storage - Store CSV and CSS content when loaded (for editing) - Enable edit buttons when files are successfully loaded - Works with all loading methods (folder picker, individual files, auto-load) - CSS now loaded via fetch to store content (changed from link href) - Makefile: Include file-editor.js in distribution build User workflow: 1. Load project files (folder picker or individual files) 2. Click "✏️ Edit" button next to any file 3. Make changes in modal editor 4. Click "Apply Changes" to update and see immediate preview 5. Modified files show orange "MODIFIED" badge 6. Click "💾 Save Changes" to download all modified files at once Technical details: - Edit buttons start disabled, enabled when file loads - JSON validation prevents saving invalid configurations - Changes apply immediately to in-memory data - Timeline regenerates automatically after edits - Modified state persists until files are saved - Optional clearing of modified state after download Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 17:15:36 +01:00
// Enable CSS edit button
if (window.fileEditor) {
window.fileEditor.enableEditButton('css');
}
console.log("Loaded stylesheet:", cssFile.name);
} else {
errors.push(`Stylesheet: ${cfg.stylesheet}`);
window.timelineEngine.updateFileStatus('css', cfg.stylesheet, 'error');
}
}
// Load SVG template
if (cfg.svgTemplate) {
const svgFile = files.find(f => f.name === cfg.svgTemplate || f.webkitRelativePath.endsWith(cfg.svgTemplate));
if (svgFile) {
window.timelineEngine.template = await svgFile.text();
window.timelineEngine.updateFileStatus('svg', svgFile.name, 'loaded');
window.timelineEngine.showTemplateFields();
feat: add inline file editing with modification tracking and save functionality Add comprehensive inline editing capabilities for all project files with visual modification tracking and batch save functionality. Features: - Edit buttons next to each file load button (Project, SVG, CSS, CSV) - Modal editor with syntax validation for JSON files - Real-time preview updates after applying changes - Visual "MODIFIED" badges on edited files - "Save Changes" button to download all modified files - Keyboard shortcuts (Escape to close editor) Implementation: - file-editor.js: New module handling all editor functionality - Editor modal with textarea for content editing - Modification tracking using Set data structure - File-specific validation (JSON syntax checking) - Batch download of all modified files - Visual badge updates for modified state - index.html: UI updates - Edit buttons added to all file items - Modal HTML structure for editor - Save Changes button in controls area - CSS styling for editor modal and modified badges - engine.js: Integration and data storage - Store CSV and CSS content when loaded (for editing) - Enable edit buttons when files are successfully loaded - Works with all loading methods (folder picker, individual files, auto-load) - CSS now loaded via fetch to store content (changed from link href) - Makefile: Include file-editor.js in distribution build User workflow: 1. Load project files (folder picker or individual files) 2. Click "✏️ Edit" button next to any file 3. Make changes in modal editor 4. Click "Apply Changes" to update and see immediate preview 5. Modified files show orange "MODIFIED" badge 6. Click "💾 Save Changes" to download all modified files at once Technical details: - Edit buttons start disabled, enabled when file loads - JSON validation prevents saving invalid configurations - Changes apply immediately to in-memory data - Timeline regenerates automatically after edits - Modified state persists until files are saved - Optional clearing of modified state after download Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 17:15:36 +01:00
// Enable SVG edit button
if (window.fileEditor) {
window.fileEditor.enableEditButton('svg');
}
console.log("Loaded SVG template:", svgFile.name);
} else {
errors.push(`SVG template: ${cfg.svgTemplate}`);
window.timelineEngine.updateFileStatus('svg', cfg.svgTemplate, 'error');
}
}
// Load CSV data
if (cfg.dataSource) {
const csvFile = files.find(f => f.name === cfg.dataSource || f.webkitRelativePath.endsWith(cfg.dataSource));
if (csvFile) {
const csvText = await csvFile.text();
window.timelineEngine.csvOverride = true;
window.timelineEngine.updateFileStatus('csv', csvFile.name, 'loaded');
feat: add inline file editing with modification tracking and save functionality Add comprehensive inline editing capabilities for all project files with visual modification tracking and batch save functionality. Features: - Edit buttons next to each file load button (Project, SVG, CSS, CSV) - Modal editor with syntax validation for JSON files - Real-time preview updates after applying changes - Visual "MODIFIED" badges on edited files - "Save Changes" button to download all modified files - Keyboard shortcuts (Escape to close editor) Implementation: - file-editor.js: New module handling all editor functionality - Editor modal with textarea for content editing - Modification tracking using Set data structure - File-specific validation (JSON syntax checking) - Batch download of all modified files - Visual badge updates for modified state - index.html: UI updates - Edit buttons added to all file items - Modal HTML structure for editor - Save Changes button in controls area - CSS styling for editor modal and modified badges - engine.js: Integration and data storage - Store CSV and CSS content when loaded (for editing) - Enable edit buttons when files are successfully loaded - Works with all loading methods (folder picker, individual files, auto-load) - CSS now loaded via fetch to store content (changed from link href) - Makefile: Include file-editor.js in distribution build User workflow: 1. Load project files (folder picker or individual files) 2. Click "✏️ Edit" button next to any file 3. Make changes in modal editor 4. Click "Apply Changes" to update and see immediate preview 5. Modified files show orange "MODIFIED" badge 6. Click "💾 Save Changes" to download all modified files at once Technical details: - Edit buttons start disabled, enabled when file loads - JSON validation prevents saving invalid configurations - Changes apply immediately to in-memory data - Timeline regenerates automatically after edits - Modified state persists until files are saved - Optional clearing of modified state after download Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 17:15:36 +01:00
// Enable CSV edit button
if (window.fileEditor) {
window.fileEditor.enableEditButton('csv');
}
console.log("Loaded CSV data:", csvFile.name);
// Set config and process CSV
window.timelineEngine.config = cfg;
window.timelineEngine.processCsv(csvText);
} else {
errors.push(`CSV data: ${cfg.dataSource}`);
window.timelineEngine.updateFileStatus('csv', cfg.dataSource, 'error');
}
}
// Update project name and description
const name = cfg.name || "Timeline";
document.getElementById("projectName").textContent = name;
document.getElementById("projectSubtitle").textContent = cfg.description || "Project loaded from folder.";
// Show field mappings
window.timelineEngine.showFieldMappings();
// Show any errors
if (errors.length > 0) {
setTimeout(() => {
alert(`⚠️ Some files could not be loaded:\n\n${errors.join('\n')}\n\nMake sure all referenced files are in the selected folder.`);
}, 500);
} else {
console.log("✅ All project files loaded successfully from folder");
}
} catch (error) {
console.error("Error loading project folder:", error);
alert(`Error loading project: ${error.message}`);
}
});
}
// Individual file inputs removed - use folder picker instead
const downloadSvg = document.getElementById("downloadSvg");
if (downloadSvg) {
downloadSvg.addEventListener("click", () => {
const svg = document.querySelector("#viewer svg");
if (!svg) return;
// Always external view for export: IDs ausblenden
svg.querySelectorAll(".item-id").forEach(el => el.style.display = "none");
const now = new Date();
const ts = String(now.getFullYear()).slice(2)
+ String(now.getMonth() + 1).padStart(2, "0")
+ String(now.getDate()).padStart(2, "0")
+ "T"
+ String(now.getHours()).padStart(2, "0")
+ String(now.getMinutes()).padStart(2, "0");
const blob = new Blob([svg.outerHTML], { type: "image/svg+xml" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `${ts}-timeline.svg`;
a.click();
URL.revokeObjectURL(url);
});
}
const toggleView = document.getElementById("toggleView");
if (toggleView) {
toggleView.addEventListener("click", () => {
const body = document.body;
const isInternal = body.classList.contains("internal-mode");
if (isInternal) {
body.classList.remove("internal-mode");
body.classList.add("external-mode");
toggleView.textContent = "Switch to Internal View";
// Hide IDs in external mode
document.querySelectorAll(".item-id").forEach(el => el.style.display = "none");
} else {
body.classList.remove("external-mode");
body.classList.add("internal-mode");
toggleView.textContent = "Switch to External View";
// Show IDs in internal mode
document.querySelectorAll(".item-id").forEach(el => el.style.display = "inline");
}
});
}
}
2025-11-18 21:36:59 +01:00