Skip to content

Commit 44c29dd

Browse files
w99910ThomasneSpecc
authored
feat(blocks-api): blocks.update() now can update tunes as well as data (codex-team#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 <[email protected]> Co-authored-by: Peter Savchenko <[email protected]>
1 parent 0e8cc0d commit 44c29dd

File tree

6 files changed

+113
-12
lines changed

6 files changed

+113
-12
lines changed

docs/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- `New` – Block Tunes now supports nesting items
66
- `New` – Block Tunes now supports separator items
7+
- `Improvment` - The API `blocks.update` now accepts `tunes` data as optional third argument and makes `data` - block data as optional.
78
- `New` – "Convert to" control is now also available in Block Tunes
89
- `Improvement` — The ability to merge blocks of different types (if both tools provide the conversionConfig)
910
- `Fix``onChange` will be called when removing the entire text within a descendant element of a block.

docs/api.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ use 'move' instead)
7979

8080
`insert(type?: string, data?: BlockToolData, config?: ToolConfig, index?: number, needToFocus?: boolean)` - insert new Block with passed parameters
8181

82-
`update(id: string, data: BlockToolData)` - updates data for the block with passed id
82+
`update(id: string, data?: BlockToolData, tunes?: {[name: string]: BlockTuneData})` - updates block data and block tunes for the block with passed id
8383

8484
#### SanitizerAPI
8585

src/components/modules/api/blocks.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import * as _ from './../../utils';
44
import BlockAPI from '../../block/api';
55
import Module from '../../__module';
66
import Block from '../../block';
7-
import { capitalize } from './../../utils';
7+
import { capitalize } from '../../utils';
8+
import { BlockTuneData } from '../../../../types/block-tunes/block-tune-data';
89

910
/**
1011
* @class BlocksAPI
@@ -320,17 +321,18 @@ export default class BlocksAPI extends Module {
320321
* Updates block data by id
321322
*
322323
* @param id - id of the block to update
323-
* @param data - the new data
324+
* @param data - (optional) the new data
325+
* @param tunes - (optional) tune data
324326
*/
325-
public update = async (id: string, data: Partial<BlockToolData>): Promise<BlockAPIInterface> => {
327+
public update = async (id: string, data?: Partial<BlockToolData>, tunes?: {[name: string]: BlockTuneData}): Promise<BlockAPIInterface> => {
326328
const { BlockManager } = this.Editor;
327329
const block = BlockManager.getBlockById(id);
328330

329331
if (block === undefined) {
330332
throw new Error(`Block with id "${id}" not found`);
331333
}
332334

333-
const updatedBlock = await BlockManager.update(block, data);
335+
const updatedBlock = await BlockManager.update(block, data, tunes);
334336

335337
// we cast to any because our BlockAPI has no "new" signature
336338
// eslint-disable-next-line @typescript-eslint/no-explicit-any

src/components/modules/blockManager.ts

+12-5
Original file line numberDiff line numberDiff line change
@@ -337,19 +337,26 @@ export default class BlockManager extends Module {
337337
* Update Block data.
338338
*
339339
* 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
340-
* Should not trigger 'block-removed' or 'block-added' events
340+
* Should not trigger 'block-removed' or 'block-added' events.
341+
*
342+
* If neither data nor tunes is provided, return the provided block instead.
341343
*
342344
* @param block - block to update
343-
* @param data - new data
345+
* @param data - (optional) new data
346+
* @param tunes - (optional) tune data
344347
*/
345-
public async update(block: Block, data: Partial<BlockToolData>): Promise<Block> {
348+
public async update(block: Block, data?: Partial<BlockToolData>, tunes?: {[name: string]: BlockTuneData}): Promise<Block> {
349+
if (!data && !tunes) {
350+
return block;
351+
}
352+
346353
const existingData = await block.data;
347354

348355
const newBlock = this.composeBlock({
349356
id: block.id,
350357
tool: block.name,
351-
data: Object.assign({}, existingData, data),
352-
tunes: block.tunes,
358+
data: Object.assign({}, existingData, data ?? {}),
359+
tunes: tunes ?? block.tunes,
353360
});
354361

355362
const blockIndex = this.getBlockIndex(block);

test/cypress/tests/api/blocks.cy.ts

+89
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type EditorJS from '../../../../types/index';
22
import type { ConversionConfig, ToolboxConfig } from '../../../../types';
33
import ToolMock from '../../fixtures/tools/ToolMock';
4+
import {nanoid} from "nanoid";
45

56
/**
67
* There will be described test cases of 'blocks.*' API
@@ -102,6 +103,94 @@ describe('api.blocks', () => {
102103
});
103104
});
104105

106+
it('should update tune data when it is provided', () => {
107+
/**
108+
* Example Tune Class
109+
*/
110+
class ExampleTune {
111+
112+
protected data: object;
113+
/**
114+
*
115+
* @param data
116+
*/
117+
constructor({ data}) {
118+
this.data = data;
119+
}
120+
121+
/**
122+
* Tell editor.js that this Tool is a Block Tune
123+
*
124+
* @returns {boolean}
125+
*/
126+
public static get isTune(): boolean {
127+
return true;
128+
}
129+
130+
/**
131+
* Create Tunes controls wrapper that will be appended to the Block Tunes panel
132+
*
133+
* @returns {Element}
134+
*/
135+
public render(): Element {
136+
return document.createElement('div');
137+
}
138+
139+
/**
140+
* CSS selectors used in Tune
141+
*/
142+
public static get CSS(): object {
143+
return {};
144+
}
145+
146+
/**
147+
* Returns Tune state
148+
*
149+
* @returns {string}
150+
*/
151+
public save(): object | string {
152+
return this.data || '';
153+
}
154+
}
155+
156+
157+
cy.createEditor({
158+
tools: {
159+
exampleTune: ExampleTune,
160+
},
161+
tunes: [ 'exampleTune' ],
162+
data: {
163+
blocks: [
164+
{
165+
id: nanoid(),
166+
type: 'paragraph',
167+
data: {
168+
text: 'First block',
169+
},
170+
tunes: {
171+
exampleTune: 'citation',
172+
},
173+
},
174+
],
175+
},
176+
}).as('editorInstance');
177+
178+
// Update the tunes data of a block
179+
// Check if it is updated
180+
cy.get<EditorJS>('@editorInstance')
181+
.then(async (editor) => {
182+
await editor.blocks.update(editor.blocks.getBlockByIndex(0).id, null, {
183+
exampleTune: 'test',
184+
});
185+
const data = await editor.save();
186+
187+
const actual = JSON.stringify(data.blocks[0].tunes);
188+
const expected = JSON.stringify({ exampleTune: 'test' });
189+
190+
expect(actual).to.eq(expected);
191+
});
192+
});
193+
105194
/**
106195
* When incorrect id passed, editor should not update any block
107196
*/

types/api/blocks.d.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Block from '../../src/components/block';
22
import {OutputBlockData, OutputData} from '../data-formats/output-data';
33
import {BlockToolData, ToolConfig} from '../tools';
44
import {BlockAPI} from './block';
5+
import {BlockTuneData} from '../block-tunes/block-tune-data';
56

67
/**
78
* Describes methods to manipulate with Editor`s blocks
@@ -142,9 +143,10 @@ export interface Blocks {
142143
* Updates block data by id
143144
*
144145
* @param id - id of the block to update
145-
* @param data - the new data. Can be partial.
146+
* @param data - (optional) the new data. Can be partial.
147+
* @param tunes - (optional) tune data
146148
*/
147-
update(id: string, data: Partial<BlockToolData>): Promise<BlockAPI>;
149+
update(id: string, data?: Partial<BlockToolData>, tunes?: {[name: string]: BlockTuneData}): Promise<BlockAPI>;
148150

149151
/**
150152
* Converts block to another type. Both blocks should provide the conversionConfig.

0 commit comments

Comments
 (0)