Skip to content
This repository has been archived by the owner on Feb 6, 2023. It is now read-only.

Ability to select which inline styles, block types, links should be retained on paste #1057

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions docs/APIReference-Editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,17 @@ needed to observe spellcheck events are not fired in IE.

Default is `false`.

#### stripPastedStyles
#### pasteSupport
```
stripPastedStyles?: boolean
pasteSupport?: Object
```
Set whether to remove all information except plaintext from pasted content.
Optionally define which inline styles and block types should be retained on
paste, and what to strip:
- images
- links

This should be used if your editor does not support rich styles.

Default is `false`.
See [Advanced Topics: Paste Support](/docs/advanced-topics-paste-support.html)
for details on usage.

### DOM and Accessibility (Optional)

Expand Down
4 changes: 3 additions & 1 deletion docs/Advanced-Topics-Custom-Block-Render.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ renderers, as well as converting pasted content to known Draft block types.
When pasting content or when using the
[convertFromHTML](/docs/api-reference-data-conversion.html#convertfromhtml)
Draft will then convert the pasted content to the respective block rendering type
by matching the Draft block render map with the matched tag.
by matching the Draft block render map with the matched tag. When pasting content
Draft can optionally strip unwanted block types (see
[Advanced Topics: Paste Support](/docs/advanced-topics-paste-support.html)).

## Draft default block render map

Expand Down
5 changes: 3 additions & 2 deletions docs/Advanced-Topics-Inline-Styles.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,9 @@ together in styled `span` nodes.
### Mapping a style string to CSS

By default, `Editor` provides support for a basic list of inline styles:
`'BOLD'`, `'ITALIC'`, `'UNDERLINE'`, and `'CODE'`. These are mapped to simple CSS
style objects, which are used to apply styles to the relevant ranges.
`'BOLD'`, `'ITALIC'`, `'UNDERLINE'`, '`STRIKETHROUGH`', and `'CODE'`. These
are mapped to simple CSS style objects, which are used to apply styles to the
relevant ranges.

For your editor, you may define custom style strings to include with these
defaults, or you may override the default style objects for the basic styles.
Expand Down
112 changes: 112 additions & 0 deletions docs/Advanced-Topics-Paste-Support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
---
id: advanced-topics-paste-support
title: Paste Support
layout: docs
category: Advanced Topics
next: advanced-topics-editorstate-race-conditions
permalink: docs/advanced-topics-paste-support.html
---

The `Editor` component offers flexibility to define custom paste support
for your editor, via the `pasteSupport` prop. This allows you to define which
inline styles and block types should be retained on paste, as well as disable
links support.

## Defaults

By default, `Editor` supports paste of links, all default
[inline styles](/docs/advanced-topics-inline-styles.html) and
[block types](/docs/advanced-topics-custom-block-render-map.html). If custom
block render map is provided, it will be used to define supported block types.

## Configuring paste support

For your editor, you may provide the `pasteSupport` prop to define the lists
of `inlineStyles` and `blockTypes` you want to support on paste. Also you can
disable images and links support.

## pasteSupport object properties

#### inlineStyles
```
inlineStyles?: List<string>
```
Optionally define the list of inliny styles supported on paste. If omitted, all
defult inline styles will be supported.

#### blockTypes
```
blockTypes?: List<string>
```
Optionally define the list of block types supported on paste. If omitted, all
block types defined in `blockRenderMap` will be supported.

#### images
```
images?: boolean
```
Optionally disable images support (set to `false`).

Default is `true`.

#### links
```
links?: boolean
```
Optionally disable links support (set to `false`).

Default is `true`.

## Example

You may want to ignore underlined text, h4-h6 headers, blockquotes and images
on paste. To do so, define a custom `pasteSupport` object:

```js
import {Editor} from 'draft-js';

const pasteSupport = {
inlineStyles: Immutable.List([
'BOLD',
'CODE',
'ITALIC',
'STRIKETHROUGH',
]),
blockTypes: Immutable.List([
'header-one',
'header-two',
'header-three',
'unordered-list-item',
'ordered-list-item',
'blockquote',
'atomic',
'code-block',
'unstyled',
]),
images: false,
};

class MyEditor extends React.Component {
// ...
render() {
return (
<Editor
pasteSupport={pasteSupport}
editorState={this.state.editorState}
...
/>
);
}
}
```

If your use case should not have any blocks, inline styles, images and links, set
`pasteSupport` prop to:
```js
{
inlineStyles: Immutable.List(),
blockTypes: Immutable.List(),
images: false,
links: false,
}
```
2 changes: 1 addition & 1 deletion docs/Advanced-Topics-Text-Direction.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ id: advanced-topics-text-direction
title: Text Direction
layout: docs
category: Advanced Topics
next: advanced-topics-editorstate-race-conditions
next: advanced-topics-paste-support
permalink: docs/advanced-topics-text-direction.html
---

Expand Down
3 changes: 2 additions & 1 deletion src/component/base/DraftEditor.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type {DraftScrollPosition} from 'DraftScrollPosition';

const DefaultDraftBlockRenderMap = require('DefaultDraftBlockRenderMap');
const DefaultDraftInlineStyle = require('DefaultDraftInlineStyle');
const DefaultDraftPasteSupport = require('DefaultDraftPasteSupport');
const DraftEditorCompositionHandler = require('DraftEditorCompositionHandler');
const DraftEditorContents = require('DraftEditorContents.react');
const DraftEditorDragHandler = require('DraftEditorDragHandler');
Expand Down Expand Up @@ -73,9 +74,9 @@ class DraftEditor extends React.Component<DraftEditorProps, State> {
blockRendererFn: emptyFunction.thatReturnsNull,
blockStyleFn: emptyFunction.thatReturns(''),
keyBindingFn: getDefaultKeyBinding,
pasteSupport: DefaultDraftPasteSupport,
readOnly: false,
spellCheck: false,
stripPastedStyles: false,
};

_blockSelectEvents: boolean;
Expand Down
16 changes: 11 additions & 5 deletions src/component/base/DraftEditorProps.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type {DraftBlockRenderMap} from 'DraftBlockRenderMap';
import type {DraftDragType} from 'DraftDragType';
import type {DraftEditorCommand} from 'DraftEditorCommand';
import type {DraftHandleValue} from 'DraftHandleValue';
import type {DraftPasteSupport} from 'DraftPasteSupport';
import type {DraftInlineStyle} from 'DraftInlineStyle';
import type {DraftTextAlignment} from 'DraftTextAlignment';
import type EditorState from 'EditorState';
Expand Down Expand Up @@ -79,10 +80,15 @@ export type DraftEditorProps = {
// autocorrect is enabled as well.
spellCheck?: boolean,

// Set whether to remove all style information from pasted content. If your
// use case should not have any block or inline styles, it is recommended
// that you set this to `true`.
stripPastedStyles?: boolean,
// Configuration object that specifies which inline styles, block types and
// links should be retained on paste. If your use case should not have any
// blocks, inline styles and links, it is recommended that you set this to
// {
// inlineStyles: List(),
// blockTypes: List(),
// links: false,
// }
pasteSupport: DraftPasteSupport,

tabIndex?: number,

Expand Down Expand Up @@ -183,7 +189,7 @@ export type DraftEditorDefaultProps = {
blockRendererFn: (block: ContentBlock) => ?Object,
blockStyleFn: (block: ContentBlock) => string,
keyBindingFn: (e: SyntheticKeyboardEvent<>) => ?string,
pasteSupport: DraftPasteSupport,
readOnly: boolean,
spellCheck: boolean,
stripPastedStyles: boolean,
};
20 changes: 19 additions & 1 deletion src/component/handlers/edit/editOnPaste.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ var DataTransfer = require('DataTransfer');
var DraftModifier = require('DraftModifier');
var DraftPasteProcessor = require('DraftPasteProcessor');
var EditorState = require('EditorState');
const DefaultDraftPasteSupport = require('DefaultDraftPasteSupport');
var RichTextEditorUtil = require('RichTextEditorUtil');

var getEntityKeyForSelection = require('getEntityKeyForSelection');
Expand Down Expand Up @@ -151,9 +152,26 @@ function editOnPaste(editor: DraftEditor, e: SyntheticClipboardEvent<>): void {

// If there is html paste data, try to parse that.
if (html) {
const pasteSupport = Object.assign(
DefaultDraftPasteSupport,
editor.props.pasteSupport,
);
const {blockTypes, inlineStyles, images, links} = pasteSupport;

// if supported block types are specified, support only them
const blockRenderMap = blockTypes
? editor.props.blockRenderMap.filter(
(block?: Object, blockType: string) =>
blockTypes.includes(blockType),
)
: editor.props.blockRenderMap;

var htmlFragment = DraftPasteProcessor.processHTML(
html,
editor.props.blockRenderMap,
blockRenderMap,
inlineStyles,
images,
links,
);
if (htmlFragment) {
const {contentBlocks, entityMap} = htmlFragment;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,21 @@ describe('convertFromHTMLToContentBlocks', () => {
test('img with http protocol should have camera emoji content', function() {
const blocks = convertFromHTMLToContentBlocks(
'<img src="http://www.facebook.com">',
null,
null,
null,
true,
);
expect(blocks.contentBlocks[0].text).toBe('\ud83d\udcf7');
});

test('img with data protocol should be correctly parsed', function() {
const blocks = convertFromHTMLToContentBlocks(
`<img src="${IMAGE_DATA_URL}">`,
null,
null,
null,
true,
);
expect(blocks.contentBlocks[0].text).toBe('\ud83d\udcf7');
});
Expand Down
Loading