diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 26b2336d..43fca419 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -3,6 +3,7 @@ ### 2.31.0 - `New` - Inline tools (those with `isReadOnlySupported` specified) can now be used in read-only mode +- `Improvement` - Block manager passes target tool config to the `conversionConfig.import` method on conversion - `Fix` - Fix selection of first block in read-only initialization with "autofocus=true" - `Fix` - Incorrect caret position after blocks merging in Safari - `Fix` - Several toolbox items exported by the one tool have the same shortcut displayed in toolbox @@ -49,11 +50,11 @@ - `New` – "Convert to" control is now also available in Block Tunes - `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. - `Improvement` — Now Paragraph placeholder will be shown for the current paragraph, not only the first one. -- `Improvment` - The API `blocks.update` now accepts `tunes` data as optional third argument and makes `data` - block data as optional. +- `Improvement` - The API `blocks.update` now accepts `tunes` data as optional third argument and makes `data` - block data as optional. - `Improvement` — The ability to merge blocks of different types (if both tools provide the conversionConfig) - `Improvement` - The API `blocks.convert()` now returns the new block API - `Improvement` - The API `caret.setToBlock()` now can accept either BlockAPI or block index or block id -- `Impovement` – *MenuConfig* – `TunesMenuConfig` type is deprecated, use the `MenuConfig` instead +- `Improvement` – *MenuConfig* – `TunesMenuConfig` type is deprecated, use the `MenuConfig` instead – `Improvement` — *Types* — `BlockToolConstructorOptions` type improved, `block` and `config` are not optional anymore - `Improvement` - The Plus button and Block Tunes toggler are now better aligned with large line-height blocks, such as Headings - `Improvement` — Creating links on Android devices: now the mobile keyboard will have an "Enter" key for accepting the inserted link. diff --git a/src/components/modules/blockManager.ts b/src/components/modules/blockManager.ts index 3f3ee99b..48fec049 100644 --- a/src/components/modules/blockManager.ts +++ b/src/components/modules/blockManager.ts @@ -863,7 +863,7 @@ export default class BlockManager extends Module { /** * Now using Conversion Config "import" we compose a new Block data */ - let newBlockData = convertStringToBlockData(cleanData, replacingTool.conversionConfig); + let newBlockData = convertStringToBlockData(cleanData, replacingTool.conversionConfig, replacingTool.settings); /** * Optional data overrides. diff --git a/src/components/utils/blocks.ts b/src/components/utils/blocks.ts index fb564223..710cfa5f 100644 --- a/src/components/utils/blocks.ts +++ b/src/components/utils/blocks.ts @@ -1,4 +1,4 @@ -import type { BlockAPI } from '../../../types'; +import type { BlockAPI, ToolConfig } from '../../../types'; import type { ConversionConfig } from '../../../types/configs/conversion-config'; import type { SavedData } from '../../../types/data-formats'; import type { BlockToolData } from '../../../types/tools/block-tool-data'; @@ -174,12 +174,13 @@ export function convertBlockDataToString(blockData: BlockToolData, conversionCon * * @param stringToImport - string to convert * @param conversionConfig - tool's conversion config + * @param targetToolConfig - target tool config, used in conversionConfig.import method */ -export function convertStringToBlockData(stringToImport: string, conversionConfig?: ConversionConfig): BlockToolData { +export function convertStringToBlockData(stringToImport: string, conversionConfig?: ConversionConfig, targetToolConfig?: ToolConfig): BlockToolData { const importProp = conversionConfig?.import; if (isFunction(importProp)) { - return importProp(stringToImport); + return importProp(stringToImport, targetToolConfig); } else if (isString(importProp)) { return { [importProp]: stringToImport, diff --git a/test/cypress/fixtures/tools/ToolMock.ts b/test/cypress/fixtures/tools/ToolMock.ts index 67b29045..51ea3a95 100644 --- a/test/cypress/fixtures/tools/ToolMock.ts +++ b/test/cypress/fixtures/tools/ToolMock.ts @@ -3,7 +3,7 @@ import type { BlockTool, BlockToolConstructorOptions } from '../../../../types'; /** * Simple structure for Tool data */ -interface MockToolData { +export interface MockToolData { text: string; } diff --git a/test/cypress/tests/api/blocks.cy.ts b/test/cypress/tests/api/blocks.cy.ts index 17da54bf..ab97b8b5 100644 --- a/test/cypress/tests/api/blocks.cy.ts +++ b/test/cypress/tests/api/blocks.cy.ts @@ -1,6 +1,6 @@ import type EditorJS from '../../../../types/index'; -import type { ConversionConfig, ToolboxConfig } from '../../../../types'; -import ToolMock from '../../fixtures/tools/ToolMock'; +import type { ConversionConfig, ToolboxConfig, ToolConfig } from '../../../../types'; +import ToolMock, { type MockToolData } from '../../fixtures/tools/ToolMock'; import { nanoid } from 'nanoid'; /** @@ -444,5 +444,84 @@ describe('api.blocks', () => { }); }); }); + + it('should pass tool config to the conversionConfig.import method of the tool', function () { + const existingBlock = { + id: 'test-id-123', + type: 'paragraph', + data: { + text: 'Some text', + }, + }; + + const conversionTargetToolConfig = { + defaultStyle: 'defaultStyle', + }; + + /** + * Mock of Tool with conversionConfig + */ + class ToolWithConversionConfig extends ToolMock { + /** + * Specify conversion config of the tool + */ + public static get conversionConfig(): { + /** + * Method that is responsible for conversion from data to string + */ + export: (data: string) => string; + + /** + * Method that is responsible for conversion from string to data + * Should return stringified config to see, if Editor actually passed tool config to it + */ + import: (content: string, config: ToolConfig) => MockToolData; + } { + return { + export: (data) => data, + /** + * Passed config should be returned + */ + import: (_content, config) => { + return { text: JSON.stringify(config) }; + }, + }; + } + } + + cy.createEditor({ + tools: { + conversionTargetTool: { + class: ToolWithConversionConfig, + config: conversionTargetToolConfig, + }, + }, + data: { + blocks: [ + existingBlock, + ], + }, + }).then(async (editor) => { + const { convert } = editor.blocks; + + await convert(existingBlock.id, 'conversionTargetTool'); + + // wait for block to be converted + cy.wait(100).then(async () => { + /** + * Check that block was converted + */ + const { blocks } = await editor.save(); + + expect(blocks.length).to.eq(1); + expect(blocks[0].type).to.eq('conversionTargetTool'); + + /** + * Check that tool converted returned config as a result of import + */ + expect(blocks[0].data.text).to.eq(JSON.stringify(conversionTargetToolConfig)); + }); + }); + }); }); }); diff --git a/types/configs/conversion-config.ts b/types/configs/conversion-config.ts index b61aa478..0f7e2748 100644 --- a/types/configs/conversion-config.ts +++ b/types/configs/conversion-config.ts @@ -1,4 +1,4 @@ -import type { BlockToolData } from '../tools'; +import type { BlockToolData, ToolConfig } from '../tools'; /** * Config allows Tool to specify how it can be converted into/from another Tool @@ -12,7 +12,7 @@ export interface ConversionConfig { * 1. String — the key of Tool data object to fill it with imported string on render. * 2. Function — method that accepts importing string and composes Tool data to render. */ - import?: ((data: string) => string) | string; + import?: ((data: string, config: ToolConfig) => BlockToolData) | string; /** * How to export this Tool to make other Block.