98 lines
3.0 KiB
TypeScript
98 lines
3.0 KiB
TypeScript
import { html, type TemplateResult } from '@design.estate/dees-element';
|
|
import { type IBlock } from './wysiwyg.types.js';
|
|
import { WysiwygConverters } from './wysiwyg.converters.js';
|
|
|
|
export class WysiwygBlocks {
|
|
static renderListContent(content: string, metadata?: any): string {
|
|
const items = content.split('\n').filter(item => item.trim());
|
|
if (items.length === 0) return '';
|
|
const listTag = metadata?.listType === 'ordered' ? 'ol' : 'ul';
|
|
return `<${listTag}>${items.map(item => `<li>${WysiwygConverters.escapeHtml(item)}</li>`).join('')}</${listTag}>`;
|
|
}
|
|
|
|
static renderBlock(
|
|
block: IBlock,
|
|
isSelected: boolean,
|
|
handlers: {
|
|
onInput: (e: InputEvent) => void;
|
|
onKeyDown: (e: KeyboardEvent) => void;
|
|
onFocus: () => void;
|
|
onBlur: () => void;
|
|
onCompositionStart: () => void;
|
|
onCompositionEnd: () => void;
|
|
}
|
|
): TemplateResult {
|
|
if (block.type === 'divider') {
|
|
return html`
|
|
<div
|
|
class="block divider"
|
|
data-block-id="${block.id}"
|
|
>
|
|
<hr>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
if (block.type === 'list') {
|
|
return html`
|
|
<div
|
|
class="block list ${isSelected ? 'selected' : ''}"
|
|
data-block-id="${block.id}"
|
|
contenteditable="true"
|
|
@input="${handlers.onInput}"
|
|
@keydown="${handlers.onKeyDown}"
|
|
@focus="${handlers.onFocus}"
|
|
@blur="${handlers.onBlur}"
|
|
@compositionstart="${handlers.onCompositionStart}"
|
|
@compositionend="${handlers.onCompositionEnd}"
|
|
.innerHTML="${this.renderListContent(block.content, block.metadata)}"
|
|
></div>
|
|
`;
|
|
}
|
|
|
|
return html`
|
|
<div
|
|
class="block ${block.type} ${isSelected ? 'selected' : ''}"
|
|
data-block-id="${block.id}"
|
|
contenteditable="true"
|
|
@input="${handlers.onInput}"
|
|
@keydown="${handlers.onKeyDown}"
|
|
@focus="${handlers.onFocus}"
|
|
@blur="${handlers.onBlur}"
|
|
@compositionstart="${handlers.onCompositionStart}"
|
|
@compositionend="${handlers.onCompositionEnd}"
|
|
></div>
|
|
`;
|
|
}
|
|
|
|
static setCursorToEnd(element: HTMLElement): void {
|
|
const range = document.createRange();
|
|
const sel = window.getSelection();
|
|
range.selectNodeContents(element);
|
|
range.collapse(false);
|
|
sel!.removeAllRanges();
|
|
sel!.addRange(range);
|
|
}
|
|
|
|
static setCursorToStart(element: HTMLElement): void {
|
|
const range = document.createRange();
|
|
const sel = window.getSelection();
|
|
range.selectNodeContents(element);
|
|
range.collapse(true);
|
|
sel!.removeAllRanges();
|
|
sel!.addRange(range);
|
|
}
|
|
|
|
static focusListItem(listElement: HTMLElement): void {
|
|
const firstLi = listElement.querySelector('li');
|
|
if (firstLi) {
|
|
firstLi.focus();
|
|
const range = document.createRange();
|
|
const sel = window.getSelection();
|
|
range.selectNodeContents(firstLi);
|
|
range.collapse(true);
|
|
sel!.removeAllRanges();
|
|
sel!.addRange(range);
|
|
}
|
|
}
|
|
} |