Paste handling improvements (#534)

* Make on paste callback non-static method

* Add docs

* change tools.md header levels

* some docs improvements

* upd docs

* Types improvements

* add image tool for testing

* Fix file drag'n'drop

* improve log on paste

* Update submodules

* Update bundle

* Update paragraph submodule

* Fix some bugs with blocks replacement
Remove tag from HTMLPasteEvent

* Use production webpack mode

* minimize: true

* Update docs

* Update submodules

* Update bundle
This commit is contained in:
George Berezhnoy 2018-11-29 12:16:06 +03:00 committed by GitHub
commit 669c11eaa5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 385 additions and 10691 deletions

View file

@ -47,7 +47,7 @@ Method that specifies how to merge two `Blocks` of the same type, for example on
Method does accept data object in same format as the `Render` and it should provide logic how to combine new
data with the currently stored value.
### Internal Tool Settings
## Internal Tool Settings
Options that Tool can specify. All settings should be passed as static properties of Tool's class.
@ -58,7 +58,7 @@ Options that Tool can specify. All settings should be passed as static propertie
| `enableLineBreaks` | _Boolean_ | `false` | With this option, CodeX Editor won't handle Enter keydowns. Can be helpful for Tools like `<code>` where line breaks should be handled by default behaviour. |
| `isInline` | _Boolean_ | `false` | Describes Tool as a [Tool for the Inline Toolbar](tools-inline.md) |
### User configuration
## User configuration
All Tools can be configured by users. You can set up some of available settings along with Tool's class
to the `tools` property of Editor Config.
@ -85,58 +85,58 @@ There are few options available by CodeX Editor.
| `inlineToolbar` | _Boolean/Array_ | `false` | Pass `true` to enable the Inline Toolbar with all Tools, or pass an array with specified Tools list |
| `config` | _Object_ | `null` | User's configuration for Plugin.
### Paste handling
## Paste handling
CodeX Editor handles paste on Blocks and provides API for Tools to process the pasted data.
When user pastes content into Editor, pasted content is splitted into blocks.
When user pastes content into Editor, pasted content will be splitted into blocks.
1. If plain text has been pasted, it is split by new line characters
2. If HTML string has been pasted, it is split by block tags
1. If plain text will be pasted, it will be splitted by new line characters
2. If HTML string will be pasted, it will be splitted by block tags
Also Editor API allows you to define RegExp patterns to substitute them by your data.
Also Editor API allows you to define your own pasting scenario. You can either:
To provide paste handling for your Tool you need to define static getter `onPaste` in Tool class.
`onPaste` getter should return object with fields described below.
1. Specify **HTML tags**, that can be represented by your Tool. For example, Image Tool can handle `<img>` tags.
If tags you specified will be found on content pasting, your Tool will be rendered.
2. Specify **RegExp** for pasted strings. If pattern has been matched, your Tool will be rendered.
3. Specify **MIME type** or **extensions** of files that can be handled by your Tool on pasting by drag-n-drop or from clipboard.
For each scenario, you should do 2 next things:
##### HTML tags handling
1. Define static getter `pasteConfig` in Tool class. Specify handled patterns there.
2. Define public method `onPaste` that will handle PasteEvent to process pasted data.
To handle pasted HTML elements object returned from `onPaste` getter should contain following fields:
### HTML tags handling
To handle pasted HTML elements object returned from `pasteConfig` getter should contain following field:
| Name | Type | Description |
| -- | -- | -- |
| `handler(content: HTMLElement)` | `Function` | _Optional_. Pasted HTML elements handler. Gets one argument `content`. `content` is HTML element extracted from pasted data. Handler should return the same object as Tool's `save` method |
| `tags` | `String[]` | _Optional_. Should contain all tag names you want to be extracted from pasted data and be passed to your `handler` method |
| `tags` | `String[]` | _Optional_. Should contain all tag names you want to be extracted from pasted data and processed by your `onPaste` method |
For correct work you MUST provide `onPaste.handler` at least for `initialBlock` Tool.
For correct work you MUST provide `onPaste` handler at least for `initialBlock` Tool.
> Example
Header tool can handle `H1`-`H6` tags using paste handling API
Header Tool can handle `H1`-`H6` tags using paste handling API
```javascript
static get onPaste() {
static get pasteConfig() {
return {
tags: ['H1', 'H2', 'H3', 'H4', 'H5', 'H6'],
handler: (element) => ({
type: element.tagName,
text: element.innerHTML
})
}
}
```
> One tag can be handled by one Tool only.
> Same tag can be handled by one (first specified) Tool only.
##### Patterns handling
### RegExp patterns handling
Your Tool can analyze text by RegExp patterns to substitute pasted string with data you want. Object returned from `onPaste` getter should contain following fields to use patterns:
Your Tool can analyze text by RegExp patterns to substitute pasted string with data you want. Object returned from `pasteConfig` getter should contain following field to use patterns:
| Name | Type | Description |
| -- | -- | -- |
| `patterns` | `Object` | _Optional_. `patterns` object contains RegExp patterns with their names as object's keys |
| `patternHandler(text: string, key: string)` | `Function` | _Optional_. Gets pasted string and pattern name. Should return the same object as Tool `save` method |
**Note** Editor will check pattern's full match, so don't forget to handle all available chars in there.
@ -144,70 +144,91 @@ Pattern will be processed only if paste was on `initialBlock` Tool and pasted st
> Example
You can handle youtube links and insert embeded video instead:
You can handle YouTube links and insert embeded video instead:
```javascript
static get onPaste() {
static get pasteConfig() {
return {
patterns: {
youtube: /http(?:s?):\/\/(?:www\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-\_]*)(&(amp;)?[\w\?=]*)?/
},
patternHandler: (text, key) => {
const urlData = Youtube.onPaste.patterns[key].exec(text);
return {
iframe: Youtube.makeEmbededFromURL(urlData)
};
}
}
}
```
> Both `onPaste.handler` and `onPaste.patternHandler` can be `async` or return a `Promise`.
##### Files
### Files pasting
Your Tool can handle files pasted or dropped into the Editor.
To handle file you should provide `files` and `fileHandler` properties in your `onPaste` configuration object.
To handle file you should provide `files` property in your `pasteConfig` configuration object.
`fileHandler` property should be a function which takes File object as an argument and returns the same object as Tool\`s `save` method.
`file` property is an object with the following fields:
`files` property is an object with the following fields:
| Name | Type | Description |
| ---- | ---- | ----------- |
| `extensions` | `string[]` | _Optional_ Array of extensions your Tool can handle |
| `mimeTypes` | `sring[]` | _Optional_ Array of MIME types your Tool can handle |
Example
```javascript
static get onPaste() {
static get pasteConfig() {
return {
files: {
mimeTypes: ['image/png'],
extensions: ['json']
},
fileHandler: (file) => {
/* do smth with the file */
return {
data // Some extracted content
}
}
}
}
```
### Sanitize
### Pasted data handling
If you registered some paste substitutions in `pasteConfig` property, you **should** provide `onPaste` callback in your Tool class.
`onPaste` should be public non-static method. It accepts custom _PasteEvent_ object as argument.
PasteEvent is an alias for three types of events - `tag`, `pattern` and `file`. You can get the type from _PasteEvent_ object's `type` property.
Each of these events provide `detail` property with info about pasted content.
| Type | Detail |
| ----- | ------ |
| `tag` | `data` - pasted HTML element |
| `pattern` | `key` - matched pattern key you specified in `pasteConfig` object <br /> `data` - pasted string |
| `file` | `file` - pasted file |
Example
```javascript
onPaste (event) {
switch (event.type) {
case 'tag':
const element = event.detail.data;
this.handleHTMLPaste(element);
break;
case 'pattern':
const text = event.detail.data;
const key = event.detail.key;
this.handlePatternPaste(key, text);
break;
case 'file':
const file = event.detail.file;
this.handleFilePaste(file);
break;
}
}
```
## Sanitize
CodeX Editor provides [API](sanitizer.md) to clean taint strings.
Use it manually at the `save()` method or or pass `sanitizer` config to do it automatically.
#### Sanitizer Configuration
### Sanitizer Configuration
The example of sanitizer configuration
@ -220,7 +241,7 @@ let sanitizerConfig = {
Keys of config object is tags and the values is a rules.
##### Rule
#### Rule
Rule can be boolean, object or function. Object is a dictionary of rules for tag's attributes.
@ -262,7 +283,7 @@ a: function(el) {
}
```
#### Manual sanitize
### Manual sanitize
Call API method `sanitizer.clean()` at the save method for each field in returned data.
@ -274,7 +295,7 @@ save() {
}
```
#### Automatic sanitize
### Automatic sanitize
If you pass the sanitizer config as static getter, CodeX Editor will automatically sanitize your saved data.