diff --git a/markitect/static/editor.js b/markitect/static/editor.js index 1876f97c..21573b3e 100644 --- a/markitect/static/editor.js +++ b/markitect/static/editor.js @@ -2098,7 +2098,28 @@ class DOMRenderer { }); const resetBtn = this.createButton('↺ Reset', 'ui-edit-reset', (e) => { - // Reset both section and staging state + // Reset section to original content (like reset all does) + this.sectionManager.resetSection(sectionId); + + // Get the reset section to update staging state with original content + const resetSection = this.sectionManager.sections.get(sectionId); + if (resetSection) { + // Update DOM immediately to show reset content + this.updateSectionContent(sectionId, resetSection.currentMarkdown); + + // Parse original image info from reset content + const originalImageMatch = resetSection.currentMarkdown.match(/!\[(.*?)\]\((.*?)\)/); + if (originalImageMatch) { + const [, originalAltText, originalImageSrc] = originalImageMatch; + + // Update staging state to reflect original content + stagingState.originalMarkdown = resetSection.currentMarkdown; + stagingState.currentAltText = originalAltText; + stagingState.currentImageSrc = originalImageSrc; + } + } + + // Clear any staged changes stagingState.stagedImageSrc = null; stagingState.stagedAltText = null; stagingState.hasChanges = false; diff --git a/test_reset_to_original.js b/test_reset_to_original.js new file mode 100644 index 00000000..0ffd2438 --- /dev/null +++ b/test_reset_to_original.js @@ -0,0 +1,226 @@ +#!/usr/bin/env node + +/** + * Test Reset to Original Functionality + * + * Tests that the reset button resets to original content like reset all does + */ + +const { TestRunner } = require('./test_runner.js'); +const runner = new TestRunner(); + +runner.describe('Reset to Original Tests', () => { + + runner.it('should reset section to original content like reset all', async () => { + // Load editor + delete require.cache[require.resolve('/home/worsch/markitect_project/markitect/static/editor.js')]; + require('/home/worsch/markitect_project/markitect/static/editor.js'); + + if (global.DOMRenderer && global.SectionManager) { + const container = document.createElement('div'); + container.innerHTML = '
'; + document.body.appendChild(container); + + const manager = new global.SectionManager(); + const renderer = new global.DOMRenderer(manager, container); + + // Create section with original image + const originalMarkdown = ''; + const sections = manager.createSectionsFromMarkdown(originalMarkdown); + const imageSection = sections[0]; + + // Start editing and make changes to the section + manager.startEditing(imageSection.id); + const modifiedMarkdown = ''; + manager.updateContent(imageSection.id, modifiedMarkdown); + manager.acceptChanges(imageSection.id); + + // Verify section now has modified content + runner.expect(imageSection.currentMarkdown).toBe(modifiedMarkdown); + runner.expect(imageSection.currentMarkdown.includes('Modified Image')).toBeTruthy(); + runner.expect(imageSection.currentMarkdown.includes('Original Image')).toBeFalsy(); + + // Render the section and set up image editor + renderer.renderAllSections(sections); + + const testElement = document.createElement('div'); + testElement.setAttribute('data-section-id', imageSection.id); + renderer.findSectionElement = () => testElement; + + let updatedContent = null; + renderer.updateSectionContent = (sectionId, content) => { + updatedContent = content; + }; + + // Show image editor + renderer.showImageEditor(imageSection.id, imageSection); + + // Click reset button + const resetButton = testElement.querySelector('.ui-edit-reset'); + runner.expect(resetButton).toBeTruthy(); + + // Simulate reset button click + resetButton.click(); + + // Verify section was reset to original content + runner.expect(imageSection.currentMarkdown).toBe(originalMarkdown); + runner.expect(imageSection.currentMarkdown.includes('Original Image')).toBeTruthy(); + runner.expect(imageSection.currentMarkdown.includes('Modified Image')).toBeFalsy(); + + // Verify DOM was updated with original content + runner.expect(updatedContent).toBe(originalMarkdown); + + // Verify alt text input shows original value + const altTextInput = testElement.querySelector('input[type="text"]'); + runner.expect(altTextInput.value).toBe('Original Image'); + + // Cleanup + document.body.removeChild(container); + } + }); + + runner.it('should reset section state to original (not just clear staged changes)', async () => { + if (global.DOMRenderer && global.SectionManager) { + const container = document.createElement('div'); + container.innerHTML = ''; + document.body.appendChild(container); + + const manager = new global.SectionManager(); + const renderer = new global.DOMRenderer(manager, container); + + // Create section with original content + const originalMarkdown = ''; + const sections = manager.createSectionsFromMarkdown(originalMarkdown); + const imageSection = sections[0]; + + // Make and save changes to section (multiple modifications) + manager.startEditing(imageSection.id); + manager.updateContent(imageSection.id, ''); + manager.acceptChanges(imageSection.id); + + manager.startEditing(imageSection.id); + manager.updateContent(imageSection.id, ''); + manager.acceptChanges(imageSection.id); + + // Verify section has been modified multiple times + runner.expect(imageSection.currentMarkdown.includes('Second Change')).toBeTruthy(); + runner.expect(imageSection.hasChanges()).toBeTruthy(); // Should have changes from original + + // Show image editor + renderer.renderAllSections(sections); + const testElement = document.createElement('div'); + testElement.setAttribute('data-section-id', imageSection.id); + renderer.findSectionElement = () => testElement; + + renderer.showImageEditor(imageSection.id, imageSection); + + // Click reset button + const resetButton = testElement.querySelector('.ui-edit-reset'); + resetButton.click(); + + // Verify complete reset to original (not just current) + runner.expect(imageSection.currentMarkdown).toBe(originalMarkdown); + runner.expect(imageSection.hasChanges()).toBeFalsy(); // Should show no changes from original + runner.expect(imageSection.state).toBe('original'); // Should be in original state + + // Cleanup + document.body.removeChild(container); + } + }); + + runner.it('should reset staging state to reflect original content after section reset', async () => { + if (global.DOMRenderer && global.SectionManager) { + const container = document.createElement('div'); + container.innerHTML = ''; + document.body.appendChild(container); + + const manager = new global.SectionManager(); + const renderer = new global.DOMRenderer(manager, container); + + // Create section with original content + const originalMarkdown = ''; + const sections = manager.createSectionsFromMarkdown(originalMarkdown); + const imageSection = sections[0]; + + // Modify the section content + manager.startEditing(imageSection.id); + manager.updateContent(imageSection.id, ''); + manager.acceptChanges(imageSection.id); + + // Show image editor with the modified content + renderer.renderAllSections(sections); + const testElement = document.createElement('div'); + testElement.setAttribute('data-section-id', imageSection.id); + renderer.findSectionElement = () => testElement; + + renderer.showImageEditor(imageSection.id, imageSection); + + // Make some staged changes in the editor + const altTextInput = testElement.querySelector('input[type="text"]'); + altTextInput.value = 'Staged Alt Text'; + const inputEvent = new Event('input', { bubbles: true }); + altTextInput.dispatchEvent(inputEvent); + + // Verify we have staged changes + // (We can't directly access stagingState, but we can see the alt text input changed) + runner.expect(altTextInput.value).toBe('Staged Alt Text'); + + // Click reset button + const resetButton = testElement.querySelector('.ui-edit-reset'); + resetButton.click(); + + // Verify alt text input was reset to original (not just to "changed" content) + runner.expect(altTextInput.value).toBe('Original Title'); + + // Verify section content is original + runner.expect(imageSection.currentMarkdown).toBe(originalMarkdown); + + // Cleanup + document.body.removeChild(container); + } + }); + + runner.it('should work consistently with resetSection method behavior', async () => { + if (global.DOMRenderer && global.SectionManager) { + const manager = new global.SectionManager(); + + // Create section + const originalMarkdown = ''; + const sections = manager.createSectionsFromMarkdown(originalMarkdown); + const section = sections[0]; + + // Modify section + manager.startEditing(section.id); + manager.updateContent(section.id, ''); + manager.acceptChanges(section.id); + + // Test direct resetSection call + manager.resetSection(section.id); + + // Verify resetSection behavior + runner.expect(section.currentMarkdown).toBe(originalMarkdown); + runner.expect(section.state).toBe('original'); + runner.expect(section.hasChanges()).toBeFalsy(); + + // This is the behavior our reset button should match + runner.expect(true).toBeTruthy(); // Test passes if we reach here + } + }); +}); + +// Run the tests +if (require.main === module) { + console.log('🔄 Running Reset to Original Tests'); + runner.run().then(() => { + const results = runner.results; + const failed = results.filter(r => r.status === 'FAIL').length; + + if (failed > 0) { + console.log(`❌ ${failed} test(s) failed - reset functionality needs attention`); + } else { + console.log('✅ All reset to original tests passed!'); + } + }); +} + +module.exports = runner; \ No newline at end of file