mirror of
https://github.com/codex-team/editor.js
synced 2026-03-14 22:55:47 +01:00
feat(blocks-api): blocks.update() now can update tunes as well as data (#2720)
* Update `tunes` data when new `tunes` data is provided AFAIK, when you update block using `editor.blocks.update` method, only `data` attribute is merged and updated. I believe `tunes` data should be updated if provided. * commit * edit parameter type, move test * restore package-lock and yarn lock * update in api docs * make data optional * edit changelog --------- Co-authored-by: Thomas <zawlintun@robust.best> Co-authored-by: Peter Savchenko <specc.dev@gmail.com>
This commit is contained in:
parent
0e8cc0d5be
commit
44c29dd645
6 changed files with 113 additions and 12 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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<BlockToolData>): Promise<BlockAPIInterface> => {
|
||||
public update = async (id: string, data?: Partial<BlockToolData>, tunes?: {[name: string]: BlockTuneData}): Promise<BlockAPIInterface> => {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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<BlockToolData>): Promise<Block> {
|
||||
public async update(block: Block, data?: Partial<BlockToolData>, tunes?: {[name: string]: BlockTuneData}): Promise<Block> {
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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<EditorJS>('@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
|
||||
*/
|
||||
|
|
|
|||
6
types/api/blocks.d.ts
vendored
6
types/api/blocks.d.ts
vendored
|
|
@ -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<BlockToolData>): Promise<BlockAPI>;
|
||||
update(id: string, data?: Partial<BlockToolData>, tunes?: {[name: string]: BlockTuneData}): Promise<BlockAPI>;
|
||||
|
||||
/**
|
||||
* Converts block to another type. Both blocks should provide the conversionConfig.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue