diff --git a/packages/core/src/components/BlockManager.ts b/packages/core/src/components/BlockManager.ts index 23f8b1d..cc668dc 100644 --- a/packages/core/src/components/BlockManager.ts +++ b/packages/core/src/components/BlockManager.ts @@ -1,11 +1,11 @@ import { BlockAddedEvent, BlockRemovedEvent, EditorJSModel, EventType, ModelEvents } from '@editorjs/model'; import 'reflect-metadata'; import { Inject, Service } from 'typedi'; -import { EditorUI } from '../ui/Editor/index.js'; import { BlockToolAdapter, CaretAdapter, FormattingAdapter } from '@editorjs/dom-adapters'; import ToolsManager from '../tools/ToolsManager.js'; import { BlockAPI, BlockToolData } from '@editorjs/editorjs'; import { CoreConfigValidated } from '../entities/Config.js'; +import { BlockAddedCoreEvent, BlockRemovedCoreEvent, EventBus } from './EventBus/index.js'; /** * Parameters for the BlocksManager.insert() method @@ -45,9 +45,9 @@ export class BlocksManager { #model: EditorJSModel; /** - * Editor's UI class instance to add and remove blocks to the UI + * Editor's EventBus instance to exchange events between components */ - #editorUI: EditorUI; + #eventBus: EventBus; /** * Caret Adapter instance @@ -74,7 +74,7 @@ export class BlocksManager { * BlocksManager constructor * All parameters are injected thorugh the IoC container * @param model - Editor's Document Model instance - * @param editorUI - Editor's UI class instance + * @param eventBus - Editor's EventBus instance * @param caretAdapter - Caret Adapter instance * @param toolsManager - Tools manager instance * @param formattingAdapter - will be passed to BlockToolAdapter for rendering inputs` formatted text @@ -82,14 +82,14 @@ export class BlocksManager { */ constructor( model: EditorJSModel, - editorUI: EditorUI, + eventBus: EventBus, caretAdapter: CaretAdapter, toolsManager: ToolsManager, formattingAdapter: FormattingAdapter, @Inject('EditorConfig') config: CoreConfigValidated ) { this.#model = model; - this.#editorUI = editorUI; + this.#eventBus = eventBus; this.#caretAdapter = caretAdapter; this.#toolsManager = toolsManager; this.#formattingAdapter = formattingAdapter; @@ -177,7 +177,12 @@ export class BlocksManager { try { const blockElement = await block.render(); - this.#editorUI.addBlock(blockElement, index.blockIndex); + this.#eventBus.dispatchEvent(new BlockAddedCoreEvent({ + tool: tool.name, + data: data.data, + ui: blockElement, + index: index.blockIndex, + })); } catch (error) { console.error(`[BlockManager] Block Tool ${data.name} failed to render`, error); } @@ -189,12 +194,15 @@ export class BlocksManager { * @param event - BlockRemovedEvent */ #handleBlockRemovedEvent(event: BlockRemovedEvent): void { - const { index } = event.detail; + const { data, index } = event.detail; if (index.blockIndex === undefined) { throw new Error('Block index should be defined. Probably something wrong with the Editor Model. Please, report this issue'); } - this.#editorUI.removeBlock(index.blockIndex); + this.#eventBus.dispatchEvent(new BlockRemovedCoreEvent({ + tool: data.name, + index: index.blockIndex, + })); } } diff --git a/packages/core/src/components/EventBus/core-events/BlockAddedCoreEvent.ts b/packages/core/src/components/EventBus/core-events/BlockAddedCoreEvent.ts new file mode 100644 index 0000000..b46d41b --- /dev/null +++ b/packages/core/src/components/EventBus/core-events/BlockAddedCoreEvent.ts @@ -0,0 +1,41 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import type { BlockToolData } from '@editorjs/editorjs'; +import { CoreEventBase } from './CoreEventBase.js'; +import { CoreEventType } from './CoreEventType.js'; + +/** + * Payload of BlockAddedCoreEvent custom event + * Contains added block data: name, data, index and UI content to be rendered on tha page + * @template UI - type of the UI content + */ +export interface BlockAddedCoreEventPayload { + /** + * Name of the added Block Tool + */ + readonly tool: string; + /** + * Added Block data + */ + readonly data: BlockToolData; + /** + * UI content to be rendered on the page + */ + readonly ui: UI; + /** + * Index of the added Block + */ + readonly index: number; +} + +/** + * Class for event that is being fired after the block is added + */ +export class BlockAddedCoreEvent extends CoreEventBase> { + /** + * BlockAddedCoreEvent constructor function + * @param payload - BlockAdded event payload with tool name, block data, index and UI content + */ + constructor(payload: BlockAddedCoreEventPayload) { + super(CoreEventType.BlockAdded, payload); + } +} diff --git a/packages/core/src/components/EventBus/core-events/BlockRemovedCoreEvent.ts b/packages/core/src/components/EventBus/core-events/BlockRemovedCoreEvent.ts new file mode 100644 index 0000000..723e832 --- /dev/null +++ b/packages/core/src/components/EventBus/core-events/BlockRemovedCoreEvent.ts @@ -0,0 +1,29 @@ +import { CoreEventBase } from './CoreEventBase.js'; +import { CoreEventType } from './CoreEventType.js'; + +/** + * Payload of BlockRemovedCoreEvent custom event + */ +export interface BlockRemovedCoreEventPayload { + /** + * Block Tool name + */ + readonly tool: string; + /** + * Index of the removed block + */ + readonly index: number; +} + +/** + * Class for event that is being fired after the block is removed + */ +export class BlockRemovedCoreEvent extends CoreEventBase { + /** + * BlockRemovedCoreEvent constructor function + * @param payload - BlockRemoved event payload with toola name and block index + */ + constructor(payload: BlockRemovedCoreEventPayload) { + super(CoreEventType.BlockRemoved, payload); + } +} diff --git a/packages/core/src/components/EventBus/core-events/CoreEventBase.ts b/packages/core/src/components/EventBus/core-events/CoreEventBase.ts new file mode 100644 index 0000000..c26acb5 --- /dev/null +++ b/packages/core/src/components/EventBus/core-events/CoreEventBase.ts @@ -0,0 +1,17 @@ +/** + * Represents a base class for core events. + * @template Payload - The type of the event payload. + */ +// eslint-disable-next-line n/no-unsupported-features/node-builtins +export class CoreEventBase extends CustomEvent { + /** + * CoreEventBase constructor function + * @param name - type of the core event + * @param payload - payload of the core event, can contain any data + */ + constructor(name: string, payload: Payload) { + super(`core:${name}`, { + detail: payload, + }); + } +} diff --git a/packages/core/src/components/EventBus/core-events/CoreEventType.ts b/packages/core/src/components/EventBus/core-events/CoreEventType.ts new file mode 100644 index 0000000..4d12b11 --- /dev/null +++ b/packages/core/src/components/EventBus/core-events/CoreEventType.ts @@ -0,0 +1,17 @@ +/** + * Enumeration of core events + */ +export enum CoreEventType { + /** + * Event is fired when a block is added to the Editor + */ + BlockAdded = 'block:added', + /** + * Event is fired when a block is removed from the Editor + */ + BlockRemoved = 'block:removed', + /** + * Event is fired when a tool is loaded + */ + ToolLoaded = 'tool:loaded' +} diff --git a/packages/core/src/components/EventBus/core-events/ToolLoadedCoreEvent.ts b/packages/core/src/components/EventBus/core-events/ToolLoadedCoreEvent.ts new file mode 100644 index 0000000..0a410d0 --- /dev/null +++ b/packages/core/src/components/EventBus/core-events/ToolLoadedCoreEvent.ts @@ -0,0 +1,28 @@ +import type { ToolFacadeClass } from '../../../tools/facades/index.js'; +import { CoreEventBase } from './CoreEventBase.js'; +import { CoreEventType } from './CoreEventType.js'; + +/** + * Payload of ToolLoadedCoreEvent custom event + * Contains laoded tool facade instance + * @todo replace facade object with API wrapper + */ +export interface ToolLoadedCoreEventPayload { + /** + * Loaded tool facade instance + */ + readonly tool: ToolFacadeClass; +} + +/** + * Class for event that is being fired after the tool is loaded + */ +export class ToolLoadedCoreEvent extends CoreEventBase { + /** + * ToolLoadedCoreEvent constructor function + * @param payload - ToolLoaded event payload with loaded tool facade instance + */ + constructor(payload: ToolLoadedCoreEventPayload) { + super(CoreEventType.ToolLoaded, payload); + } +} diff --git a/packages/core/src/components/EventBus/core-events/index.ts b/packages/core/src/components/EventBus/core-events/index.ts new file mode 100644 index 0000000..64b8a71 --- /dev/null +++ b/packages/core/src/components/EventBus/core-events/index.ts @@ -0,0 +1,4 @@ +export * from './BlockAddedCoreEvent.js'; +export * from './BlockRemovedCoreEvent.js'; +export * from './ToolLoadedCoreEvent.js'; +export * from './CoreEventType.js'; diff --git a/packages/core/src/components/EventBus/index.ts b/packages/core/src/components/EventBus/index.ts new file mode 100644 index 0000000..6e5534b --- /dev/null +++ b/packages/core/src/components/EventBus/index.ts @@ -0,0 +1,43 @@ +import 'reflect-metadata'; +import { Service } from 'typedi'; + +export type Event = `${Channel}:${Name}`; + +export type CoreEvent = Event<'core', Name>; + +/** + * Extension for the EventTarget interface to allow for custom events. + */ +declare global { + /** + * EventTarget interface extension + */ + interface EventTarget { + /** + * Adds an event listener for the specified event type + * @param type - a string representing the event type to listen for + * @param callback - the function to call when the event is triggered + * @param options - an options object that specifies characteristics about the event listener + */ + // eslint-disable-next-line n/no-unsupported-features/node-builtins + addEventListener(type: Event, callback: ((event: CustomEvent) => void) | null, options?: AddEventListenerOptions | boolean): void; + /** + * Removes an event listener for the specified event type + * @param type - a string representing the event type to stop listening for + * @param callback - the event callback to remove + * @param options - an options object that specifies characteristics about the event listener + */ + // eslint-disable-next-line n/no-unsupported-features/node-builtins + removeEventListener(type: Event, callback: ((event: CustomEvent) => void) | null, options?: EventListenerOptions | boolean): void; + } +} + +/** + * EventBus class to handle events between components + * Extends native EventTarget class + */ +@Service() +export class EventBus extends EventTarget {} + +export * from './core-events/index.js'; +export * from './ui-events/index.js'; diff --git a/packages/core/src/components/EventBus/ui-events/UIEventBase.ts b/packages/core/src/components/EventBus/ui-events/UIEventBase.ts new file mode 100644 index 0000000..a33e0c0 --- /dev/null +++ b/packages/core/src/components/EventBus/ui-events/UIEventBase.ts @@ -0,0 +1,17 @@ +/** + * Represents a base class for UI events. + * @template Payload - The type of the event payload. + */ +// eslint-disable-next-line n/no-unsupported-features/node-builtins +export class UIEventBase extends CustomEvent { + /** + * UIEventBase constructor function + * @param name - type of the core event + * @param payload - payload of the core event, can contain any data + */ + constructor(name: string, payload: Payload) { + super(`ui:${name}`, { + detail: payload, + }); + } +} diff --git a/packages/core/src/components/EventBus/ui-events/index.ts b/packages/core/src/components/EventBus/ui-events/index.ts new file mode 100644 index 0000000..c56c055 --- /dev/null +++ b/packages/core/src/components/EventBus/ui-events/index.ts @@ -0,0 +1 @@ +export * from './UIEventBase.js'; diff --git a/packages/core/src/components/Toolbox.ts b/packages/core/src/components/Toolbox.ts deleted file mode 100644 index c3caed9..0000000 --- a/packages/core/src/components/Toolbox.ts +++ /dev/null @@ -1,27 +0,0 @@ -import 'reflect-metadata'; -import { Service } from 'typedi'; -import ToolsManager from '../tools/ToolsManager.js'; -import { ToolboxUI } from '../ui/Toolbox/index.js'; - -/** - * Class responsible for Toolbox business logic - * - calls ToolboxUI to render the tools buttons in the toolbox - */ -@Service() -export class Toolbox { - /** - * Toolbox class constructor, all parameters are injected through the IoC container - * @param toolsManager - ToolsManager instance to get block tools - * @param toolboxUI - ToolboxUI instance to render tools buttons in the toolbox - */ - constructor( - toolsManager: ToolsManager, - toolboxUI: ToolboxUI - ) { - const blockTools = toolsManager.blockTools; - - blockTools.forEach((blockTool) => { - toolboxUI.addTool(blockTool); - }); - } -} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 36f8ce4..519bc99 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -10,7 +10,6 @@ import type { CoreConfig } from '@editorjs/sdk'; import { BlocksManager } from './components/BlockManager.js'; import { EditorUI } from './ui/Editor/index.js'; import { ToolboxUI } from './ui/Toolbox/index.js'; -import { Toolbox } from './components/Toolbox.js'; /** * If no holder is provided via config, the editor will be appended to the element with this id @@ -75,7 +74,6 @@ export default class Core { this.validateConfig(config); - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unnecessary-type-assertion this.#config = config as CoreConfigValidated; this.#iocContainer.set('EditorConfig', this.#config); @@ -100,7 +98,11 @@ export default class Core { this.#prepareUI(); this.#iocContainer.get(BlocksManager); - this.#iocContainer.get(Toolbox); + + /** + * @todo avait when isReady API is implemented + */ + void this.#toolsManager.prepareTools(); this.#model.initializeDocument({ blocks }); } @@ -110,11 +112,10 @@ export default class Core { */ #prepareUI(): void { const editorUI = this.#iocContainer.get(EditorUI); - const toolboxUI = this.#iocContainer.get(ToolboxUI); - editorUI.render(); + this.#iocContainer.get(ToolboxUI); - editorUI.addToolbox(toolboxUI.render()); + editorUI.render(); } /** diff --git a/packages/core/src/tools/ToolsManager.ts b/packages/core/src/tools/ToolsManager.ts index 13dd306..bfc8566 100644 --- a/packages/core/src/tools/ToolsManager.ts +++ b/packages/core/src/tools/ToolsManager.ts @@ -2,9 +2,10 @@ import type { BlockToolConstructor } from '@editorjs/sdk'; import 'reflect-metadata'; import { deepMerge, isFunction, isObject, PromiseQueue } from '@editorjs/helpers'; import { Inject, Service } from 'typedi'; -import type { BlockToolFacade, BlockTuneFacade, - InlineToolFacade } from './facades/index.js'; import { + BlockToolFacade, BlockTuneFacade, + InlineToolFacade, + ToolFacadeClass, ToolsCollection, ToolsFactory } from './facades/index.js'; @@ -19,6 +20,7 @@ import type { UnifiedToolConfig } from '../entities/index.js'; import BoldInlineTool from './internal/inline-tools/bold/index.js'; import ItalicInlineTool from './internal/inline-tools/italic/index.js'; import LinkInlineTool from './internal/inline-tools/link/index.js'; +import { EventBus, ToolLoadedCoreEvent } from '../components/EventBus/index.js'; /** * Works with tools @@ -39,6 +41,11 @@ export default class ToolsManager { */ #config: UnifiedToolConfig; + /** + * EventBus instance to exchange events between components + */ + #eventBus: EventBus; + /** * Tools available for use */ @@ -95,15 +102,18 @@ export default class ToolsManager { /** * @param editorConfig - EditorConfig object * @param editorConfig.tools - Tools configuration passed by user + * @param eventBus - EventBus instance to exchange events between components */ - constructor(@Inject('EditorConfig') editorConfig: EditorConfig) { + constructor( + @Inject('EditorConfig') editorConfig: EditorConfig, + eventBus: EventBus + ) { this.#config = this.#prepareConfig(editorConfig.tools ?? {}); + this.#eventBus = eventBus; this.#validateTools(); this.#factory = new ToolsFactory(this.#config, editorConfig, {}); - - void this.prepareTools(); } /** @@ -113,6 +123,14 @@ export default class ToolsManager { public async prepareTools(): Promise { const promiseQueue = new PromiseQueue(); + const setToAvailableToolsCollection = (toolName: string, tool: ToolFacadeClass): void => { + this.#availableTools.set(toolName, tool); + + this.#eventBus.dispatchEvent(new ToolLoadedCoreEvent({ + tool, + })); + }; + Object.entries(this.#config).forEach(([toolName, config]) => { if (isFunction(config.class.prepare)) { void promiseQueue.add(async () => { @@ -150,7 +168,7 @@ export default class ToolsManager { } } - this.#availableTools.set(toolName, tool); + setToAvailableToolsCollection(toolName, tool); } catch (e) { console.error(`Tool ${toolName} failed to prepare`, e); @@ -158,7 +176,7 @@ export default class ToolsManager { } }); } else { - this.#availableTools.set(toolName, this.#factory.get(toolName)); + setToAvailableToolsCollection(toolName, this.#factory.get(toolName)); } }); diff --git a/packages/core/src/tools/facades/ToolsCollection.ts b/packages/core/src/tools/facades/ToolsCollection.ts index d4a5e0e..65c5a06 100644 --- a/packages/core/src/tools/facades/ToolsCollection.ts +++ b/packages/core/src/tools/facades/ToolsCollection.ts @@ -2,12 +2,12 @@ import { type BlockToolFacade } from './BlockToolFacade.js'; import { type InlineToolFacade } from './InlineToolFacade.js'; import { type BlockTuneFacade } from './BlockTuneFacade.js'; -export type ToolClass = BlockToolFacade | InlineToolFacade | BlockTuneFacade; +export type ToolFacadeClass = BlockToolFacade | InlineToolFacade | BlockTuneFacade; /** * Class to store Editor Tools */ -export class ToolsCollection extends Map { +export class ToolsCollection extends Map { /** * Returns Block Tools collection */ diff --git a/packages/core/src/ui/Editor/index.ts b/packages/core/src/ui/Editor/index.ts index e27d3fe..15d5cf6 100644 --- a/packages/core/src/ui/Editor/index.ts +++ b/packages/core/src/ui/Editor/index.ts @@ -1,6 +1,9 @@ import 'reflect-metadata'; import { Inject, Service } from 'typedi'; import { CoreConfigValidated } from '../../entities/index.js'; +import { EventBus } from '../../components/EventBus/index.js'; +import { BlockAddedCoreEvent, CoreEventType } from '../../components/EventBus/index.js'; +import { ToolboxRenderedUIEvent } from '../Toolbox/index.js'; /** * Editor's main UI renderer for HTML environment @@ -19,16 +22,37 @@ export class EditorUI { */ #blocks: HTMLElement[] = []; + #eventBus: EventBus; + /** * EditorUI constructor method * @param config - EditorJS validated configuration + * @param eventBus - EventBus instance to exchange events between components */ - constructor(@Inject('EditorConfig') config: CoreConfigValidated) { + constructor(@Inject('EditorConfig') config: CoreConfigValidated, eventBus: EventBus) { this.#holder = config.holder; + this.#eventBus = eventBus; + + this.#eventBus.addEventListener(`core:${CoreEventType.BlockAdded}`, (event: BlockAddedCoreEvent) => { + const { ui, index } = event.detail; + + this.#addBlock(ui, index); + }); + + this.#eventBus.addEventListener(`core:${CoreEventType.BlockRemoved}`, (event: BlockAddedCoreEvent) => { + const { index } = event.detail; + + this.#removeBlock(index); + }); + + this.#eventBus.addEventListener(`ui:toolbox:rendered`, (event: ToolboxRenderedUIEvent) => { + this.#addToolbox(event.detail.toolbox); + }); } /** * Renders the editor UI + * @todo replace with the event handler */ public render(): void { // will add UI to holder element @@ -38,7 +62,7 @@ export class EditorUI { * Adds toolbox to the editor UI * @param toolboxElement - toolbox HTML element to add to the page */ - public addToolbox(toolboxElement: HTMLElement): void { + #addToolbox(toolboxElement: HTMLElement): void { this.#holder.appendChild(toolboxElement); } @@ -47,7 +71,7 @@ export class EditorUI { * @param blockElement - block HTML element to add to the page * @param index - index where to add a block at */ - public addBlock(blockElement: HTMLElement, index: number): void { + #addBlock(blockElement: HTMLElement, index: number): void { this.#validateIndex(index); if (index < this.#blocks.length) { @@ -63,7 +87,7 @@ export class EditorUI { * Removes block from the page * @param index - index where to remove block at */ - public removeBlock(index: number): void { + #removeBlock(index: number): void { this.#validateIndex(index); this.#blocks[index].remove(); diff --git a/packages/core/src/ui/Toolbox/ToolboxRenderedUIEvent.ts b/packages/core/src/ui/Toolbox/ToolboxRenderedUIEvent.ts new file mode 100644 index 0000000..08ea230 --- /dev/null +++ b/packages/core/src/ui/Toolbox/ToolboxRenderedUIEvent.ts @@ -0,0 +1,25 @@ +import { UIEventBase } from '../../components/EventBus/index.js'; + +/** + * Payload of the ToolboxRenderedUIEvent + * Contains Toolbox HTML element + */ +export interface ToolboxRenderedUIEventPayload { + /** + * Toolbox HTML element + */ + readonly toolbox: HTMLElement; +} + +/** + * Class for event that is being fired after the toolbox is rendered + */ +export class ToolboxRenderedUIEvent extends UIEventBase { + /** + * ToolboxRenderedUIEvent constructor function + * @param payload - ToolboxRendered event payload + */ + constructor(payload: ToolboxRenderedUIEventPayload) { + super('toolbox:rendered', payload); + } +} diff --git a/packages/core/src/ui/Toolbox/index.ts b/packages/core/src/ui/Toolbox/index.ts index 757af95..0e1b032 100644 --- a/packages/core/src/ui/Toolbox/index.ts +++ b/packages/core/src/ui/Toolbox/index.ts @@ -3,6 +3,8 @@ import { Service } from 'typedi'; import { BlockToolFacade } from '../../tools/facades/index.js'; import { make } from '@editorjs/dom'; import { BlocksAPI } from '../../api/BlocksAPI.js'; +import { CoreEventType, EventBus, ToolLoadedCoreEvent } from '../../components/EventBus/index.js'; +import { ToolboxRenderedUIEvent } from './ToolboxRenderedUIEvent.js'; /** * UI module responsible for rendering the toolbox @@ -17,6 +19,11 @@ export class ToolboxUI { */ #blocksAPI: BlocksAPI; + /** + * EventBus instance to exchange events between components + */ + #eventBus: EventBus; + /** * Object with Toolbox HTML nodes */ @@ -24,22 +31,36 @@ export class ToolboxUI { /** * ToolboxUI class constructor + * @todo - unify the constructor parameters with the other UI plugins * @param blocksAPI - BlocksAPI instance to insert blocks + * @param eventBus - EventBus instance to exchange events between components */ - constructor(blocksAPI: BlocksAPI) { + constructor(blocksAPI: BlocksAPI, eventBus: EventBus) { this.#blocksAPI = blocksAPI; + this.#eventBus = eventBus; + + this.#render(); + + this.#eventBus.addEventListener(`core:${CoreEventType.ToolLoaded}`, (event: ToolLoadedCoreEvent) => { + const { tool } = event.detail; + + if (tool.isBlock()) { + this.addTool(tool); + } + }); } /** - * Renders Toolbox UI - * @returns Toolbox HTML element + * Renders Toolbox UI and dispatches an event */ - public render(): HTMLElement { + #render(): void { this.#nodes.holder = make('div'); this.#nodes.holder.style.display = 'flex'; - return this.#nodes.holder; + this.#eventBus.dispatchEvent(new ToolboxRenderedUIEvent({ + toolbox: this.#nodes.holder, + })); } /** @@ -58,3 +79,5 @@ export class ToolboxUI { this.#nodes.holder.appendChild(toolButton); } } + +export * from './ToolboxRenderedUIEvent.js'; diff --git a/packages/dom-adapters/src/BlockToolAdapter/index.ts b/packages/dom-adapters/src/BlockToolAdapter/index.ts index 2d897dd..87ee469 100644 --- a/packages/dom-adapters/src/BlockToolAdapter/index.ts +++ b/packages/dom-adapters/src/BlockToolAdapter/index.ts @@ -88,12 +88,16 @@ export class BlockToolAdapter implements BlockToolAdapterInterface { this.#caretAdapter.attachInput(input, builder.build()); - const fragments = this.#model.getFragments(this.#blockIndex, key); - - fragments.forEach(fragment => { - console.log('fragment', fragment); - // this.#formattingAdapter.formatElementContent(input, fragment); - }); + try { + const fragments = this.#model.getFragments(this.#blockIndex, key); + + fragments.forEach(fragment => { + console.log('fragment', fragment); + // this.#formattingAdapter.formatElementContent(input, fragment); + }); + } catch (_) { + // do nothing — TextNode is not created yet as there is no initial data in the model + } } /**