diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 2dea81e0..11a28712 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -4,6 +4,7 @@ - `New` – Block Tunes now supports nesting items - `New` – Block Tunes now supports separator items +- `Improvment` - The API `blocks.update` now accepts `tunes` data as optional third argument and makes `data` - block data as optional. - `New` – "Convert to" control is now also available in Block Tunes - `Improvement` — The ability to merge blocks of different types (if both tools provide the conversionConfig) - `Fix` — `onChange` will be called when removing the entire text within a descendant element of a block. diff --git a/docs/api.md b/docs/api.md index 3111cbf8..4c7f708d 100644 --- a/docs/api.md +++ b/docs/api.md @@ -79,7 +79,7 @@ use 'move' instead) `insert(type?: string, data?: BlockToolData, config?: ToolConfig, index?: number, needToFocus?: boolean)` - insert new Block with passed parameters -`update(id: string, data: BlockToolData)` - updates data for the block with passed id +`update(id: string, data?: BlockToolData, tunes?: {[name: string]: BlockTuneData})` - updates block data and block tunes for the block with passed id #### SanitizerAPI diff --git a/src/components/modules/api/blocks.ts b/src/components/modules/api/blocks.ts index dbb7831a..6c0c5869 100644 --- a/src/components/modules/api/blocks.ts +++ b/src/components/modules/api/blocks.ts @@ -4,7 +4,8 @@ import * as _ from './../../utils'; import BlockAPI from '../../block/api'; import Module from '../../__module'; import Block from '../../block'; -import { capitalize } from './../../utils'; +import { capitalize } from '../../utils'; +import { BlockTuneData } from '../../../../types/block-tunes/block-tune-data'; /** * @class BlocksAPI @@ -320,9 +321,10 @@ export default class BlocksAPI extends Module { * Updates block data by id * * @param id - id of the block to update - * @param data - the new data + * @param data - (optional) the new data + * @param tunes - (optional) tune data */ - public update = async (id: string, data: Partial): Promise => { + public update = async (id: string, data?: Partial, tunes?: {[name: string]: BlockTuneData}): Promise => { const { BlockManager } = this.Editor; const block = BlockManager.getBlockById(id); @@ -330,7 +332,7 @@ export default class BlocksAPI extends Module { throw new Error(`Block with id "${id}" not found`); } - const updatedBlock = await BlockManager.update(block, data); + const updatedBlock = await BlockManager.update(block, data, tunes); // we cast to any because our BlockAPI has no "new" signature // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/src/components/modules/blockManager.ts b/src/components/modules/blockManager.ts index 3442c0bd..ec555f20 100644 --- a/src/components/modules/blockManager.ts +++ b/src/components/modules/blockManager.ts @@ -337,19 +337,26 @@ export default class BlockManager extends Module { * Update Block data. * * Currently we don't have an 'update' method in the Tools API, so we just create a new block with the same id and type - * Should not trigger 'block-removed' or 'block-added' events + * Should not trigger 'block-removed' or 'block-added' events. + * + * If neither data nor tunes is provided, return the provided block instead. * * @param block - block to update - * @param data - new data + * @param data - (optional) new data + * @param tunes - (optional) tune data */ - public async update(block: Block, data: Partial): Promise { + public async update(block: Block, data?: Partial, tunes?: {[name: string]: BlockTuneData}): Promise { + if (!data && !tunes) { + return block; + } + const existingData = await block.data; const newBlock = this.composeBlock({ id: block.id, tool: block.name, - data: Object.assign({}, existingData, data), - tunes: block.tunes, + data: Object.assign({}, existingData, data ?? {}), + tunes: tunes ?? block.tunes, }); const blockIndex = this.getBlockIndex(block); diff --git a/test/cypress/tests/api/blocks.cy.ts b/test/cypress/tests/api/blocks.cy.ts index 77f25e91..66496bf7 100644 --- a/test/cypress/tests/api/blocks.cy.ts +++ b/test/cypress/tests/api/blocks.cy.ts @@ -1,6 +1,7 @@ import type EditorJS from '../../../../types/index'; import type { ConversionConfig, ToolboxConfig } from '../../../../types'; import ToolMock from '../../fixtures/tools/ToolMock'; +import {nanoid} from "nanoid"; /** * There will be described test cases of 'blocks.*' API @@ -102,6 +103,94 @@ describe('api.blocks', () => { }); }); + it('should update tune data when it is provided', () => { + /** + * Example Tune Class + */ + class ExampleTune { + + protected data: object; + /** + * + * @param data + */ + constructor({ data}) { + this.data = data; + } + + /** + * Tell editor.js that this Tool is a Block Tune + * + * @returns {boolean} + */ + public static get isTune(): boolean { + return true; + } + + /** + * Create Tunes controls wrapper that will be appended to the Block Tunes panel + * + * @returns {Element} + */ + public render(): Element { + return document.createElement('div'); + } + + /** + * CSS selectors used in Tune + */ + public static get CSS(): object { + return {}; + } + + /** + * Returns Tune state + * + * @returns {string} + */ + public save(): object | string { + return this.data || ''; + } + } + + + cy.createEditor({ + tools: { + exampleTune: ExampleTune, + }, + tunes: [ 'exampleTune' ], + data: { + blocks: [ + { + id: nanoid(), + type: 'paragraph', + data: { + text: 'First block', + }, + tunes: { + exampleTune: 'citation', + }, + }, + ], + }, + }).as('editorInstance'); + + // Update the tunes data of a block + // Check if it is updated + cy.get('@editorInstance') + .then(async (editor) => { + await editor.blocks.update(editor.blocks.getBlockByIndex(0).id, null, { + exampleTune: 'test', + }); + const data = await editor.save(); + + const actual = JSON.stringify(data.blocks[0].tunes); + const expected = JSON.stringify({ exampleTune: 'test' }); + + expect(actual).to.eq(expected); + }); + }); + /** * When incorrect id passed, editor should not update any block */ diff --git a/types/api/blocks.d.ts b/types/api/blocks.d.ts index 5085e99b..7b9a0455 100644 --- a/types/api/blocks.d.ts +++ b/types/api/blocks.d.ts @@ -2,6 +2,7 @@ import Block from '../../src/components/block'; import {OutputBlockData, OutputData} from '../data-formats/output-data'; import {BlockToolData, ToolConfig} from '../tools'; import {BlockAPI} from './block'; +import {BlockTuneData} from '../block-tunes/block-tune-data'; /** * Describes methods to manipulate with Editor`s blocks @@ -142,9 +143,10 @@ export interface Blocks { * Updates block data by id * * @param id - id of the block to update - * @param data - the new data. Can be partial. + * @param data - (optional) the new data. Can be partial. + * @param tunes - (optional) tune data */ - update(id: string, data: Partial): Promise; + update(id: string, data?: Partial, tunes?: {[name: string]: BlockTuneData}): Promise; /** * Converts block to another type. Both blocks should provide the conversionConfig.