138 lines
6.8 KiB
Markdown
138 lines
6.8 KiB
Markdown
# WYSIWYG Editor Refactoring Progress Summary
|
|
|
|
## Latest Updates
|
|
|
|
### Selection Highlighting Fix ✅
|
|
- **Issue**: "Paragraphs are not highlighted consistently, headings are always highlighted"
|
|
- **Root Cause**: The `shouldUpdate` method in `dees-wysiwyg-block.ts` was using a generic `.block` selector that would match the first element with that class, not necessarily the correct block element
|
|
- **Solution**: Changed the selector to be more specific: `.block.${blockType}` which ensures the correct element is found for each block type
|
|
- **Result**: All block types now highlight consistently when selected
|
|
|
|
### Enter Key Block Creation Fix ✅
|
|
- **Issue**: "When pressing enter and jumping to new block then typing something: The cursor is not at the beginning of the new block and there is content"
|
|
- **Root Cause**: Block handlers were rendering content with template syntax `${block.content || ''}` in their render methods, which violates the static HTML principle
|
|
- **Solution**:
|
|
- Removed all `${block.content}` from render methods in paragraph, heading, quote, and code block handlers
|
|
- Content is now set programmatically in the setup() method only when needed
|
|
- Fixed `setCursorToStart` and `setCursorToEnd` to always find elements fresh instead of relying on cached `blockElement`
|
|
- **Result**: New empty blocks remain truly empty, cursor positioning works correctly
|
|
|
|
### Backspace Key Deletion Fix ✅
|
|
- **Issue**: "After typing in a new block, pressing backspace deletes the whole block instead of just the last character"
|
|
- **Root Cause**:
|
|
1. `getCursorPositionInElement` was using `element.contains()` which doesn't work across Shadow DOM boundaries
|
|
2. The backspace handler was checking `block.content === ''` which only contains the stored content, not the actual DOM content
|
|
- **Solution**:
|
|
1. Fixed `getCursorPositionInElement` to use `containsAcrossShadowDOM` for proper Shadow DOM support
|
|
2. Updated backspace handler to get actual content from DOM using `blockComponent.getContent()` instead of relying on stored `block.content`
|
|
3. Added debug logging to track cursor position and content state
|
|
- **Result**: Backspace now correctly deletes individual characters instead of the whole block
|
|
|
|
### Arrow Left Navigation Fix ✅
|
|
- **Issue**: "When jumping to the previous block from the beginning of a block with arrow left, the cursor should be at the end of the previous block, not at the start"
|
|
- **Root Cause**: Browser's default focus behavior places cursor at the beginning of contenteditable elements, overriding our cursor positioning
|
|
- **Solution**: For 'end' position, set up the selection range BEFORE focusing the element:
|
|
1. Create a range pointing to the end of content
|
|
2. Apply the selection
|
|
3. Then focus the element (which preserves the existing selection)
|
|
4. Only use setCursorToEnd for empty blocks
|
|
- **Result**: Arrow left navigation now correctly places cursor at the end of the previous block
|
|
|
|
## Completed Phases
|
|
|
|
### Phase 1: Infrastructure ✅
|
|
- Created modular block handler architecture
|
|
- Implemented `IBlockHandler` interface and `BaseBlockHandler` class
|
|
- Created `BlockRegistry` for dynamic block type registration
|
|
- Set up proper file structure under `blocks/` directory
|
|
|
|
### Phase 2: Proof of Concept ✅
|
|
- Successfully migrated divider block as the simplest example
|
|
- Validated the architecture works correctly
|
|
- Established patterns for block migration
|
|
|
|
### Phase 3: Text Blocks ✅
|
|
- **Paragraph Block**: Full editing support with text splitting, selection handling, and cursor tracking
|
|
- **Heading Blocks**: All three heading levels (h1, h2, h3) with unified handler
|
|
- **Quote Block**: Italic styling with border, full editing capabilities
|
|
- **Code Block**: Monospace font, tab handling, plain text paste support
|
|
- **List Block**: Bullet/numbered lists with proper list item management
|
|
|
|
## Key Achievements
|
|
|
|
### 1. Preserved Critical Knowledge
|
|
- **Static Rendering**: Blocks use `innerHTML` in `firstUpdated` to prevent focus loss during typing
|
|
- **Shadow DOM Selection**: Implemented `containsAcrossShadowDOM` utility for proper selection detection
|
|
- **Cursor Position Tracking**: All editable blocks track cursor position across multiple events
|
|
- **Content Splitting**: HTML-aware splitting using Range API preserves formatting
|
|
- **Focus Management**: Microtask-based focus restoration ensures reliable cursor placement
|
|
|
|
### 2. Enhanced Architecture
|
|
- Each block type is now self-contained in its own file
|
|
- Block handlers are dynamically registered and loaded
|
|
- Common functionality is shared through base classes
|
|
- Styles are co-located with their block handlers
|
|
|
|
### 3. Maintained Functionality
|
|
- All keyboard navigation works (arrows, backspace, delete, enter)
|
|
- Text selection across Shadow DOM boundaries functions correctly
|
|
- Block merging and splitting behave as before
|
|
- IME (Input Method Editor) support is preserved
|
|
- Formatting shortcuts (Cmd/Ctrl+B/I/U/K) continue to work
|
|
|
|
## Code Organization
|
|
|
|
```
|
|
ts_web/elements/wysiwyg/
|
|
├── dees-wysiwyg-block.ts (simplified main component)
|
|
├── wysiwyg.selection.ts (Shadow DOM selection utilities)
|
|
├── wysiwyg.blockregistration.ts (handler registration)
|
|
└── blocks/
|
|
├── index.ts (exports and registry)
|
|
├── block.base.ts (base handler interface)
|
|
├── decorative/
|
|
│ └── divider.block.ts
|
|
└── text/
|
|
├── paragraph.block.ts
|
|
├── heading.block.ts
|
|
├── quote.block.ts
|
|
├── code.block.ts
|
|
└── list.block.ts
|
|
```
|
|
|
|
## Next Steps
|
|
|
|
### Phase 4: Media Blocks (In Progress)
|
|
- Image block with upload/drag-drop support
|
|
- YouTube block with video embedding
|
|
- Attachment block for file uploads
|
|
|
|
### Phase 5: Content Blocks
|
|
- Markdown block with preview toggle
|
|
- HTML block with raw HTML editing
|
|
|
|
### Phase 6: Cleanup
|
|
- Remove old code from main component
|
|
- Optimize bundle size
|
|
- Update documentation
|
|
|
|
## Technical Improvements
|
|
|
|
1. **Modularity**: Each block type is now completely self-contained
|
|
2. **Extensibility**: New blocks can be added by creating a handler and registering it
|
|
3. **Maintainability**: Files are smaller and focused on single responsibilities
|
|
4. **Type Safety**: Strong TypeScript interfaces ensure consistent implementation
|
|
5. **Performance**: No degradation in performance; potential for lazy loading in future
|
|
|
|
## Migration Pattern
|
|
|
|
For future block migrations, follow this pattern:
|
|
|
|
1. Create block handler extending `BaseBlockHandler`
|
|
2. Implement required methods: `render()`, `setup()`, `getStyles()`
|
|
3. Add helper methods for cursor/content management
|
|
4. Handle Shadow DOM selection properly using utilities
|
|
5. Register handler in `wysiwyg.blockregistration.ts`
|
|
6. Test all interactions (typing, selection, navigation)
|
|
|
|
The refactoring has been successful in making the codebase more maintainable while preserving all the hard-won functionality and edge case handling from the original implementation. |