mirror of
https://github.com/codex-team/editor.js
synced 2024-06-29 02:40:23 +02:00
[Feature] BlockAPI Interface (#1075)
This commit is contained in:
parent
7c3bf76050
commit
ffe5bbc8fc
2
dist/editor.js
vendored
2
dist/editor.js
vendored
File diff suppressed because one or more lines are too long
|
@ -3,6 +3,7 @@
|
||||||
### 2.18
|
### 2.18
|
||||||
|
|
||||||
- `New` *I18n API* — Ability to provide internalization for Editor.js core and tools. [#751](https://github.com/codex-team/editor.js/issues/751)
|
- `New` *I18n API* — Ability to provide internalization for Editor.js core and tools. [#751](https://github.com/codex-team/editor.js/issues/751)
|
||||||
|
- `New` — Block API that allows you to access certain Block properties and methods
|
||||||
- `Improvements` - TSLint (deprecated) replaced with ESLint, old config changed to [CodeX ESLint Config](https://github.com/codex-team/eslint-config).
|
- `Improvements` - TSLint (deprecated) replaced with ESLint, old config changed to [CodeX ESLint Config](https://github.com/codex-team/eslint-config).
|
||||||
- `Improvements` - Fix many code-style issues, add missed annotations.
|
- `Improvements` - Fix many code-style issues, add missed annotations.
|
||||||
- `Improvements` - Adjusted GitHub action for ESLint.
|
- `Improvements` - Adjusted GitHub action for ESLint.
|
||||||
|
@ -20,6 +21,9 @@
|
||||||
- `Fix` - Public getter `shortcut` now works for Inline Tools [#1132](https://github.com/codex-team/editor.js/issues/1132)
|
- `Fix` - Public getter `shortcut` now works for Inline Tools [#1132](https://github.com/codex-team/editor.js/issues/1132)
|
||||||
- `Fix` - `CMD+A` handler removed after Editor.js destroy [#1133](https://github.com/codex-team/editor.js/issues/1133)
|
- `Fix` - `CMD+A` handler removed after Editor.js destroy [#1133](https://github.com/codex-team/editor.js/issues/1133)
|
||||||
|
|
||||||
|
> *Breaking changes* `blocks.getBlockByIndex` method now returns BlockAPI object. To access old value, use BlockAPI.holder property
|
||||||
|
|
||||||
|
|
||||||
### 2.17
|
### 2.17
|
||||||
|
|
||||||
- `Improvements` - Editor's [onchange callback](https://editorjs.io/configuration#editor-modifications-callback) now accepts an API as a parameter
|
- `Improvements` - Editor's [onchange callback](https://editorjs.io/configuration#editor-modifications-callback) now accepts an API as a parameter
|
||||||
|
|
30
docs/api.md
30
docs/api.md
|
@ -8,9 +8,33 @@ Most actual API described by [this interface](../types/api/index.d.ts).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Blocks have access to the public methods provided by Editor.js API Module. Plugin and Tune Developers
|
Tools have access to the public methods provided by Editor.js API Module. Plugin and Tune Developers
|
||||||
can use Editor\`s API as they want.
|
can use Editor\`s API as they want.
|
||||||
|
|
||||||
|
## Block API
|
||||||
|
|
||||||
|
API for certain Block methods and properties. You can access it through `editor.api.block.getBlockByIndex` method or get it form `block` property of [Tool constructor](../types/tools/block-tool.d.ts) argument.
|
||||||
|
|
||||||
|
`name: string` — Block's Tool name (key, specified in `tools` property of initial configuration)
|
||||||
|
|
||||||
|
`config: ToolConfig` — Tool config passed on Editor initialization
|
||||||
|
|
||||||
|
`holder: HTMLElement` — HTML Element that wraps Tool's HTML content
|
||||||
|
|
||||||
|
`isEmpty: boolean` — `true` if Block has any editable content
|
||||||
|
|
||||||
|
`selected: boolean` - `true` if Block is selected with Cross-Block Selection
|
||||||
|
|
||||||
|
`set stretched(state: boolean)` — set Block's stretch state
|
||||||
|
|
||||||
|
`stretched: boolean` — `true` if Block is stretched
|
||||||
|
|
||||||
|
`call(methodName: string, param?: object): void` — method to call any Tool's instance methods with checks and error handlers under-the-hood. For example, [Block lifecycle hooks](./tools.md#block-lifecycle-hooks)
|
||||||
|
|
||||||
|
`save(): Promise<void|SavedData>` — returns data saved from current Block's state, including Tool name and saving exec time
|
||||||
|
|
||||||
|
`validate(data: BlockToolData): Promise<boolean>` — calls Tool's validate method if exists
|
||||||
|
|
||||||
## Api object description
|
## Api object description
|
||||||
|
|
||||||
Common API interface.
|
Common API interface.
|
||||||
|
@ -43,11 +67,11 @@ use 'move' instead)
|
||||||
|
|
||||||
`getCurrentBlockIndex()` - current Block index
|
`getCurrentBlockIndex()` - current Block index
|
||||||
|
|
||||||
`getBlockByIndex(index: Number)` - returns Block with passed index
|
`getBlockByIndex(index: Number)` - returns Block API object by passed index
|
||||||
|
|
||||||
`getBlocksCount()` - returns Blocks count
|
`getBlocksCount()` - returns Blocks count
|
||||||
|
|
||||||
`stretchBlock(index: number, status: boolean)` - make Block stretched
|
`stretchBlock(index: number, status: boolean)` - _Deprecated. Use Block API interface instead._ make Block stretched.
|
||||||
|
|
||||||
`insertNewBlock()` - __Deprecated__ insert new Block after working place
|
`insertNewBlock()` - __Deprecated__ insert new Block after working place
|
||||||
|
|
||||||
|
|
|
@ -12,11 +12,12 @@ Each Tool should have an installation guide.
|
||||||
|
|
||||||
Each Tool's instance called with an params object.
|
Each Tool's instance called with an params object.
|
||||||
|
|
||||||
| Param | Type | Description |
|
| Param | Type | Description |
|
||||||
| ------ | ------------------- | ----------------------------------------------- |
|
| ------ | ------------------------------------------------------ | ----------------------------------------------- |
|
||||||
| api | [`IAPI`][iapi-link] | Editor.js's API methods |
|
| api | [`IAPI`](../types/index.d.ts) | Editor.js's API methods |
|
||||||
| config | `object` | Special configuration params passed in «config» |
|
| config | [`ToolConfig`](../types/tools/tool-config.d.ts) | Special configuration params passed in «config» |
|
||||||
| data | `object` | Data to be rendered in this Tool |
|
| data | [`BlockToolData`](../types/tools/block-tool-data.d.ts) | Data to be rendered in this Tool |
|
||||||
|
| block | [`BlockAPI`](../types/api/block.d.ts) | Block's API methods |
|
||||||
|
|
||||||
[iapi-link]: ../src/types-internal/api.ts
|
[iapi-link]: ../src/types-internal/api.ts
|
||||||
|
|
||||||
|
@ -228,14 +229,14 @@ onPaste (event) {
|
||||||
|
|
||||||
### Disable paste handling
|
### Disable paste handling
|
||||||
|
|
||||||
If you need to disable paste handling on your Tool for some reason, you can provide `false` as `pasteConfig` value.
|
If you need to disable paste handling on your Tool for some reason, you can provide `false` as `pasteConfig` value.
|
||||||
That way paste event won't be processed if fired on your Tool:
|
That way paste event won't be processed if fired on your Tool:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
static get pasteConfig {
|
static get pasteConfig {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Sanitize <a name="sanitize"></a>
|
## Sanitize <a name="sanitize"></a>
|
||||||
|
|
||||||
|
@ -364,7 +365,7 @@ Editor.js has a Conversion Toolbar that allows user to convert one Block to anot
|
||||||
2. You can add ability to convert other Tools to your Tool. Specify «import» property of `conversionConfig`.
|
2. You can add ability to convert other Tools to your Tool. Specify «import» property of `conversionConfig`.
|
||||||
|
|
||||||
Conversion Toolbar will be shown only near Blocks that specified an «export» rule, when user selected almost all block's content.
|
Conversion Toolbar will be shown only near Blocks that specified an «export» rule, when user selected almost all block's content.
|
||||||
This Toolbar will contain only Tools that specified an «import» rule.
|
This Toolbar will contain only Tools that specified an «import» rule.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -391,11 +392,11 @@ class Header {
|
||||||
|
|
||||||
### Your Tool -> other Tool
|
### Your Tool -> other Tool
|
||||||
|
|
||||||
The «export» field specifies how to represent your Tool's data as a string to pass it to other tool.
|
The «export» field specifies how to represent your Tool's data as a string to pass it to other tool.
|
||||||
|
|
||||||
It can be a `String` or a `Function`.
|
It can be a `String` or a `Function`.
|
||||||
|
|
||||||
`String` means a key of your Tool data object that should be used as string to export.
|
`String` means a key of your Tool data object that should be used as string to export.
|
||||||
|
|
||||||
`Function` is a method that accepts your Tool data and compose a string to export from it. See example below:
|
`Function` is a method that accepts your Tool data and compose a string to export from it. See example below:
|
||||||
|
|
||||||
|
@ -411,7 +412,7 @@ class ListTool {
|
||||||
type: 'ordered'
|
type: 'ordered'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get conversionConfig() {
|
static get conversionConfig() {
|
||||||
return {
|
return {
|
||||||
export: (data) => {
|
export: (data) => {
|
||||||
|
@ -425,11 +426,11 @@ class ListTool {
|
||||||
|
|
||||||
### Other Tool -> your Tool
|
### Other Tool -> your Tool
|
||||||
|
|
||||||
The «import» rule specifies how to create your Tool's data object from the string created by original block.
|
The «import» rule specifies how to create your Tool's data object from the string created by original block.
|
||||||
|
|
||||||
It can be a `String` or a `Function`.
|
It can be a `String` or a `Function`.
|
||||||
|
|
||||||
`String` means the key in tool data that will be filled by an exported string.
|
`String` means the key in tool data that will be filled by an exported string.
|
||||||
For example, `import: 'text'` means that `constructor` of your block will accept a `data` object with `text` property filled with string composed by original block.
|
For example, `import: 'text'` means that `constructor` of your block will accept a `data` object with `text` property filled with string composed by original block.
|
||||||
|
|
||||||
`Function` allows you to specify own logic, how a string should be converted to your tool data. For example:
|
`Function` allows you to specify own logic, how a string should be converted to your tool data. For example:
|
||||||
|
@ -442,13 +443,13 @@ class ListTool {
|
||||||
type: 'unordered'
|
type: 'unordered'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get conversionConfig() {
|
static get conversionConfig() {
|
||||||
return {
|
return {
|
||||||
// ... export rule
|
// ... export rule
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In this example, List Tool creates items by splitting original text by a dot symbol.
|
* In this example, List Tool creates items by splitting original text by a dot symbol.
|
||||||
*/
|
*/
|
||||||
import: (string) => {
|
import: (string) => {
|
||||||
const items = string.split('.');
|
const items = string.split('.');
|
||||||
|
|
|
@ -83,7 +83,8 @@ export default class MoveDownTune implements BlockTune {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nextBlockElement = this.api.blocks.getBlockByIndex(currentBlockIndex + 1);
|
const nextBlock = this.api.blocks.getBlockByIndex(currentBlockIndex + 1);
|
||||||
|
const nextBlockElement = nextBlock.holder;
|
||||||
const nextBlockCoords = nextBlockElement.getBoundingClientRect();
|
const nextBlockCoords = nextBlockElement.getBoundingClientRect();
|
||||||
|
|
||||||
let scrollOffset = Math.abs(window.innerHeight - nextBlockElement.offsetHeight);
|
let scrollOffset = Math.abs(window.innerHeight - nextBlockElement.offsetHeight);
|
||||||
|
|
|
@ -81,8 +81,10 @@ export default class MoveUpTune implements BlockTune {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentBlockElement = this.api.blocks.getBlockByIndex(currentBlockIndex);
|
const currentBlock = this.api.blocks.getBlockByIndex(currentBlockIndex);
|
||||||
const previousBlockElement = this.api.blocks.getBlockByIndex(currentBlockIndex - 1);
|
const currentBlockElement = currentBlock.holder;
|
||||||
|
const previousBlock = this.api.blocks.getBlockByIndex(currentBlockIndex - 1);
|
||||||
|
const previousBlockElement = previousBlock.holder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Here is two cases:
|
* Here is two cases:
|
||||||
|
|
114
src/components/block/api.ts
Normal file
114
src/components/block/api.ts
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
import Block from './index';
|
||||||
|
import { BlockToolData, ToolConfig } from '../../../types/tools';
|
||||||
|
import { SavedData } from '../../types-internal/block-data';
|
||||||
|
import { BlockAPI as BlockAPIInterface } from '../../../types/api';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs new BlockAPI object
|
||||||
|
*
|
||||||
|
* @class
|
||||||
|
*
|
||||||
|
* @param {Block} block - Block to expose
|
||||||
|
*/
|
||||||
|
function BlockAPI(block: Block): void {
|
||||||
|
const blockAPI: BlockAPIInterface = {
|
||||||
|
/**
|
||||||
|
* Tool name
|
||||||
|
*
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
get name(): string {
|
||||||
|
return block.name;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tool config passed on Editor's initialization
|
||||||
|
*
|
||||||
|
* @returns {ToolConfig}
|
||||||
|
*/
|
||||||
|
get config(): ToolConfig {
|
||||||
|
return block.config;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* .ce-block element, that wraps plugin contents
|
||||||
|
*
|
||||||
|
* @returns {HTMLElement}
|
||||||
|
*/
|
||||||
|
get holder(): HTMLElement {
|
||||||
|
return block.holder;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if Block content is empty
|
||||||
|
*
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
get isEmpty(): boolean {
|
||||||
|
return block.isEmpty;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if Block is selected with Cross-Block selection
|
||||||
|
*
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
get selected(): boolean {
|
||||||
|
return block.selected;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Block's stretch state
|
||||||
|
*
|
||||||
|
* @param {boolean} state — state to set
|
||||||
|
*/
|
||||||
|
set stretched(state: boolean) {
|
||||||
|
block.stretched = state;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if Block is stretched
|
||||||
|
*
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
get stretched(): boolean {
|
||||||
|
return block.stretched;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call Tool method with errors handler under-the-hood
|
||||||
|
*
|
||||||
|
* @param {string} methodName - method to call
|
||||||
|
* @param {object} param - object with parameters
|
||||||
|
*
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
call(methodName: string, param?: object): void {
|
||||||
|
block.call(methodName, param);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save Block content
|
||||||
|
*
|
||||||
|
* @returns {Promise<void|SavedData>}
|
||||||
|
*/
|
||||||
|
save(): Promise<void|SavedData> {
|
||||||
|
return block.save();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate Block data
|
||||||
|
*
|
||||||
|
* @param {BlockToolData} data - data to validate
|
||||||
|
*
|
||||||
|
* @returns {Promise<boolean>}
|
||||||
|
*/
|
||||||
|
validate(data: BlockToolData): Promise<boolean> {
|
||||||
|
return block.validate(data);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.setPrototypeOf(this, blockAPI);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BlockAPI;
|
|
@ -1,23 +1,57 @@
|
||||||
import {
|
import {
|
||||||
|
BlockAPI as BlockAPIInterface,
|
||||||
BlockTool,
|
BlockTool,
|
||||||
BlockToolConstructable,
|
BlockToolConstructable,
|
||||||
BlockToolData,
|
BlockToolData,
|
||||||
BlockTune,
|
BlockTune,
|
||||||
BlockTuneConstructable,
|
BlockTuneConstructable,
|
||||||
SanitizerConfig,
|
SanitizerConfig,
|
||||||
ToolConfig
|
ToolConfig,
|
||||||
} from '../../types';
|
ToolSettings
|
||||||
|
} from '../../../types';
|
||||||
|
|
||||||
|
import { SavedData } from '../../types-internal/block-data';
|
||||||
|
import $ from '../dom';
|
||||||
|
import * as _ from '../utils';
|
||||||
|
import ApiModule from '../modules/api';
|
||||||
|
import SelectionUtils from '../selection';
|
||||||
|
import BlockAPI from './api';
|
||||||
|
import { ToolType } from '../modules/tools';
|
||||||
|
|
||||||
import { SavedData } from '../types-internal/block-data';
|
|
||||||
import $ from './dom';
|
|
||||||
import * as _ from './utils';
|
|
||||||
import ApiModule from './../components/modules/api';
|
|
||||||
/** Import default tunes */
|
/** Import default tunes */
|
||||||
import MoveUpTune from './block-tunes/block-tune-move-up';
|
import MoveUpTune from '../block-tunes/block-tune-move-up';
|
||||||
import DeleteTune from './block-tunes/block-tune-delete';
|
import DeleteTune from '../block-tunes/block-tune-delete';
|
||||||
import MoveDownTune from './block-tunes/block-tune-move-down';
|
import MoveDownTune from '../block-tunes/block-tune-move-down';
|
||||||
import SelectionUtils from './selection';
|
|
||||||
import { ToolType } from './modules/tools';
|
/**
|
||||||
|
* Interface describes Block class constructor argument
|
||||||
|
*/
|
||||||
|
interface BlockConstructorOptions {
|
||||||
|
/**
|
||||||
|
* Tool's name
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initial Block data
|
||||||
|
*/
|
||||||
|
data: BlockToolData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tool's class or constructor function
|
||||||
|
*/
|
||||||
|
Tool: BlockToolConstructable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tool settings from initial config
|
||||||
|
*/
|
||||||
|
settings: ToolSettings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Editor's API methods
|
||||||
|
*/
|
||||||
|
api: ApiModule;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Block
|
* @class Block
|
||||||
|
@ -98,6 +132,11 @@ export default class Block {
|
||||||
*/
|
*/
|
||||||
public tunes: BlockTune[];
|
public tunes: BlockTune[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tool's user configuration
|
||||||
|
*/
|
||||||
|
public readonly config: ToolConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cached inputs
|
* Cached inputs
|
||||||
*
|
*
|
||||||
|
@ -149,29 +188,42 @@ export default class Block {
|
||||||
}, this.modificationDebounceTimer);
|
}, this.modificationDebounceTimer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class
|
* Current block API interface
|
||||||
* @param {string} toolName - Tool name that passed on initialization
|
|
||||||
* @param {object} toolInstance — passed Tool`s instance that rendered the Block
|
|
||||||
* @param {object} toolClass — Tool's class
|
|
||||||
* @param {object} settings - default settings
|
|
||||||
* @param {ApiModule} apiModule - Editor API module for pass it to the Block Tunes
|
|
||||||
*/
|
*/
|
||||||
constructor(
|
private readonly blockAPI: BlockAPIInterface;
|
||||||
toolName: string,
|
|
||||||
toolInstance: BlockTool,
|
/**
|
||||||
toolClass: BlockToolConstructable,
|
* @class
|
||||||
settings: ToolConfig,
|
* @param {string} tool - Tool name that passed on initialization
|
||||||
apiModule: ApiModule
|
* @param {BlockToolData} data - Tool's initial data
|
||||||
) {
|
* @param {BlockToolConstructable} Tool — Tool's class
|
||||||
this.name = toolName;
|
* @param {ToolSettings} settings - default tool's config
|
||||||
this.tool = toolInstance;
|
* @param {ApiModule} api - Editor API module for pass it to the Block Tunes
|
||||||
this.class = toolClass;
|
*/
|
||||||
|
constructor({
|
||||||
|
name,
|
||||||
|
data,
|
||||||
|
Tool,
|
||||||
|
settings,
|
||||||
|
api,
|
||||||
|
}: BlockConstructorOptions) {
|
||||||
|
this.name = name;
|
||||||
|
this.class = Tool;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.api = apiModule;
|
this.config = settings.config || {};
|
||||||
this.holder = this.compose();
|
this.api = api;
|
||||||
|
this.blockAPI = new BlockAPI(this);
|
||||||
|
|
||||||
this.mutationObserver = new MutationObserver(this.didMutated);
|
this.mutationObserver = new MutationObserver(this.didMutated);
|
||||||
|
|
||||||
|
this.tool = new Tool({
|
||||||
|
data,
|
||||||
|
config: this.config,
|
||||||
|
api: this.api.getMethodsForTool(name, ToolType.Block),
|
||||||
|
block: this.blockAPI,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.holder = this.compose();
|
||||||
/**
|
/**
|
||||||
* @type {BlockTune[]}
|
* @type {BlockTune[]}
|
||||||
*/
|
*/
|
||||||
|
@ -285,37 +337,12 @@ export default class Block {
|
||||||
return this.inputs[this.inputIndex - 1];
|
return this.inputs[this.inputIndex - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns Plugins content
|
|
||||||
*
|
|
||||||
* @returns {HTMLElement}
|
|
||||||
*/
|
|
||||||
public get pluginsContent(): HTMLElement {
|
|
||||||
const blockContentNodes = this.holder.querySelector(`.${Block.CSS.content}`);
|
|
||||||
|
|
||||||
if (blockContentNodes && blockContentNodes.childNodes.length) {
|
|
||||||
/**
|
|
||||||
* Editors Block content can contain different Nodes from extensions
|
|
||||||
* We use DOM isExtensionNode to ignore such Nodes and return first Block that does not match filtering list
|
|
||||||
*/
|
|
||||||
for (let child = blockContentNodes.childNodes.length - 1; child >= 0; child--) {
|
|
||||||
const contentNode = blockContentNodes.childNodes[child];
|
|
||||||
|
|
||||||
if (!$.isExtensionNode(contentNode)) {
|
|
||||||
return contentNode as HTMLElement;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Block's JSON data
|
* Get Block's JSON data
|
||||||
*
|
*
|
||||||
* @returns {object}
|
* @returns {object}
|
||||||
*/
|
*/
|
||||||
public get data(): BlockToolData {
|
public get data(): Promise<BlockToolData> {
|
||||||
return this.save().then((savedObject) => {
|
return this.save().then((savedObject) => {
|
||||||
if (savedObject && !_.isEmpty(savedObject.data)) {
|
if (savedObject && !_.isEmpty(savedObject.data)) {
|
||||||
return savedObject.data;
|
return savedObject.data;
|
||||||
|
@ -390,6 +417,13 @@ export default class Block {
|
||||||
this.holder.classList.toggle(Block.CSS.focused, state);
|
this.holder.classList.toggle(Block.CSS.focused, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Block's focused state
|
||||||
|
*/
|
||||||
|
public get focused(): boolean {
|
||||||
|
return this.holder.classList.contains(Block.CSS.focused);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set selected state
|
* Set selected state
|
||||||
* We don't need to mark Block as Selected when it is empty
|
* We don't need to mark Block as Selected when it is empty
|
||||||
|
@ -422,6 +456,15 @@ export default class Block {
|
||||||
this.holder.classList.toggle(Block.CSS.wrapperStretched, state);
|
this.holder.classList.toggle(Block.CSS.wrapperStretched, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return Block's stretched state
|
||||||
|
*
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
public get stretched(): boolean {
|
||||||
|
return this.holder.classList.contains(Block.CSS.wrapperStretched);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggle drop target state
|
* Toggle drop target state
|
||||||
*
|
*
|
||||||
|
@ -431,6 +474,31 @@ export default class Block {
|
||||||
this.holder.classList.toggle(Block.CSS.dropTarget, state);
|
this.holder.classList.toggle(Block.CSS.dropTarget, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Plugins content
|
||||||
|
*
|
||||||
|
* @returns {HTMLElement}
|
||||||
|
*/
|
||||||
|
public get pluginsContent(): HTMLElement {
|
||||||
|
const blockContentNodes = this.holder.querySelector(`.${Block.CSS.content}`);
|
||||||
|
|
||||||
|
if (blockContentNodes && blockContentNodes.childNodes.length) {
|
||||||
|
/**
|
||||||
|
* Editors Block content can contain different Nodes from extensions
|
||||||
|
* We use DOM isExtensionNode to ignore such Nodes and return first Block that does not match filtering list
|
||||||
|
*/
|
||||||
|
for (let child = blockContentNodes.childNodes.length - 1; child >= 0; child--) {
|
||||||
|
const contentNode = blockContentNodes.childNodes[child];
|
||||||
|
|
||||||
|
if (!$.isExtensionNode(contentNode)) {
|
||||||
|
return contentNode as HTMLElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls Tool's method
|
* Calls Tool's method
|
||||||
*
|
*
|
||||||
|
@ -444,6 +512,14 @@ export default class Block {
|
||||||
* call Tool's method with the instance context
|
* call Tool's method with the instance context
|
||||||
*/
|
*/
|
||||||
if (this.tool[methodName] && this.tool[methodName] instanceof Function) {
|
if (this.tool[methodName] && this.tool[methodName] instanceof Function) {
|
||||||
|
if (methodName === BlockToolAPI.APPEND_CALLBACK) {
|
||||||
|
_.log(
|
||||||
|
'`appendCallback` hook is deprecated and will be removed in the next major release. ' +
|
||||||
|
'Use `rendered` hook instead',
|
||||||
|
'warn'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// eslint-disable-next-line no-useless-call
|
// eslint-disable-next-line no-useless-call
|
||||||
this.tool[methodName].call(this.tool, params);
|
this.tool[methodName].call(this.tool, params);
|
||||||
|
@ -538,7 +614,7 @@ export default class Block {
|
||||||
return tunesList.map(({ name, Tune }: {name: string; Tune: BlockTuneConstructable}) => {
|
return tunesList.map(({ name, Tune }: {name: string; Tune: BlockTuneConstructable}) => {
|
||||||
return new Tune({
|
return new Tune({
|
||||||
api: this.api.getMethodsForTool(name, ToolType.Tune),
|
api: this.api.getMethodsForTool(name, ToolType.Tune),
|
||||||
settings: this.settings,
|
settings: this.config,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -133,7 +133,8 @@ export default class Core {
|
||||||
if (config.holderId && !config.holder) {
|
if (config.holderId && !config.holder) {
|
||||||
config.holder = config.holderId;
|
config.holder = config.holderId;
|
||||||
config.holderId = null;
|
config.holderId = null;
|
||||||
_.log('holderId property will deprecated in next major release, use holder property instead.', 'warn');
|
_.log('holderId property is deprecated and will be removed in the next major release. ' +
|
||||||
|
'Use holder property instead.', 'warn');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import Module from '../../__module';
|
import Module from '../../__module';
|
||||||
|
|
||||||
import { Blocks } from '../../../../types/api';
|
import { BlockAPI as BlockAPIInterface, Blocks } from '../../../../types/api';
|
||||||
import { BlockToolData, OutputData, ToolConfig } from '../../../../types';
|
import { BlockToolData, OutputData, ToolConfig } from '../../../../types';
|
||||||
import * as _ from './../../utils';
|
import * as _ from './../../utils';
|
||||||
|
import BlockAPI from '../../block/api';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class BlocksAPI
|
* @class BlocksAPI
|
||||||
|
@ -22,7 +23,7 @@ export default class BlocksAPI extends Module {
|
||||||
delete: (index?: number): void => this.delete(index),
|
delete: (index?: number): void => this.delete(index),
|
||||||
swap: (fromIndex: number, toIndex: number): void => this.swap(fromIndex, toIndex),
|
swap: (fromIndex: number, toIndex: number): void => this.swap(fromIndex, toIndex),
|
||||||
move: (toIndex: number, fromIndex?: number): void => this.move(toIndex, fromIndex),
|
move: (toIndex: number, fromIndex?: number): void => this.move(toIndex, fromIndex),
|
||||||
getBlockByIndex: (index: number): HTMLElement => this.getBlockByIndex(index),
|
getBlockByIndex: (index: number): BlockAPIInterface => this.getBlockByIndex(index),
|
||||||
getCurrentBlockIndex: (): number => this.getCurrentBlockIndex(),
|
getCurrentBlockIndex: (): number => this.getCurrentBlockIndex(),
|
||||||
getBlocksCount: (): number => this.getBlocksCount(),
|
getBlocksCount: (): number => this.getBlocksCount(),
|
||||||
stretchBlock: (index: number, status = true): void => this.stretchBlock(index, status),
|
stretchBlock: (index: number, status = true): void => this.stretchBlock(index, status),
|
||||||
|
@ -56,10 +57,10 @@ export default class BlocksAPI extends Module {
|
||||||
*
|
*
|
||||||
* @returns {HTMLElement}
|
* @returns {HTMLElement}
|
||||||
*/
|
*/
|
||||||
public getBlockByIndex(index: number): HTMLElement {
|
public getBlockByIndex(index: number): BlockAPIInterface {
|
||||||
const block = this.Editor.BlockManager.getBlockByIndex(index);
|
const block = this.Editor.BlockManager.getBlockByIndex(index);
|
||||||
|
|
||||||
return block.holder;
|
return new BlockAPI(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,6 +71,12 @@ export default class BlocksAPI extends Module {
|
||||||
* @deprecated — use 'move' instead
|
* @deprecated — use 'move' instead
|
||||||
*/
|
*/
|
||||||
public swap(fromIndex: number, toIndex: number): void {
|
public swap(fromIndex: number, toIndex: number): void {
|
||||||
|
_.log(
|
||||||
|
'`blocks.swap()` method is deprecated and will be removed in the next major release. ' +
|
||||||
|
'Use `block.move()` method instead',
|
||||||
|
'info'
|
||||||
|
);
|
||||||
|
|
||||||
this.Editor.BlockManager.swap(fromIndex, toIndex);
|
this.Editor.BlockManager.swap(fromIndex, toIndex);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -161,8 +168,16 @@ export default class BlocksAPI extends Module {
|
||||||
*
|
*
|
||||||
* @param {number} index - index of Block to stretch
|
* @param {number} index - index of Block to stretch
|
||||||
* @param {boolean} status - true to enable, false to disable
|
* @param {boolean} status - true to enable, false to disable
|
||||||
|
*
|
||||||
|
* @deprecated Use BlockAPI interface to stretch Blocks
|
||||||
*/
|
*/
|
||||||
public stretchBlock(index: number, status = true): void {
|
public stretchBlock(index: number, status = true): void {
|
||||||
|
_.log(
|
||||||
|
'`blocks.stretchBlock()` method is deprecated and will be removed in the next major release. ' +
|
||||||
|
'Use BlockAPI interface instead',
|
||||||
|
'warn'
|
||||||
|
);
|
||||||
|
|
||||||
const block = this.Editor.BlockManager.getBlockByIndex(index);
|
const block = this.Editor.BlockManager.getBlockByIndex(index);
|
||||||
|
|
||||||
if (!block) {
|
if (!block) {
|
||||||
|
@ -188,14 +203,13 @@ export default class BlocksAPI extends Module {
|
||||||
index?: number,
|
index?: number,
|
||||||
needToFocus?: boolean
|
needToFocus?: boolean
|
||||||
): void => {
|
): void => {
|
||||||
this.Editor.BlockManager.insert(
|
this.Editor.BlockManager.insert({
|
||||||
type,
|
tool: type,
|
||||||
data,
|
data,
|
||||||
config,
|
|
||||||
index,
|
index,
|
||||||
needToFocus
|
needToFocus,
|
||||||
);
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert new Block
|
* Insert new Block
|
||||||
|
@ -206,7 +220,7 @@ export default class BlocksAPI extends Module {
|
||||||
* @deprecated with insert() method
|
* @deprecated with insert() method
|
||||||
*/
|
*/
|
||||||
public insertNewBlock(): void {
|
public insertNewBlock(): void {
|
||||||
_.log('Method blocks.insertNewBlock() is deprecated and it will be removed in next major release. ' +
|
_.log('Method blocks.insertNewBlock() is deprecated and it will be removed in the next major release. ' +
|
||||||
'Use blocks.insert() instead.', 'warn');
|
'Use blocks.insert() instead.', 'warn');
|
||||||
this.insert();
|
this.insert();
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import Module from '../__module';
|
||||||
import $ from '../dom';
|
import $ from '../dom';
|
||||||
import * as _ from '../utils';
|
import * as _ from '../utils';
|
||||||
import Blocks from '../blocks';
|
import Blocks from '../blocks';
|
||||||
import { BlockTool, BlockToolConstructable, BlockToolData, PasteEvent, ToolConfig } from '../../../types';
|
import { BlockToolConstructable, BlockToolData, PasteEvent } from '../../../types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {BlockManager} BlockManager
|
* @typedef {BlockManager} BlockManager
|
||||||
|
@ -204,16 +204,21 @@ export default class BlockManager extends Module {
|
||||||
/**
|
/**
|
||||||
* Creates Block instance by tool name
|
* Creates Block instance by tool name
|
||||||
*
|
*
|
||||||
* @param {string} toolName - tools passed in editor config {@link EditorConfig#tools}
|
* @param {string} tool - tools passed in editor config {@link EditorConfig#tools}
|
||||||
* @param {object} data - constructor params
|
* @param {BlockToolData} [data] - constructor params
|
||||||
* @param {object} settings - block settings
|
|
||||||
*
|
*
|
||||||
* @returns {Block}
|
* @returns {Block}
|
||||||
*/
|
*/
|
||||||
public composeBlock(toolName: string, data: BlockToolData = {}, settings: ToolConfig = {}): Block {
|
public composeBlock({ tool, data = {} }: {tool: string; data?: BlockToolData}): Block {
|
||||||
const toolInstance = this.Editor.Tools.construct(toolName, data) as BlockTool;
|
const settings = this.Editor.Tools.getToolSettings(tool);
|
||||||
const toolClass = this.Editor.Tools.available[toolName] as BlockToolConstructable;
|
const Tool = this.Editor.Tools.available[tool] as BlockToolConstructable;
|
||||||
const block = new Block(toolName, toolInstance, toolClass, settings, this.Editor.API);
|
const block = new Block({
|
||||||
|
name: tool,
|
||||||
|
data,
|
||||||
|
Tool,
|
||||||
|
settings,
|
||||||
|
api: this.Editor.API,
|
||||||
|
});
|
||||||
|
|
||||||
this.bindEvents(block);
|
this.bindEvents(block);
|
||||||
|
|
||||||
|
@ -223,32 +228,63 @@ export default class BlockManager extends Module {
|
||||||
/**
|
/**
|
||||||
* Insert new block into _blocks
|
* Insert new block into _blocks
|
||||||
*
|
*
|
||||||
* @param {string} toolName — plugin name, by default method inserts initial block type
|
* @param {string} tool — plugin name, by default method inserts initial block type
|
||||||
* @param {object} data — plugin data
|
* @param {object} data — plugin data
|
||||||
* @param {object} settings - default settings
|
|
||||||
* @param {number} index - index where to insert new Block
|
* @param {number} index - index where to insert new Block
|
||||||
* @param {boolean} needToFocus - flag shows if needed to update current Block index
|
* @param {boolean} needToFocus - flag shows if needed to update current Block index
|
||||||
|
* @param {boolean} replace - flag shows if block by passed index should be replaced with inserted one
|
||||||
*
|
*
|
||||||
* @returns {Block}
|
* @returns {Block}
|
||||||
*/
|
*/
|
||||||
public insert(
|
public insert({
|
||||||
toolName: string = this.config.initialBlock,
|
tool = this.config.initialBlock,
|
||||||
data: BlockToolData = {},
|
data = {},
|
||||||
settings: ToolConfig = {},
|
index = this.currentBlockIndex + 1,
|
||||||
index: number = this.currentBlockIndex + 1,
|
needToFocus = true,
|
||||||
needToFocus = true
|
replace = false,
|
||||||
): Block {
|
}: {
|
||||||
const block = this.composeBlock(toolName, data, settings);
|
tool?: string;
|
||||||
|
data?: BlockToolData;
|
||||||
|
index?: number;
|
||||||
|
needToFocus?: boolean;
|
||||||
|
replace?: boolean;
|
||||||
|
} = {}): Block {
|
||||||
|
const block = this.composeBlock({
|
||||||
|
tool,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
|
||||||
this._blocks[index] = block;
|
this._blocks.insert(index, block, replace);
|
||||||
|
|
||||||
if (needToFocus) {
|
if (needToFocus) {
|
||||||
this.currentBlockIndex = index;
|
this.currentBlockIndex = index;
|
||||||
|
} else if (index <= this.currentBlockIndex) {
|
||||||
|
this.currentBlockIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace current working block
|
||||||
|
*
|
||||||
|
* @param {string} tool — plugin name
|
||||||
|
* @param {BlockToolData} data — plugin data
|
||||||
|
*
|
||||||
|
* @returns {Block}
|
||||||
|
*/
|
||||||
|
public replace({
|
||||||
|
tool = this.config.initialBlock,
|
||||||
|
data = {},
|
||||||
|
}): Block {
|
||||||
|
return this.insert({
|
||||||
|
tool,
|
||||||
|
data,
|
||||||
|
index: this.currentBlockIndex,
|
||||||
|
replace: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert pasted content. Call onPaste callback after insert.
|
* Insert pasted content. Call onPaste callback after insert.
|
||||||
*
|
*
|
||||||
|
@ -261,13 +297,10 @@ export default class BlockManager extends Module {
|
||||||
pasteEvent: PasteEvent,
|
pasteEvent: PasteEvent,
|
||||||
replace = false
|
replace = false
|
||||||
): Block {
|
): Block {
|
||||||
let block;
|
const block = this.insert({
|
||||||
|
tool: toolName,
|
||||||
if (replace) {
|
replace,
|
||||||
block = this.replace(toolName);
|
});
|
||||||
} else {
|
|
||||||
block = this.insert(toolName);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
block.call(BlockToolAPI.ON_PASTE, pasteEvent);
|
block.call(BlockToolAPI.ON_PASTE, pasteEvent);
|
||||||
|
@ -289,7 +322,7 @@ export default class BlockManager extends Module {
|
||||||
* @returns {Block} inserted Block
|
* @returns {Block} inserted Block
|
||||||
*/
|
*/
|
||||||
public insertInitialBlockAtIndex(index: number, needToFocus = false): Block {
|
public insertInitialBlockAtIndex(index: number, needToFocus = false): Block {
|
||||||
const block = this.composeBlock(this.config.initialBlock, {}, {});
|
const block = this.composeBlock({ tool: this.config.initialBlock });
|
||||||
|
|
||||||
this._blocks[index] = block;
|
this._blocks[index] = block;
|
||||||
|
|
||||||
|
@ -381,7 +414,7 @@ export default class BlockManager extends Module {
|
||||||
*
|
*
|
||||||
* @returns {number|undefined}
|
* @returns {number|undefined}
|
||||||
*/
|
*/
|
||||||
public removeSelectedBlocks(): number|undefined {
|
public removeSelectedBlocks(): number | undefined {
|
||||||
let firstSelectedBlockIndex;
|
let firstSelectedBlockIndex;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -439,28 +472,7 @@ export default class BlockManager extends Module {
|
||||||
*
|
*
|
||||||
* @type {Block}
|
* @type {Block}
|
||||||
*/
|
*/
|
||||||
return this.insert(this.config.initialBlock, data);
|
return this.insert({ data });
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace current working block
|
|
||||||
*
|
|
||||||
* @param {string} toolName — plugin name
|
|
||||||
* @param {BlockToolData} data — plugin data
|
|
||||||
* @param {ToolConfig} settings — plugin config
|
|
||||||
*
|
|
||||||
* @returns {Block}
|
|
||||||
*/
|
|
||||||
public replace(
|
|
||||||
toolName: string = this.config.initialBlock,
|
|
||||||
data: BlockToolData = {},
|
|
||||||
settings: ToolConfig = {}
|
|
||||||
): Block {
|
|
||||||
const block = this.composeBlock(toolName, data, settings);
|
|
||||||
|
|
||||||
this._blocks.insert(this.currentBlockIndex, block, true);
|
|
||||||
|
|
||||||
return block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -637,7 +649,7 @@ export default class BlockManager extends Module {
|
||||||
this.dropPointer();
|
this.dropPointer();
|
||||||
|
|
||||||
if (needAddInitialBlock) {
|
if (needAddInitialBlock) {
|
||||||
this.insert(this.config.initialBlock);
|
this.insert();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4,12 +4,12 @@ import * as _ from '../utils';
|
||||||
import {
|
import {
|
||||||
BlockTool,
|
BlockTool,
|
||||||
BlockToolConstructable,
|
BlockToolConstructable,
|
||||||
BlockToolData,
|
|
||||||
PasteConfig,
|
PasteConfig,
|
||||||
PasteEvent,
|
PasteEvent,
|
||||||
PasteEventDetail
|
PasteEventDetail
|
||||||
} from '../../../types';
|
} from '../../../types';
|
||||||
import Block from '../block';
|
import Block from '../block';
|
||||||
|
import { SavedData } from '../../types-internal/block-data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tag substitute object.
|
* Tag substitute object.
|
||||||
|
@ -735,16 +735,14 @@ export default class Paste extends Module {
|
||||||
/**
|
/**
|
||||||
* Insert data passed as application/x-editor-js JSON
|
* Insert data passed as application/x-editor-js JSON
|
||||||
*
|
*
|
||||||
* @param {object} blocks — Blocks' data to insert
|
* @param {Array} blocks — Blocks' data to insert
|
||||||
*
|
*
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
private insertEditorJSData(blocks: Array<{tool: string; data: BlockToolData}>): void {
|
private insertEditorJSData(blocks: Array<Pick<SavedData, 'data' | 'tool'>>): void {
|
||||||
const { BlockManager, Tools } = this.Editor;
|
const { BlockManager, Tools } = this.Editor;
|
||||||
|
|
||||||
blocks.forEach(({ tool, data }, i) => {
|
blocks.forEach(({ tool, data }, i) => {
|
||||||
const settings = this.Editor.Tools.getToolSettings(tool);
|
|
||||||
|
|
||||||
let needToReplaceCurrentBlock = false;
|
let needToReplaceCurrentBlock = false;
|
||||||
|
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
|
@ -753,11 +751,11 @@ export default class Paste extends Module {
|
||||||
needToReplaceCurrentBlock = isCurrentBlockInitial && BlockManager.currentBlock.isEmpty;
|
needToReplaceCurrentBlock = isCurrentBlockInitial && BlockManager.currentBlock.isEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needToReplaceCurrentBlock) {
|
BlockManager.insert({
|
||||||
BlockManager.replace(tool, data, settings);
|
tool,
|
||||||
} else {
|
data,
|
||||||
BlockManager.insert(tool, data, settings);
|
replace: needToReplaceCurrentBlock,
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,7 @@ import Module from '../__module';
|
||||||
/* eslint-disable import/no-duplicates */
|
/* eslint-disable import/no-duplicates */
|
||||||
import * as _ from '../utils';
|
import * as _ from '../utils';
|
||||||
import { ChainData } from '../utils';
|
import { ChainData } from '../utils';
|
||||||
import { BlockToolData } from '../../../types';
|
import { BlockToolConstructable, OutputBlockData } from '../../../types';
|
||||||
import { BlockToolConstructable } from '../../../types/tools';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Editor.js Renderer Module
|
* Editor.js Renderer Module
|
||||||
|
@ -43,9 +42,9 @@ export default class Renderer extends Module {
|
||||||
/**
|
/**
|
||||||
* Make plugin blocks from array of plugin`s data
|
* Make plugin blocks from array of plugin`s data
|
||||||
*
|
*
|
||||||
* @param {BlockToolData[]} blocks - blocks to render
|
* @param {OutputBlockData[]} blocks - blocks to render
|
||||||
*/
|
*/
|
||||||
public async render(blocks: BlockToolData[]): Promise<void> {
|
public async render(blocks: OutputBlockData[]): Promise<void> {
|
||||||
const chainData = blocks.map((block) => ({ function: (): Promise<void> => this.insertBlock(block) }));
|
const chainData = blocks.map((block) => ({ function: (): Promise<void> => this.insertBlock(block) }));
|
||||||
|
|
||||||
const sequence = await _.sequence(chainData as ChainData[]);
|
const sequence = await _.sequence(chainData as ChainData[]);
|
||||||
|
@ -63,15 +62,17 @@ export default class Renderer extends Module {
|
||||||
* @param {object} item - Block data to insert
|
* @param {object} item - Block data to insert
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
public async insertBlock(item): Promise<void> {
|
public async insertBlock(item: OutputBlockData): Promise<void> {
|
||||||
const { Tools, BlockManager } = this.Editor;
|
const { Tools, BlockManager } = this.Editor;
|
||||||
const tool = item.type;
|
const tool = item.type;
|
||||||
const data = item.data;
|
const data = item.data;
|
||||||
const settings = item.settings;
|
|
||||||
|
|
||||||
if (tool in Tools.available) {
|
if (tool in Tools.available) {
|
||||||
try {
|
try {
|
||||||
BlockManager.insert(tool, data, settings);
|
BlockManager.insert({
|
||||||
|
tool,
|
||||||
|
data,
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
_.log(`Block «${tool}» skipped because of plugins error`, 'warn', data);
|
_.log(`Block «${tool}» skipped because of plugins error`, 'warn', data);
|
||||||
throw Error(error);
|
throw Error(error);
|
||||||
|
@ -93,7 +94,10 @@ export default class Renderer extends Module {
|
||||||
stubData.title = toolToolboxSettings.title || userToolboxSettings.title || stubData.title;
|
stubData.title = toolToolboxSettings.title || userToolboxSettings.title || stubData.title;
|
||||||
}
|
}
|
||||||
|
|
||||||
const stub = BlockManager.insert(Tools.stubTool, stubData, settings);
|
const stub = BlockManager.insert({
|
||||||
|
tool: Tools.stubTool,
|
||||||
|
data: stubData,
|
||||||
|
});
|
||||||
|
|
||||||
stub.stretched = true;
|
stub.stretched = true;
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ import * as _ from '../utils';
|
||||||
|
|
||||||
import HTMLJanitor from 'html-janitor';
|
import HTMLJanitor from 'html-janitor';
|
||||||
import { BlockToolData, InlineToolConstructable, SanitizerConfig } from '../../../types';
|
import { BlockToolData, InlineToolConstructable, SanitizerConfig } from '../../../types';
|
||||||
|
import { SavedData } from '../../types-internal/block-data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -60,8 +61,8 @@ export default class Sanitizer extends Module {
|
||||||
* @param {Array<{tool, data: BlockToolData}>} blocksData - blocks' data to sanitize
|
* @param {Array<{tool, data: BlockToolData}>} blocksData - blocks' data to sanitize
|
||||||
*/
|
*/
|
||||||
public sanitizeBlocks(
|
public sanitizeBlocks(
|
||||||
blocksData: Array<{tool: string; data: BlockToolData}>
|
blocksData: Array<Pick<SavedData, 'data' | 'tool'>>
|
||||||
): Array<{tool: string; data: BlockToolData}> {
|
): Array<Pick<SavedData, 'data' | 'tool'>> {
|
||||||
return blocksData.map((block) => {
|
return blocksData.map((block) => {
|
||||||
const toolConfig = this.composeToolConfig(block.tool);
|
const toolConfig = this.composeToolConfig(block.tool);
|
||||||
|
|
||||||
|
|
|
@ -233,7 +233,10 @@ export default class ConversionToolbar extends Module {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Editor.BlockManager.replace(replacingToolName, newBlockData);
|
this.Editor.BlockManager.replace({
|
||||||
|
tool: replacingToolName,
|
||||||
|
data: newBlockData,
|
||||||
|
});
|
||||||
this.Editor.BlockSelection.clearSelection();
|
this.Editor.BlockSelection.clearSelection();
|
||||||
|
|
||||||
this.close();
|
this.close();
|
||||||
|
|
|
@ -295,13 +295,10 @@ export default class Toolbox extends Module {
|
||||||
const { BlockManager, Caret } = this.Editor;
|
const { BlockManager, Caret } = this.Editor;
|
||||||
const { currentBlock } = BlockManager;
|
const { currentBlock } = BlockManager;
|
||||||
|
|
||||||
let newBlock;
|
const newBlock = BlockManager.insert({
|
||||||
|
tool: toolName,
|
||||||
if (currentBlock.isEmpty) {
|
replace: currentBlock.isEmpty,
|
||||||
newBlock = BlockManager.replace(toolName);
|
});
|
||||||
} else {
|
|
||||||
newBlock = BlockManager.insert(toolName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply callback before inserting html
|
* Apply callback before inserting html
|
||||||
|
|
|
@ -2,8 +2,8 @@ import Paragraph from '../tools/paragraph/dist/bundle';
|
||||||
import Module from '../__module';
|
import Module from '../__module';
|
||||||
import * as _ from '../utils';
|
import * as _ from '../utils';
|
||||||
import {
|
import {
|
||||||
BlockTool,
|
BlockToolConstructable,
|
||||||
BlockToolConstructable, BlockToolData, EditorConfig,
|
EditorConfig,
|
||||||
InlineTool,
|
InlineTool,
|
||||||
InlineToolConstructable, Tool,
|
InlineToolConstructable, Tool,
|
||||||
ToolConfig,
|
ToolConfig,
|
||||||
|
@ -325,36 +325,6 @@ export default class Tools extends Module {
|
||||||
this.toolsUnavailable[data.toolName] = this.toolsClasses[data.toolName];
|
this.toolsUnavailable[data.toolName] = this.toolsClasses[data.toolName];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return Tool`s instance
|
|
||||||
*
|
|
||||||
* @param {string} tool — tool name
|
|
||||||
* @param {object} data — initial data
|
|
||||||
*
|
|
||||||
* @returns {BlockTool}
|
|
||||||
*/
|
|
||||||
public construct(tool: string, data: BlockToolData): BlockTool {
|
|
||||||
const Plugin = this.toolsClasses[tool] as BlockToolConstructable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configuration to be passed to the Tool's constructor
|
|
||||||
*/
|
|
||||||
const config = this.toolsSettings[tool][this.USER_SETTINGS.CONFIG] || {};
|
|
||||||
|
|
||||||
// Pass placeholder to initial Block config
|
|
||||||
if (tool === this.config.initialBlock && !config.placeholder) {
|
|
||||||
config.placeholder = this.config.placeholder;
|
|
||||||
}
|
|
||||||
|
|
||||||
const constructorOptions = {
|
|
||||||
api: this.Editor.API.getMethodsForTool(tool),
|
|
||||||
config,
|
|
||||||
data,
|
|
||||||
};
|
|
||||||
|
|
||||||
return new Plugin(constructorOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return Inline Tool's instance
|
* Return Inline Tool's instance
|
||||||
*
|
*
|
||||||
|
@ -393,7 +363,16 @@ export default class Tools extends Module {
|
||||||
* @returns {ToolSettings}
|
* @returns {ToolSettings}
|
||||||
*/
|
*/
|
||||||
public getToolSettings(toolName): ToolSettings {
|
public getToolSettings(toolName): ToolSettings {
|
||||||
return this.toolsSettings[toolName];
|
const settings = this.toolsSettings[toolName];
|
||||||
|
const config = settings[this.USER_SETTINGS.CONFIG] || {};
|
||||||
|
|
||||||
|
// Pass placeholder to initial Block config
|
||||||
|
if (toolName === this.config.initialBlock && !config.placeholder) {
|
||||||
|
config.placeholder = this.config.placeholder;
|
||||||
|
settings[this.USER_SETTINGS.CONFIG] = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import $ from '../../dom';
|
import $ from '../../dom';
|
||||||
import { API, BlockTool, BlockToolData } from '../../../../types';
|
import { API, BlockTool, BlockToolData, BlockToolConstructorOptions } from '../../../../types';
|
||||||
|
|
||||||
export interface StubData extends BlockToolData{
|
export interface StubData extends BlockToolData{
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -52,7 +52,7 @@ export default class Stub implements BlockTool {
|
||||||
* @param data - stub tool data
|
* @param data - stub tool data
|
||||||
* @param api - Editor.js API
|
* @param api - Editor.js API
|
||||||
*/
|
*/
|
||||||
constructor({ data, api }: {data: StubData; api: API}) {
|
constructor({ data, api }: BlockToolConstructorOptions<StubData>) {
|
||||||
this.api = api;
|
this.api = api;
|
||||||
this.title = data.title || this.api.i18n.t('Error');
|
this.title = data.title || this.api.i18n.t('Error');
|
||||||
this.subtitle = this.api.i18n.t('The block can not be displayed correctly.');
|
this.subtitle = this.api.i18n.t('The block can not be displayed correctly.');
|
||||||
|
|
65
types/api/block.d.ts
vendored
Normal file
65
types/api/block.d.ts
vendored
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import {BlockToolData, ToolConfig} from '../tools';
|
||||||
|
import {SavedData} from '../../src/types-internal/block-data';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @interface BlockAPI Describes Block API methods and properties
|
||||||
|
*/
|
||||||
|
export interface BlockAPI {
|
||||||
|
/**
|
||||||
|
* Tool name
|
||||||
|
*/
|
||||||
|
readonly name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tool config passed on Editor's initialization
|
||||||
|
*/
|
||||||
|
readonly config: ToolConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper of Tool's HTML element
|
||||||
|
*/
|
||||||
|
readonly holder: HTMLElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if Block content is empty
|
||||||
|
*/
|
||||||
|
readonly isEmpty: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if Block is selected with Cross-Block selection
|
||||||
|
*/
|
||||||
|
readonly selected: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter sets Block's stretch state
|
||||||
|
*
|
||||||
|
* Getter returns true if Block is stretched
|
||||||
|
*/
|
||||||
|
stretched: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call Tool method with errors handler under-the-hood
|
||||||
|
*
|
||||||
|
* @param {string} methodName - method to call
|
||||||
|
* @param {object} param - object with parameters
|
||||||
|
*
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
call(methodName: string, param?: object): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save Block content
|
||||||
|
*
|
||||||
|
* @return {Promise<void|SavedData>}
|
||||||
|
*/
|
||||||
|
save(): Promise<void|SavedData>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate Block data
|
||||||
|
*
|
||||||
|
* @param {BlockToolData} data
|
||||||
|
*
|
||||||
|
* @return {Promise<boolean>}
|
||||||
|
*/
|
||||||
|
validate(data: BlockToolData): Promise<boolean>;
|
||||||
|
}
|
7
types/api/blocks.d.ts
vendored
7
types/api/blocks.d.ts
vendored
|
@ -1,5 +1,6 @@
|
||||||
import {OutputData} from '../data-formats/output-data';
|
import {OutputData} from '../data-formats/output-data';
|
||||||
import {BlockToolData, ToolConfig} from "../tools";
|
import {BlockToolData, ToolConfig} from '../tools';
|
||||||
|
import {BlockAPI} from './block';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes methods to manipulate with Editor`s blocks
|
* Describes methods to manipulate with Editor`s blocks
|
||||||
|
@ -50,7 +51,7 @@ export interface Blocks {
|
||||||
* @param {number} index
|
* @param {number} index
|
||||||
* @returns {HTMLElement}
|
* @returns {HTMLElement}
|
||||||
*/
|
*/
|
||||||
getBlockByIndex(index: number): HTMLElement;
|
getBlockByIndex(index: number): BlockAPI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns current Block index
|
* Returns current Block index
|
||||||
|
@ -62,6 +63,8 @@ export interface Blocks {
|
||||||
* Mark Block as stretched
|
* Mark Block as stretched
|
||||||
* @param {number} index - Block to mark
|
* @param {number} index - Block to mark
|
||||||
* @param {boolean} status - stretch status
|
* @param {boolean} status - stretch status
|
||||||
|
*
|
||||||
|
* @deprecated Use BlockAPI interface to stretch Blocks
|
||||||
*/
|
*/
|
||||||
stretchBlock(index: number, status?: boolean): void;
|
stretchBlock(index: number, status?: boolean): void;
|
||||||
|
|
||||||
|
|
1
types/api/index.d.ts
vendored
1
types/api/index.d.ts
vendored
|
@ -10,4 +10,5 @@ export * from './toolbar';
|
||||||
export * from './notifier';
|
export * from './notifier';
|
||||||
export * from './tooltip';
|
export * from './tooltip';
|
||||||
export * from './inline-toolbar';
|
export * from './inline-toolbar';
|
||||||
|
export * from './block';
|
||||||
export * from './i18n';
|
export * from './i18n';
|
||||||
|
|
4
types/configs/editor-config.d.ts
vendored
4
types/configs/editor-config.d.ts
vendored
|
@ -1,12 +1,12 @@
|
||||||
import {ToolConstructable, ToolSettings} from '../tools';
|
import {ToolConstructable, ToolSettings} from '../tools';
|
||||||
import {LogLevels, OutputData, API} from '../index';
|
import {API, LogLevels, OutputData} from '../index';
|
||||||
import {SanitizerConfig} from './sanitizer-config';
|
import {SanitizerConfig} from './sanitizer-config';
|
||||||
import {I18nConfig} from './i18n-config';
|
import {I18nConfig} from './i18n-config';
|
||||||
|
|
||||||
export interface EditorConfig {
|
export interface EditorConfig {
|
||||||
/**
|
/**
|
||||||
* Element where Editor will be append
|
* Element where Editor will be append
|
||||||
* @deprecated property will be removed in next major release, use holder instead
|
* @deprecated property will be removed in the next major release, use holder instead
|
||||||
*/
|
*/
|
||||||
holderId?: string | HTMLElement;
|
holderId?: string | HTMLElement;
|
||||||
|
|
||||||
|
|
2
types/configs/paste-config.d.ts
vendored
2
types/configs/paste-config.d.ts
vendored
|
@ -1,5 +1,3 @@
|
||||||
import {BlockToolData} from '../index';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tool onPaste configuration object
|
* Tool onPaste configuration object
|
||||||
*/
|
*/
|
||||||
|
|
19
types/data-formats/output-data.d.ts
vendored
19
types/data-formats/output-data.d.ts
vendored
|
@ -1,5 +1,19 @@
|
||||||
import {BlockToolData} from '../tools';
|
import {BlockToolData} from '../tools';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output of one Tool
|
||||||
|
*/
|
||||||
|
export interface OutputBlockData {
|
||||||
|
/**
|
||||||
|
* Too type
|
||||||
|
*/
|
||||||
|
type: string;
|
||||||
|
/**
|
||||||
|
* Saved Block data
|
||||||
|
*/
|
||||||
|
data: BlockToolData;
|
||||||
|
}
|
||||||
|
|
||||||
export interface OutputData {
|
export interface OutputData {
|
||||||
/**
|
/**
|
||||||
* Editor's version
|
* Editor's version
|
||||||
|
@ -14,8 +28,5 @@ export interface OutputData {
|
||||||
/**
|
/**
|
||||||
* Saved Blocks
|
* Saved Blocks
|
||||||
*/
|
*/
|
||||||
blocks: Array<{
|
blocks: OutputBlockData[];
|
||||||
type: string;
|
|
||||||
data: BlockToolData
|
|
||||||
}>;
|
|
||||||
}
|
}
|
||||||
|
|
5
types/index.d.ts
vendored
5
types/index.d.ts
vendored
|
@ -36,7 +36,9 @@ export {
|
||||||
BaseToolConstructable,
|
BaseToolConstructable,
|
||||||
InlineTool,
|
InlineTool,
|
||||||
InlineToolConstructable,
|
InlineToolConstructable,
|
||||||
|
InlineToolConstructorOptions,
|
||||||
BlockToolConstructable,
|
BlockToolConstructable,
|
||||||
|
BlockToolConstructorOptions,
|
||||||
BlockTool,
|
BlockTool,
|
||||||
BlockToolData,
|
BlockToolData,
|
||||||
Tool,
|
Tool,
|
||||||
|
@ -65,7 +67,8 @@ export {
|
||||||
DictValue,
|
DictValue,
|
||||||
I18nConfig,
|
I18nConfig,
|
||||||
} from './configs';
|
} from './configs';
|
||||||
export {OutputData} from './data-formats/output-data';
|
export {OutputData, OutputBlockData} from './data-formats/output-data';
|
||||||
|
export { BlockAPI } from './api'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We have a namespace API {@link ./api/index.d.ts} (APIMethods) but we can not use it as interface
|
* We have a namespace API {@link ./api/index.d.ts} (APIMethods) but we can not use it as interface
|
||||||
|
|
11
types/tools/block-tool.d.ts
vendored
11
types/tools/block-tool.d.ts
vendored
|
@ -1,8 +1,8 @@
|
||||||
import { ConversionConfig, PasteConfig, SanitizerConfig } from '../configs';
|
import { ConversionConfig, PasteConfig, SanitizerConfig } from '../configs';
|
||||||
import { BlockToolData } from './block-tool-data';
|
import { BlockToolData } from './block-tool-data';
|
||||||
import {BaseTool, BaseToolConstructable, BaseToolConstructorOptions} from './tool';
|
import {BaseTool, BaseToolConstructable} from './tool';
|
||||||
import { ToolConfig } from './tool-config';
|
import { ToolConfig } from './tool-config';
|
||||||
import { API } from '../index';
|
import {API, BlockAPI} from '../index';
|
||||||
import { PasteEvent } from './paste-events';
|
import { PasteEvent } from './paste-events';
|
||||||
import { MoveEvent } from './hook-events';
|
import { MoveEvent } from './hook-events';
|
||||||
|
|
||||||
|
@ -77,10 +77,11 @@ export interface BlockTool extends BaseTool {
|
||||||
/**
|
/**
|
||||||
* Describe constructor parameters
|
* Describe constructor parameters
|
||||||
*/
|
*/
|
||||||
export interface BlockToolConstructorOptions extends BaseToolConstructorOptions {
|
export interface BlockToolConstructorOptions<D extends object = any, C extends object = any> {
|
||||||
api: API;
|
api: API;
|
||||||
data: BlockToolData;
|
data: BlockToolData<D>;
|
||||||
config?: ToolConfig;
|
config?: ToolConfig<C>;
|
||||||
|
block?: BlockAPI;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BlockToolConstructable extends BaseToolConstructable {
|
export interface BlockToolConstructable extends BaseToolConstructable {
|
||||||
|
|
2
types/tools/index.d.ts
vendored
2
types/tools/index.d.ts
vendored
|
@ -11,5 +11,5 @@ export * from './tool-settings';
|
||||||
export * from './paste-events';
|
export * from './paste-events';
|
||||||
export * from './hook-events';
|
export * from './hook-events';
|
||||||
|
|
||||||
export type Tool = BaseTool | BlockTool | InlineTool;
|
export type Tool = BlockTool | InlineTool;
|
||||||
export type ToolConstructable = BlockToolConstructable | InlineToolConstructable;
|
export type ToolConstructable = BlockToolConstructable | InlineToolConstructable;
|
||||||
|
|
2
types/tools/tool-config.d.ts
vendored
2
types/tools/tool-config.d.ts
vendored
|
@ -1,4 +1,4 @@
|
||||||
/**
|
/**
|
||||||
* Tool configuration object. Specified by Tool developer, so leave it as object
|
* Tool configuration object. Specified by Tool developer, so leave it as object
|
||||||
*/
|
*/
|
||||||
export type ToolConfig = object;
|
export type ToolConfig<T extends object = any> = T;
|
||||||
|
|
7
types/tools/tool.d.ts
vendored
7
types/tools/tool.d.ts
vendored
|
@ -1,4 +1,4 @@
|
||||||
import {API, BlockToolData, ToolSettings} from '../index';
|
import {API} from '../index';
|
||||||
import {ToolConfig} from './tool-config';
|
import {ToolConfig} from './tool-config';
|
||||||
import {SanitizerConfig} from '../configs';
|
import {SanitizerConfig} from '../configs';
|
||||||
|
|
||||||
|
@ -30,6 +30,11 @@ export interface BaseToolConstructable {
|
||||||
*/
|
*/
|
||||||
title?: string;
|
title?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describe constructor parameters
|
||||||
|
*/
|
||||||
|
new (config: {api: API, config?: ToolConfig}): BaseTool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tool`s prepare method. Can be async
|
* Tool`s prepare method. Can be async
|
||||||
* @param data
|
* @param data
|
||||||
|
|
Loading…
Reference in a new issue