diff --git a/markitect/document_manager.py b/markitect/document_manager.py index 4dd5d795..c22031df 100644 --- a/markitect/document_manager.py +++ b/markitect/document_manager.py @@ -447,9 +447,12 @@ class DocumentManager: const header = document.createElement('div'); header.className = 'markitect-floating-header'; header.innerHTML = ` - - - Ready + + + Ready + + Saves as: filename-edited-YYYY-MM-DD-HH-MM-SS.md + `; document.body.insertBefore(header, document.body.firstChild); @@ -520,10 +523,88 @@ class DocumentManager: } save() { - document.getElementById('save-status').textContent = 'Saved!'; - setTimeout(() => { - document.getElementById('save-status').textContent = 'Ready'; - }, 2000); + try { + // Get the current markdown content from the editor + const markdownContent = this.getMarkdownContent(); + + // Create filename with timestamp suffix for backup convention + const now = new Date(); + const timestamp = now.toISOString().slice(0, 19).replace(/:/g, '-').replace('T', '-'); + const originalFilename = window.location.pathname.split('/').pop().replace('.html', '.md'); + const backupFilename = `${originalFilename.replace('.md', '')}-edited-${timestamp}.md`; + + // Create and download the file + const blob = new Blob([markdownContent], { type: 'text/markdown' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = backupFilename; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + + // Update status with filename convention info + const statusEl = document.getElementById('save-status'); + statusEl.textContent = `Downloaded: ${backupFilename}`; + statusEl.title = 'File saved with timestamp to avoid overwriting original'; + setTimeout(() => { + statusEl.textContent = 'Ready'; + statusEl.title = ''; + }, 5000); + + } catch (error) { + document.getElementById('save-status').textContent = 'Save failed!'; + console.error('Save error:', error); + setTimeout(() => { + document.getElementById('save-status').textContent = 'Ready'; + }, 3000); + } + } + + getMarkdownContent() { + // Reconstruct markdown content from the current state of sections + const content = document.getElementById('markdown-content'); + if (!content) { + return markdownContent; // fallback to original + } + + // Simple approach: get the text content and convert back to markdown + // This is a basic implementation - could be enhanced for better preservation + const sections = content.querySelectorAll('.markitect-section-editable'); + let reconstructed = ''; + + sections.forEach(section => { + const tagName = section.tagName.toLowerCase(); + const text = section.textContent.trim(); + + if (tagName.startsWith('h')) { + const level = parseInt(tagName.charAt(1)); + reconstructed += '#'.repeat(level) + ' ' + text + '\n\n'; + } else if (tagName === 'p') { + reconstructed += text + '\n\n'; + } else if (tagName === 'blockquote') { + reconstructed += '> ' + text + '\n\n'; + } else if (tagName === 'pre') { + reconstructed += '```\n' + text + '\n```\n\n'; + } else if (tagName === 'ul') { + const items = section.querySelectorAll('li'); + items.forEach(item => { + reconstructed += '- ' + item.textContent.trim() + '\n'; + }); + reconstructed += '\n'; + } else if (tagName === 'ol') { + const items = section.querySelectorAll('li'); + items.forEach((item, index) => { + reconstructed += `${index + 1}. ` + item.textContent.trim() + '\n'; + }); + reconstructed += '\n'; + } else { + reconstructed += text + '\n\n'; + } + }); + + return reconstructed.trim(); } togglePreview() {