Skip to content

Implement some BlocksAPI method #114

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 51 additions & 1 deletion packages/core/src/api/BlocksAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { BlocksManager } from '../components/BlockManager.js';
import { BlockToolData, ToolConfig } from '@editorjs/editorjs';
import { CoreConfigValidated } from '@editorjs/sdk';
import { BlocksAPI as BlocksApiInterface } from '@editorjs/sdk';
import { type BlockNodeSerialized, EditorDocumentSerialized } from '@editorjs/model';

/**
* Blocks API
Expand All @@ -28,12 +29,60 @@ export class BlocksAPI implements BlocksApiInterface {
*/
constructor(
blocksManager: BlocksManager,
@Inject('EditorConfig') config: CoreConfigValidated
@Inject('EditorConfig') config: CoreConfigValidated
) {
this.#blocksManager = blocksManager;
this.#config = config;
}

/**
* Remove all blocks from Document
*/
public clear(): void {
return this.#blocksManager.clear();
}

/**
* Render passed data
* @param document - serialized document data to render
*/
public render(document: EditorDocumentSerialized): void {
return this.#blocksManager.render(document);
}

/**
* Removes Block by index, or current block if index is not passed
* @param index - index of a block to delete
*/
public delete(index?: number): void {
return this.#blocksManager.deleteBlock(index);
}

/**
* Moves a block to a new index
* @param toIndex - index where the block is moved to
* @param [fromIndex] - block to move. Current block if not passed
*/
public move(toIndex: number, fromIndex?: number): void {
return this.#blocksManager.move(toIndex, fromIndex);
}

/**
* Returns Blocks count
*/
public getBlocksCount(): number {
return this.#blocksManager.blocksCount;
}

/**
* Inserts several Blocks to specified index
* @param blocks - array of blocks to insert
* @param [index] - index to insert blocks at. If undefined, inserts at the end
*/
public insertMany(blocks: BlockNodeSerialized[], index?: number): void {
return this.#blocksManager.insertMany(blocks, index);
}

/**
* Inserts a new block to the editor
* @param type - Block tool name to insert
Expand Down Expand Up @@ -62,6 +111,7 @@ export class BlocksAPI implements BlocksApiInterface {
data,
index,
replace,
// needToFocus,
});
}
}
87 changes: 85 additions & 2 deletions packages/core/src/components/BlockManager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { BlockAddedEvent, BlockRemovedEvent, EditorJSModel, EventType, ModelEvents } from '@editorjs/model';
import {
BlockAddedEvent, type BlockNodeSerialized,
BlockRemovedEvent,
type EditorDocumentSerialized,
EditorJSModel,
EventType,
ModelEvents
} from '@editorjs/model';
import 'reflect-metadata';
import { Inject, Service } from 'typedi';
import { BlockToolAdapter, CaretAdapter, FormattingAdapter } from '@editorjs/dom-adapters';
Expand Down Expand Up @@ -68,6 +75,13 @@ export class BlocksManager {
*/
#formattingAdapter: FormattingAdapter;

/**
* Returns Blocks count
*/
public get blocksCount(): number {
return this.#model.length;
}

/**
* BlocksManager constructor
* All parameters are injected thorugh the IoC container
Expand Down Expand Up @@ -102,6 +116,7 @@ export class BlocksManager {
* @param parameters.type - block tool name to insert
* @param parameters.data - block's initial data
* @param parameters.index - index to insert block at
// * @param parameters.needToFocus - flag indicates if caret should be set to block after insert
* @param parameters.replace - flag indicates if block at index should be replaced
*/
public insert({
Expand All @@ -119,10 +134,78 @@ export class BlocksManager {
newIndex = this.#model.length + (replace ? 0 : 1);
}

if (replace) {
this.#model.removeBlock(this.#config.userId, newIndex);
}

this.#model.addBlock(this.#config.userId, {
...data,
name: type,
}, index);
}, newIndex);
}

/**
* Inserts several Blocks to specified index
* @param blocks - array of blocks to insert
* @param [index] - index to insert blocks at. If undefined, inserts at the end
*/
public insertMany(blocks: BlockNodeSerialized[], index: number = this.#model.length + 1): void {
blocks.forEach((block, i) => this.#model.addBlock(this.#config.userId, block, index + i));
}

/**
* Re-initialize document
* @param document - serialized document data
*/
public render(document: EditorDocumentSerialized): void {
this.#model.initializeDocument(document);
}

/**
* Remove all blocks from Document
*/
public clear(): void {
this.#model.clearBlocks();
}

/**
* Removes Block by index, or current block if index is not passed
* @param index - index of a block to delete
*/
public deleteBlock(index: number | undefined = this.#getCurrentBlockIndex()): void {
if (index === undefined) {
/**
* @todo see what happens in legacy
*/
throw new Error('No block selected to delete');
}

this.#model.removeBlock(this.#config.userId, index);
}

/**
* Moves a block to a new index
* @param toIndex - index where the block is moved to
* @param [fromIndex] - block to move. Current block if not passed
*/
public move(toIndex: number, fromIndex: number | undefined = this.#getCurrentBlockIndex()): void {
if (fromIndex === undefined) {
throw new Error('No block selected to move');
}

const block = this.#model.serialized.blocks[fromIndex];

this.#model.removeBlock(this.#config.userId, fromIndex);
this.#model.addBlock(this.#config.userId, block, toIndex + (fromIndex <= toIndex ? 1 : 0));
}

/**
* Returns block index where user caret is placed
*/
#getCurrentBlockIndex(): number | undefined {
const caretIndex = this.#caretAdapter.userCaretIndex;

return caretIndex?.blockIndex;
}

/**
Expand Down
31 changes: 11 additions & 20 deletions packages/model/src/EditorJSModel.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Stryker disable all -- we don't count mutation test coverage fot this file as it just proxy calls to EditorDocument
/* istanbul ignore file -- we don't count test coverage fot this file as it just proxy calls to EditorDocument */
import { type Index, IndexBuilder } from './entities/index.js';
import { type EditorDocumentSerialized, type Index, IndexBuilder } from './entities/index.js';
import { type BlockNodeSerialized, EditorDocument } from './entities/index.js';
import {
BlockAddedEvent,
Expand Down Expand Up @@ -108,11 +108,17 @@ export class EditorJSModel extends EventBus {
/**
* Fills the EditorDocument with the provided blocks.
*
* @param doc - document options
* @param doc.blocks - The blocks to fill the EditorDocument with.
* @param document - document data to initialize
*/
public initializeDocument({ blocks }: { blocks: BlockNodeSerialized[] }): void {
this.#document.initialize(blocks);
public initializeDocument(document: Partial<EditorDocumentSerialized> & Pick<EditorDocumentSerialized, 'blocks'>): void {
this.#document.initialize(document);
}

/**
* Clear all blocks
*/
public clearBlocks(): void {
this.#document.clear();
}

/**
Expand Down Expand Up @@ -193,21 +199,6 @@ export class EditorJSModel extends EventBus {
return this.#document.addBlock(...parameters);
}

/**
* Moves a BlockNode from one index to another
*
* @param _userId - user identifier which is being set to the context
* @param parameters = moveBlock method parameters
* @param parameters.from - The index of the BlockNode to move
* @param parameters.to - The index to move the BlockNode to
* @throws Error if the index is out of bounds
*/
@WithContext
public moveBlock(_userId: string | number, ...parameters: Parameters<EditorDocument['moveBlock']>): ReturnType<EditorDocument['moveBlock']> {
return this.#document.moveBlock(...parameters);
}


/**
* Removes a BlockNode from the EditorDocument at the specified index.
*
Expand Down
31 changes: 12 additions & 19 deletions packages/model/src/entities/EditorDocument/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,23 @@
/**
* Initializes EditorDocument with passed blocks
*
* @param blocks - document serialized blocks
* @param document - document serialized data
*/
public initialize(blocks: BlockNodeSerialized[]): void {
public initialize(document: Partial<EditorDocumentSerialized> & Pick<EditorDocumentSerialized, 'blocks'>): void {
this.clear();

blocks.forEach((block) => {
if (document.identifier !== undefined) {
this.identifier = document.identifier as DocumentId;

Check warning on line 88 in packages/model/src/entities/EditorDocument/index.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
}

Check warning on line 89 in packages/model/src/entities/EditorDocument/index.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🌿 Branch is not covered

Warning! Not covered branch

document.blocks.forEach((block) => {
this.addBlock(block);
});

if (document.properties) {
Object.entries(document.properties)
.forEach(([name, value]) => this.setProperty(name, value));

Check warning on line 97 in packages/model/src/entities/EditorDocument/index.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement

Check warning on line 97 in packages/model/src/entities/EditorDocument/index.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement

Check warning on line 97 in packages/model/src/entities/EditorDocument/index.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🕹️ Function is not covered

Warning! Not covered function
}

Check warning on line 98 in packages/model/src/entities/EditorDocument/index.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🌿 Branch is not covered

Warning! Not covered branch
}

/**
Expand Down Expand Up @@ -137,22 +146,6 @@
this.dispatchEvent(new BlockAddedEvent(builder.build(), blockNode.serialized, getContext<string | number>()!));
}

/**
* Moves a BlockNode from one index to another
*
* @param from - The index of the BlockNode to move
* @param to - The index to move the BlockNode to
* @throws Error if the index is out of bounds
*/
public moveBlock(from: number, to: number): void {
this.#checkIndexOutOfBounds(from);
this.#checkIndexOutOfBounds(to);

const blockToMove = this.#children.splice(from, 1)[0];

this.#children.splice(to, 0, blockToMove);
}

/**
* Removes a BlockNode from the EditorDocument at the specified index.
*
Expand Down
Loading
Loading