Skip to content

Commit 7b3c213

Browse files
authored
Merge branch 'next' into wrap-content
2 parents 46163c1 + 6313409 commit 7b3c213

File tree

10 files changed

+199
-17
lines changed

10 files changed

+199
-17
lines changed

docs/CHANGELOG.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
### 2.31.0
44

55
- `New` - Inline tools (those with `isReadOnlySupported` specified) can now be used in read-only mode
6+
- `Improvement` - Block manager passes target tool config to the `conversionConfig.import` method on conversion
67
- `Fix` - Fix selection of first block in read-only initialization with "autofocus=true"
78
- `Fix` - Incorrect caret position after blocks merging in Safari
9+
- `Fix` - Several toolbox items exported by the one tool have the same shortcut displayed in toolbox
810

911
### 2.30.6
1012

@@ -48,11 +50,11 @@
4850
- `New` – "Convert to" control is now also available in Block Tunes
4951
- `New` — Editor.js now supports contenteditable placeholders out of the box. Just add `data-placeholder` or `data-placeholder-active` attribute to make it work. The first one will work like native placeholder while the second one will show placeholder only when block is current.
5052
- `Improvement` — Now Paragraph placeholder will be shown for the current paragraph, not only the first one.
51-
- `Improvment` - The API `blocks.update` now accepts `tunes` data as optional third argument and makes `data` - block data as optional.
53+
- `Improvement` - The API `blocks.update` now accepts `tunes` data as optional third argument and makes `data` - block data as optional.
5254
- `Improvement` — The ability to merge blocks of different types (if both tools provide the conversionConfig)
5355
- `Improvement` - The API `blocks.convert()` now returns the new block API
5456
- `Improvement` - The API `caret.setToBlock()` now can accept either BlockAPI or block index or block id
55-
- `Impovement`*MenuConfig*`TunesMenuConfig` type is deprecated, use the `MenuConfig` instead
57+
- `Improvement`*MenuConfig*`TunesMenuConfig` type is deprecated, use the `MenuConfig` instead
5658
`Improvement`*Types*`BlockToolConstructorOptions` type improved, `block` and `config` are not optional anymore
5759
- `Improvement` - The Plus button and Block Tunes toggler are now better aligned with large line-height blocks, such as Headings
5860
- `Improvement` — Creating links on Android devices: now the mobile keyboard will have an "Enter" key for accepting the inserted link.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@editorjs/editorjs",
3-
"version": "2.31.0-rc.1",
3+
"version": "2.31.0-rc.2",
44
"description": "Editor.js — open source block-style WYSIWYG editor with JSON output",
55
"main": "dist/editorjs.umd.js",
66
"module": "dist/editorjs.mjs",

src/components/modules/blockManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -863,7 +863,7 @@ export default class BlockManager extends Module {
863863
/**
864864
* Now using Conversion Config "import" we compose a new Block data
865865
*/
866-
let newBlockData = convertStringToBlockData(cleanData, replacingTool.conversionConfig);
866+
let newBlockData = convertStringToBlockData(cleanData, replacingTool.conversionConfig, replacingTool.settings);
867867

868868
/**
869869
* Optional data overrides.

src/components/ui/toolbox.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,23 +308,23 @@ export default class Toolbox extends EventsDispatcher<ToolboxEventMap> {
308308
/**
309309
* Maps tool data to popover item structure
310310
*/
311-
const toPopoverItem = (toolboxItem: ToolboxConfigEntry, tool: BlockToolAdapter): PopoverItemParams => {
311+
const toPopoverItem = (toolboxItem: ToolboxConfigEntry, tool: BlockToolAdapter, displaySecondaryLabel = true): PopoverItemParams => {
312312
return {
313313
icon: toolboxItem.icon,
314314
title: I18n.t(I18nInternalNS.toolNames, toolboxItem.title || _.capitalize(tool.name)),
315315
name: tool.name,
316316
onActivate: (): void => {
317317
this.toolButtonActivated(tool.name, toolboxItem.data);
318318
},
319-
secondaryLabel: tool.shortcut ? _.beautifyShortcut(tool.shortcut) : '',
319+
secondaryLabel: (tool.shortcut && displaySecondaryLabel) ? _.beautifyShortcut(tool.shortcut) : '',
320320
};
321321
};
322322

323323
return this.toolsToBeDisplayed
324324
.reduce<PopoverItemParams[]>((result, tool) => {
325325
if (Array.isArray(tool.toolbox)) {
326-
tool.toolbox.forEach(item => {
327-
result.push(toPopoverItem(item, tool));
326+
tool.toolbox.forEach((item, index) => {
327+
result.push(toPopoverItem(item, tool, index === 0));
328328
});
329329
} else if (tool.toolbox !== undefined) {
330330
result.push(toPopoverItem(tool.toolbox, tool));

src/components/utils/blocks.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { BlockAPI } from '../../../types';
1+
import type { BlockAPI, ToolConfig } from '../../../types';
22
import type { ConversionConfig } from '../../../types/configs/conversion-config';
33
import type { SavedData } from '../../../types/data-formats';
44
import type { BlockToolData } from '../../../types/tools/block-tool-data';
@@ -174,12 +174,13 @@ export function convertBlockDataToString(blockData: BlockToolData, conversionCon
174174
*
175175
* @param stringToImport - string to convert
176176
* @param conversionConfig - tool's conversion config
177+
* @param targetToolConfig - target tool config, used in conversionConfig.import method
177178
*/
178-
export function convertStringToBlockData(stringToImport: string, conversionConfig?: ConversionConfig): BlockToolData {
179+
export function convertStringToBlockData(stringToImport: string, conversionConfig?: ConversionConfig, targetToolConfig?: ToolConfig): BlockToolData {
179180
const importProp = conversionConfig?.import;
180181

181182
if (isFunction(importProp)) {
182-
return importProp(stringToImport);
183+
return importProp(stringToImport, targetToolConfig);
183184
} else if (isString(importProp)) {
184185
return {
185186
[importProp]: stringToImport,

test/cypress/fixtures/tools/ToolMock.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { BlockTool, BlockToolConstructorOptions } from '../../../../types';
33
/**
44
* Simple structure for Tool data
55
*/
6-
interface MockToolData {
6+
export interface MockToolData {
77
text: string;
88
}
99

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

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type EditorJS from '../../../../types/index';
2-
import type { ConversionConfig, ToolboxConfig } from '../../../../types';
3-
import ToolMock from '../../fixtures/tools/ToolMock';
2+
import type { ConversionConfig, ToolboxConfig, ToolConfig } from '../../../../types';
3+
import ToolMock, { type MockToolData } from '../../fixtures/tools/ToolMock';
44
import { nanoid } from 'nanoid';
55

66
/**
@@ -444,5 +444,84 @@ describe('api.blocks', () => {
444444
});
445445
});
446446
});
447+
448+
it('should pass tool config to the conversionConfig.import method of the tool', function () {
449+
const existingBlock = {
450+
id: 'test-id-123',
451+
type: 'paragraph',
452+
data: {
453+
text: 'Some text',
454+
},
455+
};
456+
457+
const conversionTargetToolConfig = {
458+
defaultStyle: 'defaultStyle',
459+
};
460+
461+
/**
462+
* Mock of Tool with conversionConfig
463+
*/
464+
class ToolWithConversionConfig extends ToolMock {
465+
/**
466+
* Specify conversion config of the tool
467+
*/
468+
public static get conversionConfig(): {
469+
/**
470+
* Method that is responsible for conversion from data to string
471+
*/
472+
export: (data: string) => string;
473+
474+
/**
475+
* Method that is responsible for conversion from string to data
476+
* Should return stringified config to see, if Editor actually passed tool config to it
477+
*/
478+
import: (content: string, config: ToolConfig) => MockToolData;
479+
} {
480+
return {
481+
export: (data) => data,
482+
/**
483+
* Passed config should be returned
484+
*/
485+
import: (_content, config) => {
486+
return { text: JSON.stringify(config) };
487+
},
488+
};
489+
}
490+
}
491+
492+
cy.createEditor({
493+
tools: {
494+
conversionTargetTool: {
495+
class: ToolWithConversionConfig,
496+
config: conversionTargetToolConfig,
497+
},
498+
},
499+
data: {
500+
blocks: [
501+
existingBlock,
502+
],
503+
},
504+
}).then(async (editor) => {
505+
const { convert } = editor.blocks;
506+
507+
await convert(existingBlock.id, 'conversionTargetTool');
508+
509+
// wait for block to be converted
510+
cy.wait(100).then(async () => {
511+
/**
512+
* Check that block was converted
513+
*/
514+
const { blocks } = await editor.save();
515+
516+
expect(blocks.length).to.eq(1);
517+
expect(blocks[0].type).to.eq('conversionTargetTool');
518+
519+
/**
520+
* Check that tool converted returned config as a result of import
521+
*/
522+
expect(blocks[0].data.text).to.eq(JSON.stringify(conversionTargetToolConfig));
523+
});
524+
});
525+
});
447526
});
448527
});

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

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,5 +114,105 @@ describe('Toolbox', function () {
114114
expect(blocks[1].type).to.eq('nonConvertableTool');
115115
});
116116
});
117+
118+
it('should display shortcut only for the first toolbox item if tool exports toolbox with several items', function () {
119+
/**
120+
* Mock of Tool with conversionConfig
121+
*/
122+
class ToolWithSeveralToolboxItems extends ToolMock {
123+
/**
124+
* Specify toolbox with several items related to one tool
125+
*/
126+
public static get toolbox(): ToolboxConfig {
127+
return [
128+
{
129+
icon: '',
130+
title: 'first tool',
131+
},
132+
{
133+
icon: '',
134+
title: 'second tool',
135+
},
136+
];
137+
}
138+
}
139+
140+
cy.createEditor({
141+
tools: {
142+
severalToolboxItemsTool: {
143+
class: ToolWithSeveralToolboxItems,
144+
shortcut: 'CMD+SHIFT+L',
145+
},
146+
},
147+
});
148+
149+
cy.get('[data-cy=editorjs]')
150+
.find('.ce-paragraph')
151+
.click()
152+
.type('Some text')
153+
.type('/'); // call a shortcut for toolbox
154+
155+
/**
156+
* Secondary title (shortcut) should exist for first toolbox item of the tool
157+
*/
158+
/* eslint-disable-next-line cypress/require-data-selectors */
159+
cy.get('.ce-popover')
160+
.find('.ce-popover-item[data-item-name="severalToolboxItemsTool"]')
161+
.first()
162+
.find('.ce-popover-item__secondary-title')
163+
.should('exist');
164+
165+
/**
166+
* Secondary title (shortcut) should not exist for second toolbox item of the same tool
167+
*/
168+
/* eslint-disable-next-line cypress/require-data-selectors */
169+
cy.get('.ce-popover')
170+
.find('.ce-popover-item[data-item-name="severalToolboxItemsTool"]')
171+
.eq(1)
172+
.find('.ce-popover-item__secondary-title')
173+
.should('not.exist');
174+
});
175+
176+
it('should display shortcut for the item if tool exports toolbox as an one item object', function () {
177+
/**
178+
* Mock of Tool with conversionConfig
179+
*/
180+
class ToolWithOneToolboxItems extends ToolMock {
181+
/**
182+
* Specify toolbox with several items related to one tool
183+
*/
184+
public static get toolbox(): ToolboxConfig {
185+
return {
186+
icon: '',
187+
title: 'tool',
188+
};
189+
}
190+
}
191+
192+
cy.createEditor({
193+
tools: {
194+
oneToolboxItemTool: {
195+
class: ToolWithOneToolboxItems,
196+
shortcut: 'CMD+SHIFT+L',
197+
},
198+
},
199+
});
200+
201+
cy.get('[data-cy=editorjs]')
202+
.find('.ce-paragraph')
203+
.click()
204+
.type('Some text')
205+
.type('/'); // call a shortcut for toolbox
206+
207+
/**
208+
* Secondary title (shortcut) should exist for toolbox item of the tool
209+
*/
210+
/* eslint-disable-next-line cypress/require-data-selectors */
211+
cy.get('.ce-popover')
212+
.find('.ce-popover-item[data-item-name="oneToolboxItemTool"]')
213+
.first()
214+
.find('.ce-popover-item__secondary-title')
215+
.should('exist');
216+
});
117217
});
118218
});

types/configs/conversion-config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { BlockToolData } from '../tools';
1+
import type { BlockToolData, ToolConfig } from '../tools';
22

33
/**
44
* Config allows Tool to specify how it can be converted into/from another Tool
@@ -12,7 +12,7 @@ export interface ConversionConfig {
1212
* 1. String — the key of Tool data object to fill it with imported string on render.
1313
* 2. Function — method that accepts importing string and composes Tool data to render.
1414
*/
15-
import?: ((data: string) => string) | string;
15+
import?: ((data: string, config: ToolConfig) => BlockToolData) | string;
1616

1717
/**
1818
* How to export this Tool to make other Block.

types/tools/tool-settings.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export interface ToolboxConfigEntry {
2222
icon?: string;
2323

2424
/**
25-
* May contain overrides for tool default config
25+
* May contain overrides for tool default data
2626
*/
2727
data?: BlockToolData
2828
}

0 commit comments

Comments
 (0)