import { type IBlock } from './wysiwyg.types.js'; import { WysiwygShortcuts } from './wysiwyg.shortcuts.js'; import { WysiwygBlocks } from './wysiwyg.blocks.js'; export class WysiwygBlockOperations { private component: any; // Will be typed properly when imported constructor(component: any) { this.component = component; } /** * Creates a new block with the specified parameters */ createBlock(type: IBlock['type'] = 'paragraph', content: string = '', metadata?: any): IBlock { return { id: WysiwygShortcuts.generateBlockId(), type, content, ...(metadata && { metadata }) }; } /** * Inserts a block after the specified block */ async insertBlockAfter(afterBlock: IBlock, newBlock: IBlock, focusNewBlock: boolean = true): Promise { const blocks = this.component.blocks; const blockIndex = blocks.findIndex((b: IBlock) => b.id === afterBlock.id); this.component.blocks = [ ...blocks.slice(0, blockIndex + 1), newBlock, ...blocks.slice(blockIndex + 1) ]; this.component.updateValue(); this.component.requestUpdate(); if (focusNewBlock && newBlock.type !== 'divider') { // Wait for the component to update await this.component.updateComplete; // Focus the new block await this.focusBlock(newBlock.id, 'start'); } } /** * Removes a block by its ID */ removeBlock(blockId: string): void { this.component.blocks = this.component.blocks.filter((b: IBlock) => b.id !== blockId); this.component.updateValue(); } /** * Finds a block by its ID */ findBlock(blockId: string): IBlock | undefined { return this.component.blocks.find((b: IBlock) => b.id === blockId); } /** * Gets the index of a block */ getBlockIndex(blockId: string): number { return this.component.blocks.findIndex((b: IBlock) => b.id === blockId); } /** * Focuses a specific block */ async focusBlock(blockId: string, cursorPosition: 'start' | 'end' | number = 'start'): Promise { // First ensure the component is updated await this.component.updateComplete; const wrapperElement = this.component.shadowRoot!.querySelector(`[data-block-id="${blockId}"]`); if (wrapperElement) { const blockComponent = wrapperElement.querySelector('dees-wysiwyg-block') as any; if (blockComponent) { // Wait a frame to ensure the block is rendered await new Promise(resolve => requestAnimationFrame(resolve)); // Now focus with cursor position blockComponent.focusWithCursor(cursorPosition); } } } /** * Updates the content of a block */ updateBlockContent(blockId: string, content: string): void { const block = this.findBlock(blockId); if (block) { block.content = content; this.component.updateValue(); } } /** * Transforms a block to a different type */ transformBlock(blockId: string, newType: IBlock['type'], metadata?: any): void { const block = this.findBlock(blockId); if (block) { block.type = newType; block.content = ''; if (metadata) { block.metadata = metadata; } this.component.updateValue(); this.component.requestUpdate(); } } /** * Moves a block to a new position */ moveBlock(blockId: string, targetIndex: number): void { const blocks = [...this.component.blocks]; const currentIndex = this.getBlockIndex(blockId); if (currentIndex === -1 || targetIndex < 0 || targetIndex >= blocks.length) { return; } const [movedBlock] = blocks.splice(currentIndex, 1); blocks.splice(targetIndex, 0, movedBlock); this.component.blocks = blocks; this.component.updateValue(); } /** * Gets the previous block */ getPreviousBlock(blockId: string): IBlock | null { const index = this.getBlockIndex(blockId); return index > 0 ? this.component.blocks[index - 1] : null; } /** * Gets the next block */ getNextBlock(blockId: string): IBlock | null { const index = this.getBlockIndex(blockId); return index < this.component.blocks.length - 1 ? this.component.blocks[index + 1] : null; } }