I want to combine the inline toolbar with the example from draft.js to insert a link into the editor.
Thanks to the draft.js plugin FAQ I am able to add a decorator to the draft-js-plugin editor which inserts a link on a button click.
Now I want to put this button inside the inline-toolbar from draft-js-plugins. That doesn't seem to work. This is what I've done so far:
Editor.jsx
...
const inlineToolbarPlugin = createInlineToolbarPlugin({
theme: {buttonStyles, toolbarStyles},
structure: [..., LinkButton]
});
const {InlineToolbar} = inlineToolbarPlugin;
const plugins = [inlineToolbarPlugin];
class RMSEditor extends Component {
...
render() {
return (
<div>
<div className={editorStyles.editor}>
<Editor
editorState={this.state.editorState}
onChange={this.onChange}
plugins={plugins}
decorators={this.decorator}
ref={(element) => {
this.editor = element;
}}
readOnly={this.state.readOnly}
/>
<InlineToolbar />
</div>
</div>
);
}
LinkButton.jsx
import classNames from "classnames/bind";
import React from "react";
import {Glyphicon} from "react-bootstrap";
import styles from "./buttonStyles.less";
const cx = classNames.bind(styles);
const LinkButton = () => {
return (
<div className={cx('buttonWrapper')} onClick={(e) => {
console.log("Div", e);
}}>
<button className={cx('button')} onClick={(e) => {
console.log("Button", e);
}}><Glyphicon glyph="link"/></button>
</div>
)
};
export default LinkButton;
This way, I have managed to get a Button that shows up in the inline toolbar. But when I clicked on that button, nothing happens. I expacted that one of the onClick
handlers will fire but that is not the case.
Full source code
Here you can find my full sourcecode as I don't want to put only the relevant parts directly under the questions. Please notice that the code will not work in the run snipped
thingy as I have no clue how to get it to work there without setting up the hole wabpack thing.
MentionsEditor.jsx
import {CompositeDecorator, EditorState, RichUtils} from "draft-js";
import {BoldButton, CodeButton, ItalicButton, UnderlineButton, UnorderedListButton} from "draft-js-buttons";
import createInlineToolbarPlugin from "draft-js-inline-toolbar-plugin";
import {defaultSuggestionsFilter} from "draft-js-mention-plugin"; // eslint-disable-line import/no-unresolved
import Editor from "draft-js-plugins-editor"; // eslint-disable-line import/no-unresolved
import React, {Component, PropTypes} from "react";
import {Button} from "react-bootstrap";
import buttonStyles from "./buttonStyles";
import editorStyles from "./editorStyles";
import LinkButton from "./InsertLinkButton";
import toolbarStyles from "./toolbarStyles";
const inlineToolbarPlugin = createInlineToolbarPlugin({
theme: {buttonStyles, toolbarStyles},
structure: [BoldButton, ItalicButton, UnderlineButton, CodeButton, UnorderedListButton, LinkButton]
});
const {InlineToolbar} = inlineToolbarPlugin;
const plugins = [inlineToolbarPlugin];
class RMSEditor extends Component {
constructor(props) {
super(props);
}
decorator = [
{
strategy: function findLinkEntities(contentBlock, callback, contentState) {
contentBlock.findEntityRanges(
(character) => {
const entityKey = character.getEntity();
return (
entityKey !== null &&
contentState.getEntity(entityKey).getType() === 'LINK'
);
},
callback
);
},
component: function (props) {
const {url} = props.contentState.getEntity(props.entityKey).getData();
return (
<a href={url}>
{props.children}
</a>
);
}
}
];
state = {
editorState: EditorState.createEmpty(),
};
onChange = (editorState) => {
this.setState({
editorState,
});
};
editorLink = function (props) {
const {url} = props.contentState.getEntity(props.entityKey).getData();
return (
<a href={url} style={{color: "blue"}}>
{props.children}
</a>
);
};
focus = () => {
this.editor.focus();
};
insertLink = (e) => {
e.preventDefault();
const {editorState} = this.state;
const contentState = editorState.getCurrentContent();
const contentStateWithEntity = contentState.createEntity(
'LINK',
'MUTABLE',
{url: "https://example.com"}
);
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const newEditorState = EditorState.set(editorState, {currentContent: contentStateWithEntity});
this.setState({
editorState: RichUtils.toggleLink(
newEditorState,
newEditorState.getSelection(),
entityKey
)
}, () => {
setTimeout(() => {
this.focus()
}, 0);
});
};
render() {
return (
<div>
<Button onClick={this.insertLink}>insert URL</Button>
<div className={editorStyles.editor}>
<Editor
editorState={this.state.editorState}
onChange={this.onChange}
plugins={plugins}
decorators={this.decorator}
ref={(element) => {
this.editor = element;
}}
readOnly={this.state.readOnly}
/>
<InlineToolbar />
</div>
</div>
);
}
}
RMSEditor.propTypes = {
stakeholder: PropTypes.object.isRequired
};
export default RMSEditor;
LinkButton.jsx
import classNames from "classnames/bind";
import React from "react";
import {Glyphicon} from "react-bootstrap";
import styles from "./buttonStyles.less";
const cx = classNames.bind(styles);
const LinkButton = () => {
return (
<div className={cx('buttonWrapper')} onClick={(e) => {
console.log("Div", e);
}}>
<button className={cx('button')} onClick={(e) => {
console.log("Button", e);
}}><Glyphicon glyph="link"/></button>
</div>
)
};
export default LinkButton;