Skip to content

Commit

Permalink
renderFromHTML API method (codex-team#654)
Browse files Browse the repository at this point in the history
* renderFromHTML API method

* Fix case when currentBlock is undefined

* Clear editor before render

* Handle single block processing

* Update paragraph
  • Loading branch information
gohabereg authored Mar 18, 2019
1 parent 6bd857d commit a47ffcc
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 45 deletions.
10 changes: 5 additions & 5 deletions dist/editor.js

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

### 2.12.0

- `New` *API* - new `blocks` API method `renderFromHTML`

### 2.11.11

- `New` — Add ability to pass configuration for internal Tools
Expand Down
4 changes: 4 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ export interface API {

Methods that working with Blocks

`render(data)` - render passed JSON data

`renderFromHTML(data)` - parse and render passed HTML string (*not for production use*)

`swap(fromIndex, toIndex)` - swaps two Blocks by their positions

`delete(blockIndex?: Number)` - deletes Block with passed index
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.11.11",
"version": "2.12.0",
"description": "Editor.js — Native JS, based on API and Open Source",
"main": "dist/editor.js",
"types": "./types/index.d.ts",
Expand Down
11 changes: 11 additions & 0 deletions src/components/modules/api/blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default class BlocksAPI extends Module {
return {
clear: () => this.clear(),
render: (data: OutputData) => this.render(data),
renderFromHTML: (data: string) => this.renderFromHTML(data),
delete: () => this.delete(),
swap: (fromIndex: number, toIndex: number) => this.swap(fromIndex, toIndex),
getBlockByIndex: (index: number) => this.getBlockByIndex(index),
Expand Down Expand Up @@ -113,6 +114,16 @@ export default class BlocksAPI extends Module {
return this.Editor.Renderer.render(data.blocks);
}

/**
* Render passed HTML string
* @param {string} data
* @return {Promise<void>}
*/
public renderFromHTML(data: string): Promise<void> {
this.Editor.BlockManager.clear();
return this.Editor.Paste.processText(data, true);
}

/**
* Stretch Block's content
* @param {number} index
Expand Down
84 changes: 45 additions & 39 deletions src/components/modules/paste.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,41 @@ export default class Paste extends Module {
}
}

/**
* Process pasted text and divide them into Blocks
*
* @param {string} data - text to process. Can be HTML or plain.
* @param {boolean} isHTML - if passed string is HTML, this parameter should be true
*/
public async processText(data: string, isHTML: boolean = false) {
const {Caret, BlockManager, Tools} = this.Editor;
const dataToInsert = isHTML ? this.processHTML(data) : this.processPlain(data);

if (!dataToInsert.length) {
return;
}

if (dataToInsert.length === 1) {
if (!dataToInsert[0].isBlock) {
this.processInlinePaste(dataToInsert.pop());
} else {
this.processSingleBlock(dataToInsert.pop());
}
return;
}

const isCurrentBlockInitial = BlockManager.currentBlock && Tools.isInitial(BlockManager.currentBlock.tool);
const needToReplaceCurrentBlock = isCurrentBlockInitial && BlockManager.currentBlock.isEmpty;

await Promise.all(dataToInsert.map(
async (content, i) => await this.insertBlock(content, i === 0 && needToReplaceCurrentBlock),
));

if (BlockManager.currentBlock) {
Caret.setToBlock(BlockManager.currentBlock, Caret.positions.END);
}
}

/**
* Set onPaste callback handler
*/
Expand Down Expand Up @@ -424,39 +459,6 @@ export default class Paste extends Module {
};
}

/**
* Process pasted text and divide them into Blocks
*
* @param {string} data - text to process. Can be HTML or plain.
* @param {boolean} isHTML - if passed string is HTML, this parameter should be true
*/
private async processText(data: string, isHTML: boolean = false) {
const {Caret, BlockManager, Tools} = this.Editor;
const dataToInsert = isHTML ? this.processHTML(data) : this.processPlain(data);

if (!dataToInsert.length) {
return;
}

if (dataToInsert.length === 1) {
if (!dataToInsert[0].isBlock) {
this.processInlinePaste(dataToInsert.pop());
} else {
this.processSingleBlock(dataToInsert.pop());
}
return;
}

const isCurrentBlockInitial = Tools.isInitial(BlockManager.currentBlock.tool);
const needToReplaceCurrentBlock = isCurrentBlockInitial && BlockManager.currentBlock.isEmpty;

await Promise.all(dataToInsert.map(
async (content, i) => await this.insertBlock(content, i === 0 && needToReplaceCurrentBlock),
));

Caret.setToBlock(BlockManager.currentBlock, Caret.positions.END);
}

/**
* Split HTML string to blocks and return it as array of Block data
*
Expand Down Expand Up @@ -558,8 +560,12 @@ export default class Paste extends Module {
/**
* If pasted tool isn`t equal current Block or if pasted content contains block elements, insert it as new Block
*/
if (dataToInsert.tool !== currentBlock.name || !$.containsOnlyInlineElements(dataToInsert.content.innerHTML)) {
this.insertBlock(dataToInsert, Tools.isInitial(currentBlock.tool) && currentBlock.isEmpty);
if (
!currentBlock ||
dataToInsert.tool !== currentBlock.name ||
!$.containsOnlyInlineElements(dataToInsert.content.innerHTML)
) {
this.insertBlock(dataToInsert, currentBlock && Tools.isInitial(currentBlock.tool) && currentBlock.isEmpty);
return;
}

Expand All @@ -578,7 +584,7 @@ export default class Paste extends Module {
const {BlockManager, Caret, Sanitizer, Tools} = this.Editor;
const {content, tool} = dataToInsert;

const currentBlockIsInitial = Tools.isInitial(BlockManager.currentBlock.tool);
const currentBlockIsInitial = BlockManager.currentBlock && Tools.isInitial(BlockManager.currentBlock.tool);

if (currentBlockIsInitial && content.textContent.length < Paste.PATTERN_PROCESSING_MAX_LENGTH) {
const blockData = await this.processPattern(content.textContent);
Expand All @@ -597,10 +603,10 @@ export default class Paste extends Module {
}
}

const currentToolSanitizeConfig = Sanitizer.getInlineToolsConfig(BlockManager.currentBlock.name);

/** If there is no pattern substitute - insert string as it is */
if (BlockManager.currentBlock.currentInput) {
if (BlockManager.currentBlock && BlockManager.currentBlock.currentInput) {
const currentToolSanitizeConfig = Sanitizer.getInlineToolsConfig(BlockManager.currentBlock.name);

document.execCommand('insertHTML', false, Sanitizer.clean(content.innerHTML, currentToolSanitizeConfig));
} else {
this.insertBlock(dataToInsert);
Expand Down
7 changes: 7 additions & 0 deletions types/api/blocks.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ export interface Blocks {
*/
render(data: OutputData): Promise<void>;

/**
* Render passed HTML string
* @param {string} data
* @return {Promise<void>}
*/
renderFromHTML(data: string): Promise<void>;

/**
* Removes current Block
*/
Expand Down

0 comments on commit a47ffcc

Please sign in to comment.