Skip to content

Commit

Permalink
Merge branch 'next' into wrap-content
Browse files Browse the repository at this point in the history
  • Loading branch information
paescuj authored Oct 29, 2024
2 parents 46163c1 + 6313409 commit 7b3c213
Show file tree
Hide file tree
Showing 10 changed files with 199 additions and 17 deletions.
6 changes: 4 additions & 2 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
### 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

### 2.30.6

Expand Down Expand Up @@ -48,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.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@editorjs/editorjs",
"version": "2.31.0-rc.1",
"version": "2.31.0-rc.2",
"description": "Editor.js — open source block-style WYSIWYG editor with JSON output",
"main": "dist/editorjs.umd.js",
"module": "dist/editorjs.mjs",
Expand Down
2 changes: 1 addition & 1 deletion src/components/modules/blockManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
8 changes: 4 additions & 4 deletions src/components/ui/toolbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,23 +308,23 @@ export default class Toolbox extends EventsDispatcher<ToolboxEventMap> {
/**
* Maps tool data to popover item structure
*/
const toPopoverItem = (toolboxItem: ToolboxConfigEntry, tool: BlockToolAdapter): PopoverItemParams => {
const toPopoverItem = (toolboxItem: ToolboxConfigEntry, tool: BlockToolAdapter, displaySecondaryLabel = true): PopoverItemParams => {
return {
icon: toolboxItem.icon,
title: I18n.t(I18nInternalNS.toolNames, toolboxItem.title || _.capitalize(tool.name)),
name: tool.name,
onActivate: (): void => {
this.toolButtonActivated(tool.name, toolboxItem.data);
},
secondaryLabel: tool.shortcut ? _.beautifyShortcut(tool.shortcut) : '',
secondaryLabel: (tool.shortcut && displaySecondaryLabel) ? _.beautifyShortcut(tool.shortcut) : '',
};
};

return this.toolsToBeDisplayed
.reduce<PopoverItemParams[]>((result, tool) => {
if (Array.isArray(tool.toolbox)) {
tool.toolbox.forEach(item => {
result.push(toPopoverItem(item, tool));
tool.toolbox.forEach((item, index) => {
result.push(toPopoverItem(item, tool, index === 0));
});
} else if (tool.toolbox !== undefined) {
result.push(toPopoverItem(tool.toolbox, tool));
Expand Down
7 changes: 4 additions & 3 deletions src/components/utils/blocks.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion test/cypress/fixtures/tools/ToolMock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { BlockTool, BlockToolConstructorOptions } from '../../../../types';
/**
* Simple structure for Tool data
*/
interface MockToolData {
export interface MockToolData {
text: string;
}

Expand Down
83 changes: 81 additions & 2 deletions test/cypress/tests/api/blocks.cy.ts
Original file line number Diff line number Diff line change
@@ -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';

/**
Expand Down Expand Up @@ -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));
});
});
});
});
});
100 changes: 100 additions & 0 deletions test/cypress/tests/ui/toolbox.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,5 +114,105 @@ describe('Toolbox', function () {
expect(blocks[1].type).to.eq('nonConvertableTool');
});
});

it('should display shortcut only for the first toolbox item if tool exports toolbox with several items', function () {
/**
* Mock of Tool with conversionConfig
*/
class ToolWithSeveralToolboxItems extends ToolMock {
/**
* Specify toolbox with several items related to one tool
*/
public static get toolbox(): ToolboxConfig {
return [
{
icon: '',
title: 'first tool',
},
{
icon: '',
title: 'second tool',
},
];
}
}

cy.createEditor({
tools: {
severalToolboxItemsTool: {
class: ToolWithSeveralToolboxItems,
shortcut: 'CMD+SHIFT+L',
},
},
});

cy.get('[data-cy=editorjs]')
.find('.ce-paragraph')
.click()
.type('Some text')
.type('/'); // call a shortcut for toolbox

/**
* Secondary title (shortcut) should exist for first toolbox item of the tool
*/
/* eslint-disable-next-line cypress/require-data-selectors */
cy.get('.ce-popover')
.find('.ce-popover-item[data-item-name="severalToolboxItemsTool"]')
.first()
.find('.ce-popover-item__secondary-title')
.should('exist');

/**
* Secondary title (shortcut) should not exist for second toolbox item of the same tool
*/
/* eslint-disable-next-line cypress/require-data-selectors */
cy.get('.ce-popover')
.find('.ce-popover-item[data-item-name="severalToolboxItemsTool"]')
.eq(1)
.find('.ce-popover-item__secondary-title')
.should('not.exist');
});

it('should display shortcut for the item if tool exports toolbox as an one item object', function () {
/**
* Mock of Tool with conversionConfig
*/
class ToolWithOneToolboxItems extends ToolMock {
/**
* Specify toolbox with several items related to one tool
*/
public static get toolbox(): ToolboxConfig {
return {
icon: '',
title: 'tool',
};
}
}

cy.createEditor({
tools: {
oneToolboxItemTool: {
class: ToolWithOneToolboxItems,
shortcut: 'CMD+SHIFT+L',
},
},
});

cy.get('[data-cy=editorjs]')
.find('.ce-paragraph')
.click()
.type('Some text')
.type('/'); // call a shortcut for toolbox

/**
* Secondary title (shortcut) should exist for toolbox item of the tool
*/
/* eslint-disable-next-line cypress/require-data-selectors */
cy.get('.ce-popover')
.find('.ce-popover-item[data-item-name="oneToolboxItemTool"]')
.first()
.find('.ce-popover-item__secondary-title')
.should('exist');
});
});
});
4 changes: 2 additions & 2 deletions types/configs/conversion-config.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion types/tools/tool-settings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface ToolboxConfigEntry {
icon?: string;

/**
* May contain overrides for tool default config
* May contain overrides for tool default data
*/
data?: BlockToolData
}
Expand Down

0 comments on commit 7b3c213

Please sign in to comment.