From bd839d8d85fb766032daf9476df65522f1673493 Mon Sep 17 00:00:00 2001 From: GuillaumeOnepilot Date: Sat, 16 Dec 2023 21:31:36 +0100 Subject: [PATCH 01/16] feature: possibilities to merge blocks of different types --- src/components/block/index.ts | 12 ++++++++++-- src/components/modules/blockManager.ts | 2 +- src/components/tools/base.ts | 4 +++- src/components/tools/block.ts | 9 ++++++++- src/components/utils/blocks.ts | 4 ++++ types/tools/block-tool.d.ts | 15 ++++++++++++++- 6 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/components/block/index.ts b/src/components/block/index.ts index b47fe7811..882dd39b4 100644 --- a/src/components/block/index.ts +++ b/src/components/block/index.ts @@ -549,9 +549,10 @@ export default class Block extends EventsDispatcher { * Call plugins merge method * * @param {BlockToolData} data - data to merge + * @param {string} type - type of the block to merge */ - public async mergeWith(data: BlockToolData): Promise { - await this.toolInstance.merge(data); + public async mergeWith(data: BlockToolData, type: string): Promise { + await this.toolInstance.merge(data, type); } /** @@ -994,4 +995,11 @@ export default class Block extends EventsDispatcher { private dropInputsCache(): void { this.cachedInputs = []; } + + /** + * Get the list of mergeable blocks with the current block + */ + public get mergeableWithBlocks(): string[]|undefined { + return this.tool.mergeableBlocks; + } } diff --git a/src/components/modules/blockManager.ts b/src/components/modules/blockManager.ts index 7075d30fb..499008562 100644 --- a/src/components/modules/blockManager.ts +++ b/src/components/modules/blockManager.ts @@ -474,7 +474,7 @@ export default class BlockManager extends Module { const blockToMergeData = await blockToMerge.data; if (!_.isEmpty(blockToMergeData)) { - await targetBlock.mergeWith(blockToMergeData); + await targetBlock.mergeWith(blockToMergeData, targetBlock.name); } this.removeBlock(blockToMerge); diff --git a/src/components/tools/base.ts b/src/components/tools/base.ts index f89345a91..4b3a134b8 100644 --- a/src/components/tools/base.ts +++ b/src/components/tools/base.ts @@ -89,7 +89,9 @@ export enum InternalBlockToolSettings { /** * Tool paste config */ - PasteConfig = 'pasteConfig' + PasteConfig = 'pasteConfig', + + MergeableBlocks = 'mergeableBlocks' } /** diff --git a/src/components/tools/block.ts b/src/components/tools/block.ts index c5a0f337a..d557a32b1 100644 --- a/src/components/tools/block.ts +++ b/src/components/tools/block.ts @@ -35,7 +35,7 @@ export default class BlockTool extends BaseTool { /** * Tool's constructable blueprint */ - protected constructable: BlockToolConstructable; + public constructable: BlockToolConstructable; /** * Creates new Tool instance @@ -212,4 +212,11 @@ export default class BlockTool extends BaseTool { return baseConfig; } + + /** + * + */ + public get mergeableBlocks(): string[]|undefined { + return this.constructable[InternalBlockToolSettings.MergeableBlocks]; + } } diff --git a/src/components/utils/blocks.ts b/src/components/utils/blocks.ts index 92a802eef..dbe57dce6 100644 --- a/src/components/utils/blocks.ts +++ b/src/components/utils/blocks.ts @@ -14,6 +14,10 @@ import { isFunction, isString, log } from '../utils'; * @param blockToMerge - block to merge from */ export function areBlocksMergeable(targetBlock: Block, blockToMerge: Block): boolean { + if (blockToMerge.mergeableWithBlocks?.includes(targetBlock.name)) { + return true; + } + return targetBlock.mergeable && targetBlock.name === blockToMerge.name; } diff --git a/types/tools/block-tool.d.ts b/types/tools/block-tool.d.ts index 8c9bb858a..4bf673f81 100644 --- a/types/tools/block-tool.d.ts +++ b/types/tools/block-tool.d.ts @@ -12,6 +12,12 @@ import { TunesMenuConfig } from './tool-settings'; * @see {@link docs/tools.md} */ export interface BlockTool extends BaseTool { + + /** + * Block that can be merged with the block + */ + mergeableBlocks?: string[]; + /** * Sanitizer rules description */ @@ -40,8 +46,9 @@ export interface BlockTool extends BaseTool { * Method that specified how to merge two Blocks with same type. * Called by backspace at the beginning of the Block * @param {BlockToolData} blockData + * @param {string} type */ - merge?(blockData: BlockToolData): void; + merge?(blockData: BlockToolData, type: string): void; /** * On paste callback. Fired when pasted content can be substituted by a Tool @@ -92,6 +99,12 @@ export interface BlockToolConstructorOptions Date: Sat, 16 Dec 2023 22:41:22 +0100 Subject: [PATCH 02/16] fix: remove scope change --- src/components/tools/block.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/tools/block.ts b/src/components/tools/block.ts index d557a32b1..c2ec2f1b8 100644 --- a/src/components/tools/block.ts +++ b/src/components/tools/block.ts @@ -35,7 +35,7 @@ export default class BlockTool extends BaseTool { /** * Tool's constructable blueprint */ - public constructable: BlockToolConstructable; + protected constructable: BlockToolConstructable; /** * Creates new Tool instance From 810935b6094b0daf76486845a68ca130e9e2f670 Mon Sep 17 00:00:00 2001 From: GuillaumeOnepilot Date: Sat, 23 Dec 2023 15:14:59 +0100 Subject: [PATCH 03/16] feat: use convert config instead of defined property --- src/components/block/index.ts | 9 ++------- src/components/modules/blockManager.ts | 19 ++++++++++++++++++- src/components/tools/base.ts | 2 -- src/components/tools/block.ts | 7 ------- src/components/utils/blocks.ts | 5 ++++- types/tools/block-tool.d.ts | 11 ----------- 6 files changed, 24 insertions(+), 29 deletions(-) diff --git a/src/components/block/index.ts b/src/components/block/index.ts index 882dd39b4..a9034dfb4 100644 --- a/src/components/block/index.ts +++ b/src/components/block/index.ts @@ -389,6 +389,8 @@ export default class Block extends EventsDispatcher { * @returns {boolean} */ public get mergeable(): boolean { + console.log(this.toolInstance.merge); + return _.isFunction(this.toolInstance.merge); } @@ -995,11 +997,4 @@ export default class Block extends EventsDispatcher { private dropInputsCache(): void { this.cachedInputs = []; } - - /** - * Get the list of mergeable blocks with the current block - */ - public get mergeableWithBlocks(): string[]|undefined { - return this.tool.mergeableBlocks; - } } diff --git a/src/components/modules/blockManager.ts b/src/components/modules/blockManager.ts index 499008562..ecc4fc2bf 100644 --- a/src/components/modules/blockManager.ts +++ b/src/components/modules/blockManager.ts @@ -471,7 +471,24 @@ export default class BlockManager extends Module { * @returns {Promise} - the sequence that can be continued */ public async mergeBlocks(targetBlock: Block, blockToMerge: Block): Promise { - const blockToMergeData = await blockToMerge.data; + const data = await blockToMerge.data; + + const getBlockToolData = async (): Promise => { + const importConfig = targetBlock.tool.conversionConfig.import; + const exportConfig = blockToMerge.tool.conversionConfig.export; + + if (typeof importConfig === 'string') { + return { + [importConfig]: typeof exportConfig === 'string' ? data[exportConfig] : exportConfig(data), + }; + } + + return importConfig(await blockToMerge.exportDataAsString()); + }; + + const blockToMergeData = targetBlock.name !== blockToMerge.name + ? await getBlockToolData() + : data; if (!_.isEmpty(blockToMergeData)) { await targetBlock.mergeWith(blockToMergeData, targetBlock.name); diff --git a/src/components/tools/base.ts b/src/components/tools/base.ts index 4b3a134b8..ddfa7079c 100644 --- a/src/components/tools/base.ts +++ b/src/components/tools/base.ts @@ -90,8 +90,6 @@ export enum InternalBlockToolSettings { * Tool paste config */ PasteConfig = 'pasteConfig', - - MergeableBlocks = 'mergeableBlocks' } /** diff --git a/src/components/tools/block.ts b/src/components/tools/block.ts index c2ec2f1b8..c5a0f337a 100644 --- a/src/components/tools/block.ts +++ b/src/components/tools/block.ts @@ -212,11 +212,4 @@ export default class BlockTool extends BaseTool { return baseConfig; } - - /** - * - */ - public get mergeableBlocks(): string[]|undefined { - return this.constructable[InternalBlockToolSettings.MergeableBlocks]; - } } diff --git a/src/components/utils/blocks.ts b/src/components/utils/blocks.ts index dbe57dce6..f9219c13b 100644 --- a/src/components/utils/blocks.ts +++ b/src/components/utils/blocks.ts @@ -9,12 +9,15 @@ import { isFunction, isString, log } from '../utils'; * We can merge two blocks if: * - they have the same type * - they have a merge function (.mergeable = true) + * - If they have valid conversions config * * @param targetBlock - block to merge to * @param blockToMerge - block to merge from */ export function areBlocksMergeable(targetBlock: Block, blockToMerge: Block): boolean { - if (blockToMerge.mergeableWithBlocks?.includes(targetBlock.name)) { + if (blockToMerge.mergeable && + blockToMerge.tool.conversionConfig?.export !== undefined && + targetBlock.tool.conversionConfig?.import !== undefined) { return true; } diff --git a/types/tools/block-tool.d.ts b/types/tools/block-tool.d.ts index 4bf673f81..ea2642531 100644 --- a/types/tools/block-tool.d.ts +++ b/types/tools/block-tool.d.ts @@ -12,12 +12,6 @@ import { TunesMenuConfig } from './tool-settings'; * @see {@link docs/tools.md} */ export interface BlockTool extends BaseTool { - - /** - * Block that can be merged with the block - */ - mergeableBlocks?: string[]; - /** * Sanitizer rules description */ @@ -100,11 +94,6 @@ export interface BlockToolConstructorOptions Date: Sat, 23 Dec 2023 15:37:31 +0100 Subject: [PATCH 04/16] chore:: use built-in function for type check --- src/components/modules/blockManager.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/modules/blockManager.ts b/src/components/modules/blockManager.ts index ecc4fc2bf..db29d6d65 100644 --- a/src/components/modules/blockManager.ts +++ b/src/components/modules/blockManager.ts @@ -21,6 +21,7 @@ import { BlockChanged } from '../events'; import { clean } from '../utils/sanitizer'; import { convertStringToBlockData } from '../utils/blocks'; import PromiseQueue from '../utils/promise-queue'; +import { isString } from '../utils'; /** * @typedef {BlockManager} BlockManager @@ -477,9 +478,9 @@ export default class BlockManager extends Module { const importConfig = targetBlock.tool.conversionConfig.import; const exportConfig = blockToMerge.tool.conversionConfig.export; - if (typeof importConfig === 'string') { + if (isString(importConfig)) { return { - [importConfig]: typeof exportConfig === 'string' ? data[exportConfig] : exportConfig(data), + [importConfig]: isString(exportConfig) ? data[exportConfig] : exportConfig(data), }; } From f8460a2bccc41ac0a3d030f677e90c6cf6d551ee Mon Sep 17 00:00:00 2001 From: GuillaumeOnepilot Date: Sat, 23 Dec 2023 15:56:12 +0100 Subject: [PATCH 05/16] fix: remove console.log --- src/components/block/index.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/block/index.ts b/src/components/block/index.ts index a9034dfb4..c68d4eb7d 100644 --- a/src/components/block/index.ts +++ b/src/components/block/index.ts @@ -389,8 +389,6 @@ export default class Block extends EventsDispatcher { * @returns {boolean} */ public get mergeable(): boolean { - console.log(this.toolInstance.merge); - return _.isFunction(this.toolInstance.merge); } From 2074dd129200abd0164b48dbe88b18cc309fb3dc Mon Sep 17 00:00:00 2001 From: GuillaumeOnepilot Date: Sat, 23 Dec 2023 16:03:02 +0100 Subject: [PATCH 06/16] chore: remove styling added by mistakes --- src/components/tools/base.ts | 2 +- types/tools/block-tool.d.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/tools/base.ts b/src/components/tools/base.ts index ddfa7079c..f89345a91 100644 --- a/src/components/tools/base.ts +++ b/src/components/tools/base.ts @@ -89,7 +89,7 @@ export enum InternalBlockToolSettings { /** * Tool paste config */ - PasteConfig = 'pasteConfig', + PasteConfig = 'pasteConfig' } /** diff --git a/types/tools/block-tool.d.ts b/types/tools/block-tool.d.ts index ea2642531..9b0e3bf05 100644 --- a/types/tools/block-tool.d.ts +++ b/types/tools/block-tool.d.ts @@ -93,7 +93,6 @@ export interface BlockToolConstructorOptions Date: Sun, 24 Dec 2023 17:30:11 +0100 Subject: [PATCH 07/16] test: add testing for different blocks types merging --- test/cypress/fixtures/tools/SimpleHeader.ts | 89 +++++++++++++++++++ .../tests/modules/BlockEvents/Backspace.cy.ts | 44 +++++++++ 2 files changed, 133 insertions(+) create mode 100644 test/cypress/fixtures/tools/SimpleHeader.ts diff --git a/test/cypress/fixtures/tools/SimpleHeader.ts b/test/cypress/fixtures/tools/SimpleHeader.ts new file mode 100644 index 000000000..71696b706 --- /dev/null +++ b/test/cypress/fixtures/tools/SimpleHeader.ts @@ -0,0 +1,89 @@ +import { + BaseTool, + BlockToolConstructorOptions, + BlockToolData, + ConversionConfig +} from '../../../../types'; + +/** + * Simplified Header for testing + */ +export class SimpleHeader implements BaseTool { + private _data: BlockToolData; + private element: HTMLHeadingElement; + + /** + * + * @param options - constructor options + */ + constructor({ data }: BlockToolConstructorOptions) { + this._data = data; + } + + /** + * Return Tool's view + * + * @returns {HTMLHeadingElement} + * @public + */ + public render(): HTMLHeadingElement { + this.element = document.createElement('h1'); + + this.element.innerHTML = this._data.text; + + return this.element; + } + + /** + * @param data - saved data to merger with current block + */ + public merge(data: BlockToolData): void { + this.data = { + text: this.data.text + data.text, + level: this.data.level, + }; + } + + /** + * Extract Tool's data from the view + * + * @param toolsContent - Text tools rendered view + */ + public save(toolsContent: HTMLHeadingElement): BlockToolData { + return { + text: toolsContent.innerHTML, + level: 1, + }; + } + + /** + * Allow Header to be converted to/from other blocks + */ + public static get conversionConfig(): ConversionConfig { + return { + export: 'text', // use 'text' property for other blocks + import: 'text', // fill 'text' property from other block's export string + }; + } + + /** + * Data getter + */ + private get data(): BlockToolData { + this._data.text = this.element.innerHTML; + this._data.level = 1; + + return this._data; + } + + /** + * Data setter + */ + private set data(data: BlockToolData) { + this._data = data; + + if (data.text !== undefined) { + this.element.innerHTML = this._data.text || ''; + } + } +} diff --git a/test/cypress/tests/modules/BlockEvents/Backspace.cy.ts b/test/cypress/tests/modules/BlockEvents/Backspace.cy.ts index ac988a0b0..72f2ae1df 100644 --- a/test/cypress/tests/modules/BlockEvents/Backspace.cy.ts +++ b/test/cypress/tests/modules/BlockEvents/Backspace.cy.ts @@ -1,5 +1,7 @@ import type EditorJS from '../../../../../types/index'; import Chainable = Cypress.Chainable; +import Header from '../../../../../example/tools/header/dist/header.mjs'; +import { SimpleHeader } from '../../../fixtures/tools/SimpleHeader'; /** @@ -293,6 +295,48 @@ describe('Backspace keydown', function () { .should('not.have.class', 'ce-toolbar--opened'); }); + it('should merge different types of blocks if they valid conversion config', function () { + cy.createEditor({ + tools: { + header: SimpleHeader, + }, + data: { + blocks: [ + { + id: 'block1', + type: 'header', + data: { + text: 'First block heading', + }, + }, + { + id: 'block2', + type: 'paragraph', + data: { + text: 'Second block paragraph', + }, + }, + ], + }, + }).as('editorInstance'); + + cy.get('[data-cy=editorjs]') + .find('.ce-paragraph') + .last() + .click() + .type('{home}') // move caret to the beginning + .type('{backspace}'); + + cy.get('@editorInstance') + .then(async (editor) => { + const { blocks } = await editor.save(); + + expect(blocks.length).to.eq(1); // one block has been removed + expect(blocks[0].id).to.eq('block1'); // second block is still here + expect(blocks[0].data.text).to.eq('First block headingSecond block paragraph'); // text has been merged + }); + }); + it('should simply set Caret to the end of the previous Block if Caret at the start of the Block but Blocks are not mergeable. Also, should close the Toolbox.', function () { /** * Mock of tool without merge method From 63703a93d6cf923e858c5daedd39901f3fce7ed7 Mon Sep 17 00:00:00 2001 From: GuillaumeOnepilot Date: Sun, 24 Dec 2023 17:37:35 +0100 Subject: [PATCH 08/16] fix: remove unused import --- test/cypress/tests/modules/BlockEvents/Backspace.cy.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/test/cypress/tests/modules/BlockEvents/Backspace.cy.ts b/test/cypress/tests/modules/BlockEvents/Backspace.cy.ts index 72f2ae1df..5b5e29976 100644 --- a/test/cypress/tests/modules/BlockEvents/Backspace.cy.ts +++ b/test/cypress/tests/modules/BlockEvents/Backspace.cy.ts @@ -1,6 +1,5 @@ import type EditorJS from '../../../../../types/index'; import Chainable = Cypress.Chainable; -import Header from '../../../../../example/tools/header/dist/header.mjs'; import { SimpleHeader } from '../../../fixtures/tools/SimpleHeader'; From 887a2ecebd2819c4ca71b628773af26b46da2680 Mon Sep 17 00:00:00 2001 From: GuillaumeOnepilot Date: Sat, 23 Mar 2024 20:42:41 +0100 Subject: [PATCH 09/16] fix: remove type argument --- src/components/block/index.ts | 5 ++--- src/components/modules/blockManager.ts | 2 +- types/tools/block-tool.d.ts | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/components/block/index.ts b/src/components/block/index.ts index 4632e17d7..22c6dfa35 100644 --- a/src/components/block/index.ts +++ b/src/components/block/index.ts @@ -539,10 +539,9 @@ export default class Block extends EventsDispatcher { * Call plugins merge method * * @param {BlockToolData} data - data to merge - * @param {string} type - type of the block to merge */ - public async mergeWith(data: BlockToolData, type: string): Promise { - await this.toolInstance.merge(data, type); + public async mergeWith(data: BlockToolData): Promise { + this.toolInstance.merge(data); } /** diff --git a/src/components/modules/blockManager.ts b/src/components/modules/blockManager.ts index c4bcaebcb..cf7a1db1a 100644 --- a/src/components/modules/blockManager.ts +++ b/src/components/modules/blockManager.ts @@ -492,7 +492,7 @@ export default class BlockManager extends Module { : data; if (!_.isEmpty(blockToMergeData)) { - await targetBlock.mergeWith(blockToMergeData, targetBlock.name); + await targetBlock.mergeWith(blockToMergeData); } this.removeBlock(blockToMerge); diff --git a/types/tools/block-tool.d.ts b/types/tools/block-tool.d.ts index 9b0e3bf05..8c9bb858a 100644 --- a/types/tools/block-tool.d.ts +++ b/types/tools/block-tool.d.ts @@ -40,9 +40,8 @@ export interface BlockTool extends BaseTool { * Method that specified how to merge two Blocks with same type. * Called by backspace at the beginning of the Block * @param {BlockToolData} blockData - * @param {string} type */ - merge?(blockData: BlockToolData, type: string): void; + merge?(blockData: BlockToolData): void; /** * On paste callback. Fired when pasted content can be substituted by a Tool From b7a70426dfed1e3a835216426570f02428b29521 Mon Sep 17 00:00:00 2001 From: GuillaumeOnepilot Date: Sat, 23 Mar 2024 20:57:19 +0100 Subject: [PATCH 10/16] fix: use existing functions for data export --- src/components/modules/blockManager.ts | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/src/components/modules/blockManager.ts b/src/components/modules/blockManager.ts index cf7a1db1a..3b56753c7 100644 --- a/src/components/modules/blockManager.ts +++ b/src/components/modules/blockManager.ts @@ -21,7 +21,6 @@ import { BlockChanged } from '../events'; import { clean } from '../utils/sanitizer'; import { convertStringToBlockData } from '../utils/blocks'; import PromiseQueue from '../utils/promise-queue'; -import { isString } from '../utils'; /** * @typedef {BlockManager} BlockManager @@ -472,24 +471,12 @@ export default class BlockManager extends Module { * @returns {Promise} - the sequence that can be continued */ public async mergeBlocks(targetBlock: Block, blockToMerge: Block): Promise { - const data = await blockToMerge.data; - - const getBlockToolData = async (): Promise => { - const importConfig = targetBlock.tool.conversionConfig.import; - const exportConfig = blockToMerge.tool.conversionConfig.export; - - if (isString(importConfig)) { - return { - [importConfig]: isString(exportConfig) ? data[exportConfig] : exportConfig(data), - }; - } - - return importConfig(await blockToMerge.exportDataAsString()); - }; - const blockToMergeData = targetBlock.name !== blockToMerge.name - ? await getBlockToolData() - : data; + ? convertStringToBlockData( + await blockToMerge.exportDataAsString(), + targetBlock.tool.conversionConfig + ) + : await blockToMerge.data; if (!_.isEmpty(blockToMergeData)) { await targetBlock.mergeWith(blockToMergeData); From 58ba6735749eab6359791b4d3e1d5f9f058a8e91 Mon Sep 17 00:00:00 2001 From: GuillaumeOnepilot Date: Sat, 23 Mar 2024 21:01:52 +0100 Subject: [PATCH 11/16] chore: update changelog --- docs/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index a1b00479d..64ccef078 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,6 +2,7 @@ ### 2.30.0 +- `Improvement` — Ability to merge blocks with different types - `Fix` — `onChange` will be called when removing the entire text within a descendant element of a block. - `Fix` - Unexpected new line on Enter press with selected block without caret - `Fix` - Search input autofocus loosing after Block Tunes opening From f9718cae9b0e98c11ade38f9f27aaa66300cb3c9 Mon Sep 17 00:00:00 2001 From: GuillaumeOnepilot Date: Sat, 23 Mar 2024 22:19:16 +0100 Subject: [PATCH 12/16] fix: re put await --- src/components/block/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/block/index.ts b/src/components/block/index.ts index 89824257c..25e898f04 100644 --- a/src/components/block/index.ts +++ b/src/components/block/index.ts @@ -541,7 +541,7 @@ export default class Block extends EventsDispatcher { * @param {BlockToolData} data - data to merge */ public async mergeWith(data: BlockToolData): Promise { - this.toolInstance.merge(data); + await this.toolInstance.merge(data); } /** From 995d5eec6886d2a5d539a220118d19f3bf48794f Mon Sep 17 00:00:00 2001 From: GuillaumeOnepilot Date: Sat, 23 Mar 2024 22:20:38 +0100 Subject: [PATCH 13/16] fix: remove unnecessary check --- src/components/utils/blocks.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/utils/blocks.ts b/src/components/utils/blocks.ts index f9219c13b..360da5d68 100644 --- a/src/components/utils/blocks.ts +++ b/src/components/utils/blocks.ts @@ -15,8 +15,7 @@ import { isFunction, isString, log } from '../utils'; * @param blockToMerge - block to merge from */ export function areBlocksMergeable(targetBlock: Block, blockToMerge: Block): boolean { - if (blockToMerge.mergeable && - blockToMerge.tool.conversionConfig?.export !== undefined && + if (blockToMerge.tool.conversionConfig?.export !== undefined && targetBlock.tool.conversionConfig?.import !== undefined) { return true; } From 17059d0319c2fe09e8306046daf2170a4c0c0e29 Mon Sep 17 00:00:00 2001 From: GuillaumeOnepilot Date: Sat, 23 Mar 2024 22:21:02 +0100 Subject: [PATCH 14/16] fix: typo in test name --- test/cypress/tests/modules/BlockEvents/Backspace.cy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cypress/tests/modules/BlockEvents/Backspace.cy.ts b/test/cypress/tests/modules/BlockEvents/Backspace.cy.ts index 5b5e29976..c0ec8080e 100644 --- a/test/cypress/tests/modules/BlockEvents/Backspace.cy.ts +++ b/test/cypress/tests/modules/BlockEvents/Backspace.cy.ts @@ -294,7 +294,7 @@ describe('Backspace keydown', function () { .should('not.have.class', 'ce-toolbar--opened'); }); - it('should merge different types of blocks if they valid conversion config', function () { + it('should merge different types of blocks if they valid have a conversion config', function () { cy.createEditor({ tools: { header: SimpleHeader, From d59715b00d992e04ddbdb8950f5ee3f4e7b0b387 Mon Sep 17 00:00:00 2001 From: GuillaumeOnepilot Date: Sat, 23 Mar 2024 22:20:38 +0100 Subject: [PATCH 15/16] fix: re-add condition for merge --- src/components/utils/blocks.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/utils/blocks.ts b/src/components/utils/blocks.ts index 360da5d68..f9219c13b 100644 --- a/src/components/utils/blocks.ts +++ b/src/components/utils/blocks.ts @@ -15,7 +15,8 @@ import { isFunction, isString, log } from '../utils'; * @param blockToMerge - block to merge from */ export function areBlocksMergeable(targetBlock: Block, blockToMerge: Block): boolean { - if (blockToMerge.tool.conversionConfig?.export !== undefined && + if (blockToMerge.mergeable && + blockToMerge.tool.conversionConfig?.export !== undefined && targetBlock.tool.conversionConfig?.import !== undefined) { return true; } From f33445a12130d3598141adcd033e2199c75ee006 Mon Sep 17 00:00:00 2001 From: GuillaumeOnepilot Date: Wed, 27 Mar 2024 09:07:30 +0100 Subject: [PATCH 16/16] test: add caret position test --- .../tests/modules/BlockEvents/Backspace.cy.ts | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/test/cypress/tests/modules/BlockEvents/Backspace.cy.ts b/test/cypress/tests/modules/BlockEvents/Backspace.cy.ts index c0ec8080e..7deff30d2 100644 --- a/test/cypress/tests/modules/BlockEvents/Backspace.cy.ts +++ b/test/cypress/tests/modules/BlockEvents/Backspace.cy.ts @@ -294,7 +294,7 @@ describe('Backspace keydown', function () { .should('not.have.class', 'ce-toolbar--opened'); }); - it('should merge different types of blocks if they valid have a conversion config', function () { + it('should merge different types of blocks if they valid have a conversion config. Also, should close the Toolbox. Caret should be places in a place of glue', function () { cy.createEditor({ tools: { header: SimpleHeader, @@ -334,6 +334,30 @@ describe('Backspace keydown', function () { expect(blocks[0].id).to.eq('block1'); // second block is still here expect(blocks[0].data.text).to.eq('First block headingSecond block paragraph'); // text has been merged }); + + /** + * Caret is set to the place of merging + */ + cy.window() + .then((window) => { + const selection = window.getSelection(); + const range = selection.getRangeAt(0); + + cy.get('[data-cy=editorjs]') + .find('[data-cy=block-wrapper]') + .should(($block) => { + expect($block[0].contains(range.startContainer)).to.be.true; + range.startContainer.normalize(); // glue merged text nodes + expect(range.startOffset).to.be.eq('First block heading'.length); + }); + }); + + /** + * Toolbox has been closed + */ + cy.get('[data-cy=editorjs]') + .find('.ce-toolbar') + .should('not.have.class', 'ce-toolbar--opened'); }); it('should simply set Caret to the end of the previous Block if Caret at the start of the Block but Blocks are not mergeable. Also, should close the Toolbox.', function () {