From 4f41b22335510d739d58ce1036ece59a6fc58e88 Mon Sep 17 00:00:00 2001 From: tegwick Date: Sun, 2 Nov 2025 17:07:42 +0100 Subject: [PATCH] fix: reset button now resets to original content like reset all function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed reset button behavior to match reset all functionality: ## 🔄 Reset Button Enhancement - **Before**: Only cleared staged changes, kept current modified content - **After**: Resets section to original content like "Reset All" function does ## 🎯 Consistent Behavior - **Reset Button**: Now calls `sectionManager.resetSection()` for complete reset - **Reset All**: Already used `resetSection()` for each section - **Result**: Both reset functions now have identical behavior ## 🚀 Implementation Details - **Section Reset**: Calls `resetSection()` to restore original markdown content - **DOM Update**: Immediately updates display with `updateSectionContent()` - **Staging State**: Updates staging state to reflect original content values - **Preview Update**: Resets image preview and alt text input to original values - **Change Indicator**: Clears "unsaved changes" warning ## 📝 Reset Button Workflow (New) 1. **Reset Section**: Restore section to original content and state 2. **Update Display**: Show original content immediately in document 3. **Parse Original**: Extract original image source and alt text 4. **Update Staging**: Set staging state to reflect original values 5. **Clear Changes**: Remove any staged modifications 6. **Update UI**: Reset preview and form inputs to original values ## ✅ User Experience - **Consistent**: Reset button behavior now matches user expectations - **Complete**: Resets everything back to original (not just current changes) - **Immediate**: Users see original content restored right away - **Reliable**: Works the same way as "Reset All" function Added comprehensive test suite with 4 tests covering complete reset functionality. Reset button now provides true "revert to original" behavior. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- markitect/static/editor.js | 23 +++- test_reset_to_original.js | 226 +++++++++++++++++++++++++++++++++++++ 2 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 test_reset_to_original.js 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 = '![Original Image](https://original.com/image.jpg)'; + const sections = manager.createSectionsFromMarkdown(originalMarkdown); + const imageSection = sections[0]; + + // Start editing and make changes to the section + manager.startEditing(imageSection.id); + const modifiedMarkdown = '![Modified Image](https://modified.com/image.jpg)'; + 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 = '![Original Alt](https://original.com/pic.png)'; + 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, '![First Change](https://first.com/pic.png)'); + manager.acceptChanges(imageSection.id); + + manager.startEditing(imageSection.id); + manager.updateContent(imageSection.id, '![Second Change](https://second.com/pic.png)'); + 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 = '![Original Title](https://example.com/original.jpg)'; + const sections = manager.createSectionsFromMarkdown(originalMarkdown); + const imageSection = sections[0]; + + // Modify the section content + manager.startEditing(imageSection.id); + manager.updateContent(imageSection.id, '![Changed Title](https://example.com/changed.jpg)'); + 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 = '![Test](https://test.com/image.png)'; + const sections = manager.createSectionsFromMarkdown(originalMarkdown); + const section = sections[0]; + + // Modify section + manager.startEditing(section.id); + manager.updateContent(section.id, '![Modified](https://modified.com/image.png)'); + 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