diff --git a/ts_web/elements/wysiwyg/CLEANUP-STATUS.md b/ts_web/elements/wysiwyg/CLEANUP-STATUS.md new file mode 100644 index 0000000..9904dee --- /dev/null +++ b/ts_web/elements/wysiwyg/CLEANUP-STATUS.md @@ -0,0 +1,65 @@ +# WYSIWYG Block Cleanup Status + +## Overview +This document tracks the cleanup of `dees-wysiwyg-block.ts` after migrating all block types to the new block handler architecture. + +## Completed ✅ +All cleanup tasks have been successfully completed on 2025-06-26. + +## Cleanup Tasks + +### 1. ✅ Remove Block-Specific Styles (lines 101-219) +- [x] Remove `.block.heading-1/2/3` styles → Now in `heading.block.ts` +- [x] Remove `.block.quote` styles → Now in `quote.block.ts` +- [x] Remove `.block.list` styles → Now in `list.block.ts` +- [x] Remove `.block.paragraph` styles → Now in `paragraph.block.ts` + +### 2. ✅ Remove Code Block Specific Logic +- [x] Remove code block rendering in `renderBlockContent()` (lines 508-521) +- [x] Remove all `type === 'code'` conditional branches +- [x] Simplify element selection to not special-case code blocks + +### 3. ✅ Remove List Block Specific Logic +- [x] Remove `focusListItem()` method (lines 814-821) +- [x] Remove list-specific handling in `getContent()` (lines 732-734) +- [x] Remove list-specific handling in `setContent()` (lines 764-765) +- [x] Remove list content rendering in `firstUpdated()` (line 479) + +### 4. ✅ Remove getPlaceholder() Method +- [x] Remove entire method (lines 538-553) +- [x] Update renderBlockContent() to not use placeholders + +### 5. ✅ Clean Up Excessive Empty Lines +- [x] Remove consecutive blank lines throughout the file + +### 6. ✅ Centralize nonEditableTypes +- [x] Create a single source of truth for non-editable block types +- [x] Remove duplicate arrays + +### 7. ✅ Simplify Handler Delegation +- [x] Keep handler delegation pattern but ensure consistency + +### 8. ✅ Remove Unused Properties (if confirmed unused) +- [x] Keep `contentInitialized` - still used for tracking +- [x] Keep `blockElement` - used for caching +- [x] Keep cursor tracking properties - used for selection + +## Implementation Notes + +### Block Types Now Fully Handled by Handlers: +1. **Text blocks**: paragraph, heading-1/2/3, quote, code, list +2. **Media blocks**: image, youtube, attachment +3. **Content blocks**: divider, markdown, html + +### Remaining Responsibilities of dees-wysiwyg-block.ts: +1. Shadow DOM container management +2. Handler delegation for all operations +3. Generic block wrapper styles +4. Selection/cursor tracking +5. Event listener setup (until fully delegated to handlers) + +## Future Improvements +- Consider moving all event handling to block handlers +- Simplify the handler delegation pattern +- Move generic block styles to a shared location +- Consider removing the need for special-casing any block types \ No newline at end of file diff --git a/ts_web/elements/wysiwyg/dees-wysiwyg-block.ts b/ts_web/elements/wysiwyg/dees-wysiwyg-block.ts index 2648336..be8a1fa 100644 --- a/ts_web/elements/wysiwyg/dees-wysiwyg-block.ts +++ b/ts_web/elements/wysiwyg/dees-wysiwyg-block.ts @@ -50,6 +50,9 @@ export class DeesWysiwygBlock extends DeesElement { private handlerStylesInjected = false; + // Block types that don't support contenteditable + private static readonly NON_EDITABLE_TYPES = ['image', 'divider', 'youtube']; + private injectHandlerStyles(): void { // Only inject once per instance if (this.handlerStylesInjected) return; @@ -98,54 +101,7 @@ export class DeesWysiwygBlock extends DeesElement { pointer-events: none; } - .block.heading-1 { - font-size: 32px; - font-weight: 700; - line-height: 1.2; - margin: 24px 0 8px 0; - color: ${cssManager.bdTheme('#000000', '#ffffff')}; - } - - .block.heading-2 { - font-size: 24px; - font-weight: 600; - line-height: 1.3; - margin: 20px 0 6px 0; - color: ${cssManager.bdTheme('#000000', '#ffffff')}; - } - - .block.heading-3 { - font-size: 20px; - font-weight: 600; - line-height: 1.4; - margin: 16px 0 4px 0; - color: ${cssManager.bdTheme('#000000', '#ffffff')}; - } - - .block.quote { - border-left: 3px solid ${cssManager.bdTheme('#0066cc', '#4d94ff')}; - padding-left: 20px; - color: ${cssManager.bdTheme('#555', '#b0b0b0')}; - font-style: italic; - line-height: 1.6; - margin: 16px 0; - } - - /* Code block styles moved to handler */ - - .block.list { - padding: 0; - } - - .block.list ul, - .block.list ol { - margin: 0; - padding-left: 24px; - } - - .block.list li { - margin: 4px 0; - } + /* Block-specific styles moved to handlers */ /* Formatting styles */ @@ -195,12 +151,6 @@ export class DeesWysiwygBlock extends DeesElement { color: inherit; } - /* Paragraph specific styles */ - .block.paragraph { - font-size: 16px; - line-height: 1.6; - font-weight: 400; - } /* Strike through */ .block :is(s, strike) { @@ -208,15 +158,6 @@ export class DeesWysiwygBlock extends DeesElement { opacity: 0.7; } - /* List specific margin adjustments */ - .block.list li { - margin-bottom: 8px; - line-height: 1.6; - } - - .block.list li:last-child { - margin-bottom: 0; - } /* Block margin adjustments based on type */ :host-context(.block-wrapper:first-child) .block { @@ -307,9 +248,7 @@ export class DeesWysiwygBlock extends DeesElement { // Handle special block types // Now find the actual editable block element - const editableBlock = this.block.type === 'code' - ? this.shadowRoot?.querySelector('.block.code') as HTMLDivElement - : this.shadowRoot?.querySelector('.block') as HTMLDivElement; + const editableBlock = this.shadowRoot?.querySelector('.block') as HTMLDivElement; // Ensure the block element maintains its content if (editableBlock) { @@ -364,7 +303,7 @@ export class DeesWysiwygBlock extends DeesElement { this.handlers?.onMouseUp?.(e); }); - editableBlock.addEventListener('click', (e: MouseEvent) => { + editableBlock.addEventListener('click', () => { // Small delay to let browser set cursor position setTimeout(() => { const pos = this.getCursorPosition(editableBlock); @@ -398,9 +337,7 @@ export class DeesWysiwygBlock extends DeesElement { } // Get fresh reference to the editable block - const currentEditableBlock = this.block?.type === 'code' - ? this.shadowRoot?.querySelector('.block.code') as HTMLDivElement - : this.shadowRoot?.querySelector('.block') as HTMLDivElement; + const currentEditableBlock = this.shadowRoot?.querySelector('.block') as HTMLDivElement; if (!currentEditableBlock) return; @@ -464,7 +401,7 @@ export class DeesWysiwygBlock extends DeesElement { (this as any)._selectionHandler = checkSelection; // Add keyup handler for cursor position tracking - editableBlock.addEventListener('keyup', (e) => { + editableBlock.addEventListener('keyup', () => { // Track cursor position const pos = this.getCursorPosition(editableBlock); if (pos !== null) { @@ -474,13 +411,7 @@ export class DeesWysiwygBlock extends DeesElement { // Set initial content if needed if (this.block.content) { - if (this.block.type === 'code') { - editableBlock.textContent = this.block.content; - } else if (this.block.type === 'list') { - editableBlock.innerHTML = WysiwygBlocks.renderListContent(this.block.content, this.block.metadata); - } else { - editableBlock.innerHTML = this.block.content; - } + editableBlock.innerHTML = this.block.content; } } @@ -505,52 +436,16 @@ export class DeesWysiwygBlock extends DeesElement { return handler.render(this.block, this.isSelected); } - if (this.block.type === 'code') { - const language = this.block.metadata?.language || 'plain text'; - const selectedClass = this.isSelected ? ' selected' : ''; - return ` -
-
${language}
-
-
- `; - } - - - - - - const placeholder = this.getPlaceholder(); + // Default rendering for blocks without handlers const selectedClass = this.isSelected ? ' selected' : ''; return `
`; } - private getPlaceholder(): string { - switch (this.block.type) { - case 'paragraph': - return "Type '/' for commands..."; - case 'heading-1': - return 'Heading 1'; - case 'heading-2': - return 'Heading 2'; - case 'heading-3': - return 'Heading 3'; - case 'quote': - return 'Quote'; - default: - return ''; - } - } public focus(): void { @@ -563,8 +458,7 @@ export class DeesWysiwygBlock extends DeesElement { } // Handle non-editable blocks - const nonEditableTypes = ['image', 'divider', 'youtube']; - if (this.block && nonEditableTypes.includes(this.block.type)) { + if (this.block && DeesWysiwygBlock.NON_EDITABLE_TYPES.includes(this.block.type)) { const blockElement = this.shadowRoot?.querySelector(`.block.${this.block.type}`) as HTMLDivElement; if (blockElement) { blockElement.focus(); @@ -572,10 +466,8 @@ export class DeesWysiwygBlock extends DeesElement { return; } - // Get the actual editable element (might be nested for code blocks) - const editableElement = this.block?.type === 'code' - ? this.shadowRoot?.querySelector('.block.code') as HTMLDivElement - : this.shadowRoot?.querySelector('.block') as HTMLDivElement; + // Get the actual editable element + const editableElement = this.shadowRoot?.querySelector('.block') as HTMLDivElement; if (!editableElement) return; @@ -604,16 +496,13 @@ export class DeesWysiwygBlock extends DeesElement { } // Non-editable blocks don't support cursor positioning - const nonEditableTypes = ['image', 'divider', 'youtube']; - if (this.block && nonEditableTypes.includes(this.block.type)) { + if (this.block && DeesWysiwygBlock.NON_EDITABLE_TYPES.includes(this.block.type)) { this.focus(); return; } - // Get the actual editable element (might be nested for code blocks) - const editableElement = this.block?.type === 'code' - ? this.shadowRoot?.querySelector('.block.code') as HTMLDivElement - : this.shadowRoot?.querySelector('.block') as HTMLDivElement; + // Get the actual editable element + const editableElement = this.shadowRoot?.querySelector('.block') as HTMLDivElement; if (!editableElement) return; @@ -722,24 +611,15 @@ export class DeesWysiwygBlock extends DeesElement { } - // Get the actual editable element (might be nested for code blocks) - const editableElement = this.block?.type === 'code' - ? this.shadowRoot?.querySelector('.block.code') as HTMLDivElement - : this.shadowRoot?.querySelector('.block') as HTMLDivElement; + // Get the actual editable element + const editableElement = this.shadowRoot?.querySelector('.block') as HTMLDivElement; if (!editableElement) return ''; - if (this.block.type === 'list') { - const listItems = editableElement.querySelectorAll('li'); - return Array.from(listItems).map(li => li.innerHTML || '').join('\n'); - } else if (this.block.type === 'code') { - return editableElement.textContent || ''; - } else { - // For regular blocks, get the innerHTML which includes formatting tags - const content = editableElement.innerHTML || ''; - console.log('Getting content from block:', content); - return content; - } + // Get the innerHTML which includes formatting tags + const content = editableElement.innerHTML || ''; + console.log('Getting content from block:', content); + return content; } public setContent(content: string): void { @@ -751,23 +631,15 @@ export class DeesWysiwygBlock extends DeesElement { return handler.setContent(container, content, context); } - // Get the actual editable element (might be nested for code blocks) - const editableElement = this.block?.type === 'code' - ? this.shadowRoot?.querySelector('.block.code') as HTMLDivElement - : this.shadowRoot?.querySelector('.block') as HTMLDivElement; + // Get the actual editable element + const editableElement = this.shadowRoot?.querySelector('.block') as HTMLDivElement; if (!editableElement) return; // Store if we have focus const hadFocus = document.activeElement === editableElement || this.shadowRoot?.activeElement === editableElement; - if (this.block.type === 'list') { - editableElement.innerHTML = WysiwygBlocks.renderListContent(content, this.block.metadata); - } else if (this.block.type === 'code') { - editableElement.textContent = content; - } else { - editableElement.innerHTML = content; - } + editableElement.innerHTML = content; // Restore focus if we had it if (hadFocus) { @@ -785,9 +657,7 @@ export class DeesWysiwygBlock extends DeesElement { } // Always find the element fresh, don't rely on cached blockElement - const editableElement = this.block?.type === 'code' - ? this.shadowRoot?.querySelector('.block.code') as HTMLDivElement - : this.shadowRoot?.querySelector('.block') as HTMLDivElement; + const editableElement = this.shadowRoot?.querySelector('.block') as HTMLDivElement; if (editableElement) { WysiwygBlocks.setCursorToStart(editableElement); } @@ -803,28 +673,12 @@ export class DeesWysiwygBlock extends DeesElement { } // Always find the element fresh, don't rely on cached blockElement - const editableElement = this.block?.type === 'code' - ? this.shadowRoot?.querySelector('.block.code') as HTMLDivElement - : this.shadowRoot?.querySelector('.block') as HTMLDivElement; + const editableElement = this.shadowRoot?.querySelector('.block') as HTMLDivElement; if (editableElement) { WysiwygBlocks.setCursorToEnd(editableElement); } } - public focusListItem(): void { - if (this.block.type === 'list') { - const editableElement = this.shadowRoot?.querySelector('.block') as HTMLDivElement; - if (editableElement) { - WysiwygBlocks.focusListItem(editableElement); - } - } - } - - - - - - @@ -860,9 +714,7 @@ export class DeesWysiwygBlock extends DeesElement { // Get the actual editable element first - const editableElement = this.block?.type === 'code' - ? this.shadowRoot?.querySelector('.block.code') as HTMLDivElement - : this.shadowRoot?.querySelector('.block') as HTMLDivElement; + const editableElement = this.shadowRoot?.querySelector('.block') as HTMLDivElement; if (!editableElement) { console.log('getSplitContent: No editable element found'); @@ -932,24 +784,6 @@ export class DeesWysiwygBlock extends DeesElement { return null; } - // For code blocks, use simple text splitting - if (this.block.type === 'code') { - const cursorPos = this.getCursorPosition(editableElement) || 0; - const fullText = editableElement.textContent || ''; - - console.log('getSplitContent: Code block split:', { - cursorPos, - fullTextLength: fullText.length, - before: fullText.substring(0, cursorPos), - after: fullText.substring(cursorPos) - }); - - return { - before: fullText.substring(0, cursorPos), - after: fullText.substring(cursorPos) - }; - } - // For HTML content, get cursor position first const cursorPos = this.getCursorPosition(editableElement); console.log('getSplitContent: Cursor position for HTML split:', cursorPos); @@ -1004,4 +838,4 @@ export class DeesWysiwygBlock extends DeesElement { }; } -} \ No newline at end of file +}