-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add BlockManager and EditorUI classes (#85)
* Add BlockManager and EditorUI classes * Add JSDocs * Add try catch for block.render() call
- Loading branch information
Showing
3 changed files
with
208 additions
and
79 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import { BlockAddedEvent, BlockRemovedEvent, EditorJSModel, EventType, ModelEvents } from '@editorjs/model'; | ||
import 'reflect-metadata'; | ||
import { Service } from 'typedi'; | ||
import { EditorUI } from './ui/Editor/index.js'; | ||
import { BlockToolAdapter, CaretAdapter } from '@editorjs/dom-adapters'; | ||
import ToolsManager from './tools/ToolsManager.js'; | ||
import { BlockAPI } from '@editorjs/editorjs'; | ||
|
||
/** | ||
* BlocksManager is responsible for | ||
* - handling block adding and removing events | ||
* - updating the Model blocks data on user actions | ||
*/ | ||
@Service() | ||
export class BlocksManager { | ||
/** | ||
* Editor's Document Model instance to get and update blocks data | ||
*/ | ||
#model: EditorJSModel; | ||
|
||
/** | ||
* Editor's UI class instance to add and remove blocks to the UI | ||
*/ | ||
#editorUI: EditorUI; | ||
|
||
/** | ||
* Caret Adapter instance | ||
* Required here to create BlockToolAdapter | ||
*/ | ||
#caretAdapter: CaretAdapter; | ||
|
||
/** | ||
* Tools manager instance to get block tools | ||
*/ | ||
#toolsManager: ToolsManager; | ||
|
||
/** | ||
* 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 caretAdapter - Caret Adapter instance | ||
* @param toolsManager - Tools manager instance | ||
*/ | ||
constructor( | ||
model: EditorJSModel, | ||
editorUI: EditorUI, | ||
caretAdapter: CaretAdapter, | ||
toolsManager: ToolsManager | ||
) { | ||
this.#model = model; | ||
this.#editorUI = editorUI; | ||
this.#caretAdapter = caretAdapter; | ||
this.#toolsManager = toolsManager; | ||
|
||
this.#model.addEventListener(EventType.Changed, event => this.#handleModelUpdate(event)); | ||
} | ||
|
||
/** | ||
* Handles model update events | ||
* Filters only BlockAddedEvent and BlockRemovedEvent | ||
* @param event - Model update event | ||
*/ | ||
#handleModelUpdate(event: ModelEvents): void { | ||
switch (true) { | ||
case event instanceof BlockAddedEvent: | ||
void this.#handleBlockAddedEvent(event); | ||
break; | ||
case event instanceof BlockRemovedEvent: | ||
this.#handleBlockRemovedEvent(event); | ||
break; | ||
default: | ||
} | ||
} | ||
|
||
/** | ||
* Handles BlockAddedEvent | ||
* - creates BlockTool instance | ||
* - renders its content | ||
* - calls UI module to render the block | ||
* @param event - BlockAddedEvent | ||
*/ | ||
async #handleBlockAddedEvent(event: BlockAddedEvent): Promise<void> { | ||
const { index, data } = event.detail; | ||
|
||
if (index.blockIndex === undefined) { | ||
throw new Error('[BlockManager] Block index should be defined. Probably something wrong with the Editor Model. Please, report this issue'); | ||
} | ||
|
||
const blockToolAdapter = new BlockToolAdapter(this.#model, this.#caretAdapter, index.blockIndex); | ||
|
||
const tool = this.#toolsManager.blockTools.get(event.detail.data.name); | ||
|
||
if (!tool) { | ||
throw new Error(`[BlockManager] Block Tool ${event.detail.data.name} not found`); | ||
} | ||
|
||
const block = tool.create({ | ||
adapter: blockToolAdapter, | ||
data: data, | ||
block: {} as BlockAPI, | ||
readOnly: false, | ||
}); | ||
|
||
try { | ||
const blockElement = await block.render(); | ||
|
||
this.#editorUI.addBlock(blockElement, index.blockIndex); | ||
} catch (error) { | ||
console.error(`[BlockManager] Block Tool ${event.detail.data.name} failed to render`, error); | ||
} | ||
} | ||
|
||
/** | ||
* Handles BlockRemovedEvent | ||
* - callse UI module to remove the block | ||
* @param event - BlockRemovedEvent | ||
*/ | ||
#handleBlockRemovedEvent(event: BlockRemovedEvent): void { | ||
const { 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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import 'reflect-metadata'; | ||
import { Inject, Service } from 'typedi'; | ||
import { CoreConfigValidated } from '../../entities/index.js'; | ||
|
||
/** | ||
* Editor's main UI renderer for HTML environment | ||
* - renders the editor UI | ||
* - adds and removes blocks on the page | ||
* - handles user UI interactions | ||
*/ | ||
@Service() | ||
export class EditorUI { | ||
/** | ||
* Editor holder element | ||
*/ | ||
#holder: HTMLElement; | ||
/** | ||
* Elements of the blocks added to the editor | ||
*/ | ||
#blocks: HTMLElement[] = []; | ||
|
||
/** | ||
* EditorUI constructor method | ||
* @param config - EditorJS validated configuration | ||
*/ | ||
constructor(@Inject('EditorConfig') config: CoreConfigValidated) { | ||
this.#holder = config.holder; | ||
} | ||
|
||
/** | ||
* Renders the editor UI | ||
*/ | ||
public render(): void { | ||
// will add UI to holder element | ||
} | ||
|
||
/** | ||
* Renders block's content on the page | ||
* @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 { | ||
this.#validateIndex(index); | ||
|
||
if (index < this.#blocks.length) { | ||
this.#blocks[index].insertAdjacentElement('beforebegin', blockElement); | ||
this.#blocks.splice(index, 0, blockElement); | ||
} else { | ||
this.#holder.appendChild(blockElement); | ||
this.#blocks.push(blockElement); | ||
} | ||
} | ||
|
||
/** | ||
* Removes block from the page | ||
* @param index - index where to remove block at | ||
*/ | ||
public removeBlock(index: number): void { | ||
this.#validateIndex(index); | ||
|
||
this.#blocks[index].remove(); | ||
this.#blocks.splice(index, 1); | ||
} | ||
|
||
/** | ||
* Validates index to be in bounds of the blocks array | ||
* @param index - index to validate | ||
*/ | ||
#validateIndex(index: number): void { | ||
if (index < 0 || index > this.#blocks.length) { | ||
throw new Error('Index out of bounds'); | ||
} | ||
} | ||
} |
1c8dcf2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverage report for
./packages/model
Test suite run success
389 tests passing in 24 suites.
Report generated by 🧪jest coverage report action from 1c8dcf2
1c8dcf2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverage report for
./packages/collaboration-manager
Test suite run success
6 tests passing in 1 suite.
Report generated by 🧪jest coverage report action from 1c8dcf2