diff --git a/src/components/modules/api/blocks.ts b/src/components/modules/api/blocks.ts index 994f72adc..d3ec3bb65 100644 --- a/src/components/modules/api/blocks.ts +++ b/src/components/modules/api/blocks.ts @@ -228,15 +228,15 @@ export default class BlocksAPI extends Module { * @param {boolean?} needToFocus - flag to focus inserted Block * @param replace - pass true to replace the Block existed under passed index */ - public insert = ( + public insert = async ( type: string = this.config.defaultBlock, data: BlockToolData = {}, config: ToolConfig = {}, index?: number, needToFocus?: boolean, replace?: boolean - ): BlockAPIInterface => { - const insertedBlock = this.Editor.BlockManager.insert({ + ): Promise => { + const insertedBlock = await this.Editor.BlockManager.insert({ tool: type, data, index, @@ -267,7 +267,7 @@ export default class BlocksAPI extends Module { * @param id - id of the block to update * @param data - the new data */ - public update = (id: string, data: BlockToolData): void => { + public update = async (id: string, data: BlockToolData): Promise => { const { BlockManager } = this.Editor; const block = BlockManager.getBlockById(id); @@ -278,8 +278,7 @@ export default class BlocksAPI extends Module { } const blockIndex = BlockManager.getBlockIndex(block); - - BlockManager.insert({ + await BlockManager.insert({ id: block.id, tool: block.name, data, diff --git a/src/components/modules/blockEvents.ts b/src/components/modules/blockEvents.ts index 7fece2f49..e451cb8a0 100644 --- a/src/components/modules/blockEvents.ts +++ b/src/components/modules/blockEvents.ts @@ -191,13 +191,13 @@ export default class BlockEvents extends Module { return; } - BlockSelection.copySelectedBlocks(event).then(() => { + BlockSelection.copySelectedBlocks(event).then(async () => { const selectionPositionIndex = BlockManager.removeSelectedBlocks(); /** * Insert default block in place of removed ones */ - const insertedBlock = BlockManager.insertDefaultBlockAtIndex(selectionPositionIndex, true); + const insertedBlock = await BlockManager.insertDefaultBlockAtIndex(selectionPositionIndex, true); Caret.setToBlock(insertedBlock, Caret.positions.START); @@ -211,7 +211,7 @@ export default class BlockEvents extends Module { * * @param {KeyboardEvent} event - keydown */ - private enter(event: KeyboardEvent): void { + private async enter(event: KeyboardEvent): Promise { const { BlockManager, UI } = this.Editor; const currentBlock = BlockManager.currentBlock; @@ -250,7 +250,7 @@ export default class BlockEvents extends Module { * Split the Current Block into two blocks * Renew local current node after split */ - newCurrent = this.Editor.BlockManager.split(); + newCurrent = await this.Editor.BlockManager.split(); } this.Editor.Caret.setToBlock(newCurrent); diff --git a/src/components/modules/blockManager.ts b/src/components/modules/blockManager.ts index 9ac893bca..48d62be2e 100644 --- a/src/components/modules/blockManager.ts +++ b/src/components/modules/blockManager.ts @@ -15,6 +15,7 @@ import { BlockToolData, PasteEvent } from '../../../types'; import { BlockTuneData } from '../../../types/block-tunes/block-tune-data'; import BlockAPI from '../block/api'; import { BlockMutationType } from '../../../types/events/block/mutation-type'; +import BlockTool from '../tools/block'; /** * @typedef {BlockManager} BlockManager @@ -232,23 +233,23 @@ export default class BlockManager extends Module { * * @returns {Block} */ - public composeBlock({ + public async composeBlock({ tool: name, data = {}, id = undefined, tunes: tunesData = {}, - }: {tool: string; id?: string; data?: BlockToolData; tunes?: {[name: string]: BlockTuneData}}): Block { + }: { tool: string; id?: string; data?: BlockToolData; tunes?: { [name: string]: BlockTuneData } }): Promise { const readOnly = this.Editor.ReadOnly.isEnabled; const tool = this.Editor.Tools.blockTools.get(name); + const actialData = await this.composeBlockData(tool, data); const block = new Block({ id, - data, + data: actialData, tool, api: this.Editor.API, readOnly, tunesData, }); - if (!readOnly) { this.bindBlockEvents(block); } @@ -269,7 +270,7 @@ export default class BlockManager extends Module { * * @returns {Block} */ - public insert({ + public async insert({ id = undefined, tool = this.config.defaultBlock, data = {}, @@ -284,15 +285,14 @@ export default class BlockManager extends Module { index?: number; needToFocus?: boolean; replace?: boolean; - tunes?: {[name: string]: BlockTuneData}; - } = {}): Block { + tunes?: { [name: string]: BlockTuneData }; + } = {}): Promise { let newIndex = index; if (newIndex === undefined) { newIndex = this.currentBlockIndex + (replace ? 0 : 1); } - - const block = this.composeBlock({ + const block = await this.composeBlock({ id, tool, data, @@ -339,7 +339,7 @@ export default class BlockManager extends Module { public replace({ tool = this.config.defaultBlock, data = {}, - }): Block { + }): Promise { return this.insert({ tool, data, @@ -355,12 +355,12 @@ export default class BlockManager extends Module { * @param {PasteEvent} pasteEvent - pasted data * @param {boolean} replace - should replace current block */ - public paste( + public async paste( toolName: string, pasteEvent: PasteEvent, replace = false - ): Block { - const block = this.insert({ + ): Promise { + const block = await this.insert({ tool: toolName, replace, }); @@ -384,8 +384,8 @@ export default class BlockManager extends Module { * * @returns {Block} inserted Block */ - public insertDefaultBlockAtIndex(index: number, needToFocus = false): Block { - const block = this.composeBlock({ tool: this.config.defaultBlock }); + public async insertDefaultBlockAtIndex(index: number, needToFocus = false): Promise { + const block = await this.composeBlock({ tool: this.config.defaultBlock }); this._blocks[index] = block; @@ -410,7 +410,7 @@ export default class BlockManager extends Module { * * @returns {Block} */ - public insertAtEnd(): Block { + public insertAtEnd(): Promise { /** * Define new value for current block index */ @@ -534,7 +534,7 @@ export default class BlockManager extends Module { * * @returns {Block} */ - public split(): Block { + public split(): Promise { const extractedFragment = this.Editor.Caret.extractFragmentFromCaretPosition(); const wrapper = $.make('div'); @@ -881,4 +881,24 @@ export default class BlockManager extends Module { return block; } + + /** + * Retrieves default block data by creating fake block. + * Merges retrieved data with specified data object. + * + * @param tool - block's tool + * @param dataOverrides - object containing overrides for default block data + */ + private async composeBlockData(tool: BlockTool, dataOverrides = {}): Promise { + const block = new Block({ + tool, + api: this.Editor.API, + readOnly: true, + data: {}, + tunesData: {}, + }); + const blockData = await block.data; + + return Object.assign(blockData, dataOverrides); + } } diff --git a/src/components/modules/caret.ts b/src/components/modules/caret.ts index 94b54711a..2dc51a734 100644 --- a/src/components/modules/caret.ts +++ b/src/components/modules/caret.ts @@ -336,9 +336,9 @@ export default class Caret extends Module { if (lastBlock.tool.isDefault && lastBlock.isEmpty) { this.setToBlock(lastBlock); } else { - const newBlock = this.Editor.BlockManager.insertAtEnd(); - - this.setToBlock(newBlock); + this.Editor.BlockManager.insertAtEnd().then(newBlock => { + this.setToBlock(newBlock); + }); } } @@ -390,7 +390,7 @@ export default class Caret extends Module { * * @returns {boolean} */ - public navigateNext(): boolean { + public async navigateNext(): Promise { const { BlockManager } = this.Editor; const { currentBlock, nextContentfulBlock } = BlockManager; const { nextInput } = currentBlock; @@ -417,7 +417,7 @@ export default class Caret extends Module { * If there is no nextBlock, but currentBlock is not default, * insert new default block at the end and navigate to it */ - nextBlock = BlockManager.insertAtEnd(); + nextBlock = await BlockManager.insertAtEnd(); } if (isAtEnd) { diff --git a/src/components/modules/paste.ts b/src/components/modules/paste.ts index e901897b6..ac403d3dc 100644 --- a/src/components/modules/paste.ts +++ b/src/components/modules/paste.ts @@ -6,7 +6,6 @@ import { PasteEvent, PasteEventDetail } from '../../../types'; -import Block from '../block'; import { SavedData } from '../../../types/data-formats'; import { clean, sanitizeBlocks } from '../utils/sanitizer'; import BlockTool from '../tools/block'; @@ -112,12 +111,12 @@ export default class Paste extends Module { /** * Tags` substitutions parameters */ - private toolsTags: {[tag: string]: TagSubstitute} = {}; + private toolsTags: { [tag: string]: TagSubstitute } = {}; /** * Store tags to substitute by tool name */ - private tagsByTool: {[tools: string]: string[]} = {}; + private tagsByTool: { [tools: string]: string[] } = {}; /** Patterns` substitutions parameters */ private toolsPatterns: PatternSubstitute[] = []; @@ -186,7 +185,7 @@ export default class Paste extends Module { this.insertEditorJSData(JSON.parse(editorJSData)); return; - } catch (e) {} // Do nothing and continue execution as usual if error appears + } catch (e) { } // Do nothing and continue execution as usual if error appears } /** @@ -449,7 +448,7 @@ export default class Paste extends Module { private async processFiles(items: FileList): Promise { const { BlockManager } = this.Editor; - let dataToInsert: {type: string; event: PasteEvent}[]; + let dataToInsert: { type: string; event: PasteEvent }[]; dataToInsert = await Promise.all( Array @@ -473,7 +472,7 @@ export default class Paste extends Module { * * @param {File} file - file to process */ - private async processFile(file: File): Promise<{event: PasteEvent; type: string}> { + private async processFile(file: File): Promise<{ event: PasteEvent; type: string }> { const extension = _.getFileExtension(file); const foundConfig = Object @@ -576,7 +575,7 @@ export default class Paste extends Module { * @returns {PasteData[]} */ private processPlain(plain: string): PasteData[] { - const { defaultBlock } = this.config as {defaultBlock: string}; + const { defaultBlock } = this.config as { defaultBlock: string }; if (!plain) { return []; @@ -652,9 +651,9 @@ export default class Paste extends Module { BlockManager.currentBlock.tool.isDefault && BlockManager.currentBlock.isEmpty; - const insertedBlock = BlockManager.paste(blockData.tool, blockData.event, needToReplaceCurrentBlock); - - Caret.setToBlock(insertedBlock, Caret.positions.END); + BlockManager.paste(blockData.tool, blockData.event, needToReplaceCurrentBlock).then(insertedBlock => { + Caret.setToBlock(insertedBlock, Caret.positions.END); + }); return; } @@ -681,7 +680,7 @@ export default class Paste extends Module { * * @returns {Promise<{event: PasteEvent, tool: string}>} */ - private async processPattern(text: string): Promise<{event: PasteEvent; tool: string}> { + private async processPattern(text: string): Promise<{ event: PasteEvent; tool: string }> { const pattern = this.toolsPatterns.find((substitute) => { const execResult = substitute.pattern.exec(text); @@ -718,18 +717,16 @@ export default class Paste extends Module { private insertBlock(data: PasteData, canReplaceCurrentBlock = false): void { const { BlockManager, Caret } = this.Editor; const { currentBlock } = BlockManager; - let block: Block; if (canReplaceCurrentBlock && currentBlock && currentBlock.isEmpty) { - block = BlockManager.paste(data.tool, data.event, true); - Caret.setToBlock(block, Caret.positions.END); - - return; + BlockManager.paste(data.tool, data.event, true).then(block => { + Caret.setToBlock(block, Caret.positions.END); + }); + } else { + BlockManager.paste(data.tool, data.event).then(block => { + Caret.setToBlock(block, Caret.positions.END); + }); } - - block = BlockManager.paste(data.tool, data.event); - - Caret.setToBlock(block, Caret.positions.END); } /** @@ -754,13 +751,13 @@ export default class Paste extends Module { needToReplaceCurrentBlock = isCurrentBlockDefault && BlockManager.currentBlock.isEmpty; } - const block = BlockManager.insert({ + BlockManager.insert({ tool, data, replace: needToReplaceCurrentBlock, + }).then(block => { + Caret.setToBlock(block, Caret.positions.END); }); - - Caret.setToBlock(block, Caret.positions.END); }); } diff --git a/src/components/modules/renderer.ts b/src/components/modules/renderer.ts index 6f800069b..fab5be724 100644 --- a/src/components/modules/renderer.ts +++ b/src/components/modules/renderer.ts @@ -77,7 +77,7 @@ export default class Renderer extends Module { if (Tools.available.has(tool)) { try { - BlockManager.insert({ + await BlockManager.insert({ id, tool, data, @@ -105,12 +105,11 @@ export default class Renderer extends Module { stubData.title = toolboxTitle || stubData.title; } - const stub = BlockManager.insert({ + const stub = await BlockManager.insert({ id, tool: Tools.stubTool, data: stubData, - }); - + }) stub.stretched = true; _.log(`Tool «${tool}» is not found. Check 'tools' property at your initial Editor.js config.`, 'warn'); diff --git a/src/components/modules/ui.ts b/src/components/modules/ui.ts index ead5c9ba3..7ba4aa863 100644 --- a/src/components/modules/ui.ts +++ b/src/components/modules/ui.ts @@ -514,19 +514,21 @@ export default class UI extends Module { if (BlockSelection.anyBlockSelected && !Selection.isSelectionExists) { const selectionPositionIndex = BlockManager.removeSelectedBlocks(); - Caret.setToBlock(BlockManager.insertDefaultBlockAtIndex(selectionPositionIndex, true), Caret.positions.START); - - /** Clear selection */ - BlockSelection.clearSelection(event); - - /** - * Stop propagations - * Manipulation with BlockSelections is handled in global backspacePress because they may occur - * with CMD+A or RectangleSelection and they can be handled on document event - */ - event.preventDefault(); - event.stopPropagation(); - event.stopImmediatePropagation(); + BlockManager.insertDefaultBlockAtIndex(selectionPositionIndex, true).then(block => { + Caret.setToBlock(block, Caret.positions.START); + + /** Clear selection */ + BlockSelection.clearSelection(event); + + /** + * Stop propagations + * Manipulation with BlockSelections is handled in global backspacePress because they may occur + * with CMD+A or RectangleSelection and they can be handled on document event + */ + event.preventDefault(); + event.stopPropagation(); + event.stopImmediatePropagation(); + }); } } @@ -596,19 +598,19 @@ export default class UI extends Module { /** * Insert the default typed Block */ - const newBlock = this.Editor.BlockManager.insert(); - - this.Editor.Caret.setToBlock(newBlock); - - /** - * And highlight - */ - this.Editor.BlockManager.highlightCurrentNode(); - - /** - * Move toolbar and show plus button because new Block is empty - */ - this.Editor.Toolbar.moveAndOpen(newBlock); + this.Editor.BlockManager.insert().then(newBlock => { + this.Editor.Caret.setToBlock(newBlock); + + /** + * And highlight + */ + this.Editor.BlockManager.highlightCurrentNode(); + + /** + * Move toolbar and show plus button because new Block is empty + */ + this.Editor.Toolbar.moveAndOpen(newBlock); + }); } this.Editor.BlockSelection.clearSelection(event); diff --git a/src/components/ui/toolbox.ts b/src/components/ui/toolbox.ts index ad4e84147..a364129cc 100644 --- a/src/components/ui/toolbox.ts +++ b/src/components/ui/toolbox.ts @@ -379,7 +379,7 @@ export default class Toolbox extends EventsDispatcher { * @param {string} toolName - Tool name * @param blockDataOverrides - predefined Block data */ - private insertNewBlock(toolName: string, blockDataOverrides?: BlockToolData): void { + private async insertNewBlock(toolName: string, blockDataOverrides?: BlockToolData): Promise { const currentBlockIndex = this.api.blocks.getCurrentBlockIndex(); const currentBlock = this.api.blocks.getBlockByIndex(currentBlockIndex); @@ -393,7 +393,7 @@ export default class Toolbox extends EventsDispatcher { */ const index = currentBlock.isEmpty ? currentBlockIndex : currentBlockIndex + 1; - const newBlock = this.api.blocks.insert( + const newBlock = await this.api.blocks.insert( toolName, blockDataOverrides, undefined, diff --git a/test/cypress/tests/api/blocks.spec.ts b/test/cypress/tests/api/blocks.spec.ts index 7eb748698..a51119261 100644 --- a/test/cypress/tests/api/blocks.spec.ts +++ b/test/cypress/tests/api/blocks.spec.ts @@ -65,8 +65,7 @@ describe('api.blocks', () => { const newBlockData = { text: 'Updated text', }; - - editor.blocks.update(idToUpdate, newBlockData); + await editor.blocks.update(idToUpdate, newBlockData); cy.get('[data-cy=editorjs]') .get('div.ce-block') @@ -86,12 +85,10 @@ describe('api.blocks', () => { const newBlockData = { text: 'Updated text', }; - - editor.blocks.update(idToUpdate, newBlockData); + await editor.blocks.update(idToUpdate, newBlockData); const output = await (editor as any).save(); const text = output.blocks[0].data.text; - expect(text).to.be.eq(newBlockData.text); }); }); diff --git a/types/api/blocks.d.ts b/types/api/blocks.d.ts index bd7ca41d9..b94e0d730 100644 --- a/types/api/blocks.d.ts +++ b/types/api/blocks.d.ts @@ -110,7 +110,7 @@ export interface Blocks { index?: number, needToFocus?: boolean, replace?: boolean, - ): BlockAPI; + ): Promise; /** @@ -119,5 +119,5 @@ export interface Blocks { * @param id - id of the block to update * @param data - the new data */ - update(id: string, data: BlockToolData): void; + update(id: string, data: BlockToolData): Promise; }