Skip to content

Commit c829336

Browse files
VolgaIgorneSpecc
andauthored
Fixed display of conversion menu for blocks without export rule (#2799)
* Fixed display of convert menu for blocks without export rule According to the workflow script from the documentation: https://editorjs.io/tools-api/#conversionconfig * Update CHANGELOG.md * some improvements and tests --------- Co-authored-by: Peter Savchenko <[email protected]>
1 parent 8f365f0 commit c829336

File tree

7 files changed

+102
-20
lines changed

7 files changed

+102
-20
lines changed

docs/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
### 2.30.6
4+
5+
`Fix` – Fix the display of ‘Convert To’ near blocks that do not have the ‘conversionConfig.export’ rule specified
6+
37
### 2.30.5
48

59
`Fix` – Fix exported types

src/components/utils/blocks.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ export async function getConvertibleToolsForBlock(block: BlockAPI, allBlockTools
5151
const savedData = await block.save() as SavedData;
5252
const blockData = savedData.data;
5353

54+
/**
55+
* Checking that the block's tool has an «export» rule
56+
*/
57+
const blockTool = allBlockTools.find((tool) => tool.name === block.name);
58+
59+
if (blockTool !== undefined && !isToolConvertable(blockTool, 'export')) {
60+
return [];
61+
}
62+
5463
return allBlockTools.reduce((result, tool) => {
5564
/**
5665
* Skip tools without «import» rule specified
@@ -59,12 +68,19 @@ export async function getConvertibleToolsForBlock(block: BlockAPI, allBlockTools
5968
return result;
6069
}
6170

71+
/**
72+
* Skip tools that does not specify toolbox
73+
*/
74+
if (tool.toolbox === undefined) {
75+
return result;
76+
}
77+
6278
/** Filter out invalid toolbox entries */
6379
const actualToolboxItems = tool.toolbox.filter((toolboxItem) => {
6480
/**
6581
* Skip items that don't pass 'toolbox' property or do not have an icon
6682
*/
67-
if (isEmpty(toolboxItem) || !toolboxItem.icon) {
83+
if (isEmpty(toolboxItem) || toolboxItem.icon === undefined) {
6884
return false;
6985
}
7086

@@ -86,10 +102,10 @@ export async function getConvertibleToolsForBlock(block: BlockAPI, allBlockTools
86102
result.push({
87103
...tool,
88104
toolbox: actualToolboxItems,
89-
});
105+
} as BlockToolAdapter);
90106

91107
return result;
92-
}, []);
108+
}, [] as BlockToolAdapter[]);
93109
}
94110

95111

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import type { ConversionConfig } from '@/types/configs/conversion-config';
2+
import ToolMock from './ToolMock';
3+
4+
/**
5+
* This tool has a conversionConfig, but it doesn't have export property.
6+
*
7+
* That means that tool can be created from string, but can't be converted to string.
8+
*/
9+
export class ToolWithoutConversionExport extends ToolMock {
10+
/**
11+
* Rules specified how our Tool can be converted to/from other Tool.
12+
*/
13+
public static get conversionConfig(): ConversionConfig {
14+
return {
15+
import: 'text', // this tool can be created from string
16+
17+
/**
18+
* Here is no "export" property, so this tool can't be converted to string
19+
*/
20+
// export: (data) => data.text,
21+
};
22+
}
23+
}

test/cypress/tests/ui/BlockTunes.cy.ts

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { selectionChangeDebounceTimeout } from '../../../../src/components/constants';
22
import Header from '@editorjs/header';
3-
import type { ToolboxConfig } from '../../../../types';
3+
import type { ConversionConfig, ToolboxConfig } from '../../../../types';
44
import type { MenuConfig } from '../../../../types/tools';
5-
5+
import { ToolWithoutConversionExport } from '../../fixtures/tools/ToolWithoutConversionExport';
66

77
describe('BlockTunes', function () {
88
describe('Search', () => {
@@ -185,6 +185,39 @@ describe('BlockTunes', function () {
185185
.should('not.exist');
186186
});
187187

188+
it('should not display the ConvertTo control if block has no conversionConfig.export specified', () => {
189+
cy.createEditor({
190+
tools: {
191+
testTool: ToolWithoutConversionExport,
192+
},
193+
data: {
194+
blocks: [
195+
{
196+
type: 'testTool',
197+
data: {
198+
text: 'Some text',
199+
},
200+
},
201+
],
202+
},
203+
}).as('editorInstance');
204+
205+
cy.get('@editorInstance')
206+
.get('[data-cy=editorjs]')
207+
.find('.ce-block')
208+
.click();
209+
210+
cy.get('@editorInstance')
211+
.get('[data-cy=editorjs]')
212+
.find('.ce-toolbar__settings-btn')
213+
.click();
214+
215+
cy.get('@editorInstance')
216+
.get('[data-cy=editorjs]')
217+
.find('.ce-popover-item[data-item-name=convert-to]')
218+
.should('not.exist');
219+
});
220+
188221
it('should not display tool with the same data in "Convert to" menu', () => {
189222
/**
190223
* Tool with several toolbox entries configured
@@ -193,9 +226,10 @@ describe('BlockTunes', function () {
193226
/**
194227
* Tool is convertable
195228
*/
196-
public static get conversionConfig(): { import: string } {
229+
public static get conversionConfig(): ConversionConfig {
197230
return {
198231
import: 'text',
232+
export: 'text',
199233
};
200234
}
201235

test/cypress/tests/utils/flipper.cy.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,9 @@ describe('Flipper', () => {
8787
.trigger('keydown', { keyCode: ARROW_DOWN_KEY_CODE });
8888

8989
/**
90-
* Check whether we focus the Move Up Tune or not
90+
* Check whether we focus the Delete Tune or not
9191
*/
92-
cy.get('[data-item-name="move-up"]')
92+
cy.get('[data-item-name="delete"]')
9393
.should('have.class', 'ce-popover-item--focused');
9494

9595
cy.get('[data-cy=editorjs]')

types/tools/block-tool.d.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ConversionConfig, PasteConfig, SanitizerConfig } from '../configs';
22
import { BlockToolData } from './block-tool-data';
3-
import { BaseTool, BaseToolConstructable } from './tool';
3+
import { BaseTool, BaseToolConstructable, BaseToolConstructorOptions } from './tool';
44
import { ToolConfig } from './tool-config';
55
import { API, BlockAPI, ToolboxConfig } from '../index';
66
import { PasteEvent } from './paste-events';
@@ -83,10 +83,8 @@ export interface BlockTool extends BaseTool {
8383
/**
8484
* Describe constructor parameters
8585
*/
86-
export interface BlockToolConstructorOptions<D extends object = any, C extends object = any> {
87-
api: API;
86+
export interface BlockToolConstructorOptions<D extends object = any, C extends object = any> extends BaseToolConstructorOptions<C> {
8887
data: BlockToolData<D>;
89-
config: ToolConfig<C>;
9088
block: BlockAPI;
9189
readOnly: boolean;
9290
}

types/tools/tool.d.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,27 @@ import {MenuConfig} from './menu-config';
99
export interface BaseTool<RenderReturnType = HTMLElement> {
1010
/**
1111
* Tool`s render method
12-
*
13-
* For Inline Tools may return either HTMLElement (deprecated) or {@link MenuConfig}
12+
*
13+
* For Inline Tools may return either HTMLElement (deprecated) or {@link MenuConfig}
1414
* @see https://editorjs.io/menu-config
15-
*
15+
*
1616
* For Block Tools returns tool`s wrapper html element
1717
*/
1818
render(): RenderReturnType | Promise<RenderReturnType>;
1919
}
2020

21+
export interface BaseToolConstructorOptions<C extends object = any> {
22+
/**
23+
* Editor.js API
24+
*/
25+
api: API;
26+
27+
/**
28+
* Tool configuration
29+
*/
30+
config?: ToolConfig<C>;
31+
}
32+
2133
export interface BaseToolConstructable {
2234
/**
2335
* Define Tool type as Inline
@@ -35,11 +47,6 @@ export interface BaseToolConstructable {
3547
*/
3648
title?: string;
3749

38-
/**
39-
* Describe constructor parameters
40-
*/
41-
new (config: {api: API, config?: ToolConfig}): BaseTool;
42-
4350
/**
4451
* Tool`s prepare method. Can be async
4552
* @param data

0 commit comments

Comments
 (0)