Skip to content

Commit

Permalink
[Feature] BlockAPI Interface (codex-team#1075)
Browse files Browse the repository at this point in the history
  • Loading branch information
gohabereg authored May 27, 2020
1 parent 7c3bf76 commit ffe5bbc
Show file tree
Hide file tree
Showing 29 changed files with 544 additions and 226 deletions.
2 changes: 1 addition & 1 deletion 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
Expand Up @@ -3,6 +3,7 @@
### 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` — 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` - Fix many code-style issues, add missed annotations.
- `Improvements` - Adjusted GitHub action for ESLint.
Expand All @@ -20,6 +21,9 @@
- `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)

> *Breaking changes* `blocks.getBlockByIndex` method now returns BlockAPI object. To access old value, use BlockAPI.holder property

### 2.17

- `Improvements` - Editor's [onchange callback](https://editorjs.io/configuration#editor-modifications-callback) now accepts an API as a parameter
Expand Down
30 changes: 27 additions & 3 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

## 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

Common API interface.
Expand Down Expand Up @@ -43,11 +67,11 @@ use 'move' instead)

`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

`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

Expand Down
37 changes: 19 additions & 18 deletions docs/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ Each Tool should have an installation guide.

Each Tool's instance called with an params object.

| Param | Type | Description |
| ------ | ------------------- | ----------------------------------------------- |
| api | [`IAPI`][iapi-link] | Editor.js's API methods |
| config | `object` | Special configuration params passed in «config» |
| data | `object` | Data to be rendered in this Tool |
| Param | Type | Description |
| ------ | ------------------------------------------------------ | ----------------------------------------------- |
| api | [`IAPI`](../types/index.d.ts) | Editor.js's API methods |
| config | [`ToolConfig`](../types/tools/tool-config.d.ts) | Special configuration params passed in «config» |
| 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

Expand Down Expand Up @@ -228,14 +229,14 @@ onPaste (event) {

### 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:

```javascript
static get pasteConfig {
return false;
}
```
```

## Sanitize <a name="sanitize"></a>

Expand Down Expand Up @@ -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`.

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:

Expand All @@ -391,11 +392,11 @@ class Header {

### 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`.

`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:

Expand All @@ -411,7 +412,7 @@ class ListTool {
type: 'ordered'
}
}

static get conversionConfig() {
return {
export: (data) => {
Expand All @@ -425,11 +426,11 @@ class ListTool {

### 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.

`Function` allows you to specify own logic, how a string should be converted to your tool data. For example:
Expand All @@ -442,13 +443,13 @@ class ListTool {
type: 'unordered'
}
}

static get conversionConfig() {
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) => {
const items = string.split('.');
Expand Down
3 changes: 2 additions & 1 deletion src/components/block-tunes/block-tune-move-down.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ export default class MoveDownTune implements BlockTune {
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();

let scrollOffset = Math.abs(window.innerHeight - nextBlockElement.offsetHeight);
Expand Down
6 changes: 4 additions & 2 deletions src/components/block-tunes/block-tune-move-up.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ export default class MoveUpTune implements BlockTune {
return;
}

const currentBlockElement = this.api.blocks.getBlockByIndex(currentBlockIndex);
const previousBlockElement = this.api.blocks.getBlockByIndex(currentBlockIndex - 1);
const currentBlock = this.api.blocks.getBlockByIndex(currentBlockIndex);
const currentBlockElement = currentBlock.holder;
const previousBlock = this.api.blocks.getBlockByIndex(currentBlockIndex - 1);
const previousBlockElement = previousBlock.holder;

/**
* Here is two cases:
Expand Down
114 changes: 114 additions & 0 deletions src/components/block/api.ts
Original file line number Diff line number Diff line change
@@ -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;
Loading

0 comments on commit ffe5bbc

Please sign in to comment.