Improve Wysiwyg editor

This commit is contained in:
Juergen Kunz
2025-06-24 08:19:53 +00:00
parent e4a042907a
commit 169f74aa2e
8 changed files with 982 additions and 27 deletions

View File

@ -0,0 +1,146 @@
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
*/
insertBlockAfter(afterBlock: IBlock, newBlock: IBlock, focusNewBlock: boolean = true): void {
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();
if (focusNewBlock && newBlock.type !== 'divider') {
setTimeout(() => {
this.focusBlock(newBlock.id);
}, 50);
}
}
/**
* 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
*/
focusBlock(blockId: string, cursorPosition: 'start' | 'end' = 'start'): void {
const wrapperElement = this.component.shadowRoot!.querySelector(`[data-block-id="${blockId}"]`);
if (wrapperElement) {
const blockElement = wrapperElement.querySelector('.block') as HTMLDivElement;
if (blockElement) {
blockElement.focus();
if (cursorPosition === 'start') {
WysiwygBlocks.setCursorToStart(blockElement);
} else {
WysiwygBlocks.setCursorToEnd(blockElement);
}
}
}
}
/**
* 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;
}
}