@kedao/editor
Version:
Rich Text Editor Based On Draft.js
182 lines • 7.06 kB
JavaScript
import './styles.scss';
import React from 'react';
import { Map } from 'immutable';
import { EditorState, SelectionState } from 'draft-js';
import PrismDecorator from 'draft-js-prism';
import { ContentUtils } from '@kedao/utils';
import Prism from 'prismjs';
class CodeBlockWrapper extends React.Component {
constructor(props) {
super(props);
this.codeBlockBlockKey = null;
this.codeBlockBlock = null;
this.setCodeBlockSyntax = (event) => {
const syntax = event.currentTarget.dataset.syntax;
if (!syntax) {
return false;
}
try {
const syntaxName = this.props.syntaxs.find((item) => item.syntax === syntax).name;
if (!syntaxName) {
return false;
}
const selectionState = SelectionState.createEmpty(this.codeBlockBlockKey);
const editorState = EditorState.forceSelection(this.props.editorState, selectionState);
this.setState({ syntax, syntaxName }, () => {
this.props.editor.setValue(ContentUtils.setSelectionBlockData(editorState, { syntax }));
});
}
catch (error) {
console.warn(error);
}
};
this.state = {
syntax: props.syntaxs[0].syntax,
syntaxName: props.syntaxs[0].name
};
}
componentDidMount() {
this.codeBlockBlock = this.getCodeBlockBlock(this.props);
this.getCodeBlockSyntax(this.props);
}
UNSAFE_componentWillReceiveProps(nextProps) {
this.codeBlockBlock = this.getCodeBlockBlock(nextProps);
this.getCodeBlockSyntax(nextProps);
}
getCodeBlockBlock(props) {
try {
const offsetKey = props['data-offset-key'];
const blockKey = offsetKey.split('-')[0];
const contentState = props.editorState.getCurrentContent();
this.codeBlockBlockKey = blockKey;
return contentState.getBlockForKey(blockKey);
}
catch (error) {
console.warn(error);
return null;
}
}
getCodeBlockSyntax(props) {
if (this.codeBlockBlock) {
const blockData = this.codeBlockBlock.getData();
const syntax = blockData.get('syntax') || props.syntaxs[0].syntax;
const syntaxName = props.syntaxs.find((item) => item.syntax === syntax).name;
if (!syntaxName) {
return false;
}
this.setState({ syntax, syntaxName });
}
}
render() {
return (React.createElement("div", { className: "kedao-code-block-wrapper" },
React.createElement("div", { className: "kedao-code-block-header", contentEditable: false },
React.createElement("div", { className: "syntax-switcher" },
React.createElement("span", null, this.state.syntaxName),
React.createElement("ul", { className: "syntax-list" }, this.props.syntaxs.map((item, index) => (React.createElement("li", { key: index, "data-syntax": item.syntax, onClick: this.setCodeBlockSyntax }, item.name)))))),
React.createElement("pre", { className: `kedao-code-block${this.props.showLineNumber ? ' show-line-number' : ''}`, "data-syntax": this.state.syntax }, this.props.children)));
}
}
const getCodeBlockBlock = (block) => {
if (!block || !block.getType || block.getType() !== 'code-block') {
return null;
}
const blockDOMNode = document.querySelector(`code[data-offset-key="${block.getKey()}-0-0"]`);
if (!blockDOMNode) {
return null;
}
if (blockDOMNode.parentNode.nodeName.toLowerCase() !== 'pre') {
return null;
}
return blockDOMNode.parentNode.dataset.syntax;
};
const getCodeBlockRenderMap = (options) => (props) => {
return Map({
'code-block': {
element: 'code',
wrapper: React.createElement(CodeBlockWrapper, Object.assign({}, options, props)),
nestingEnabled: false
}
});
};
export default (options = {}) => {
const { showLineNumber, showTools, includeEditors, excludeEditors } = options;
const syntaxs = options.syntaxs || [
{
name: 'JavaScript',
syntax: 'javascript'
},
{
name: 'HTML',
syntax: 'html'
},
{
name: 'CSS',
syntax: 'css'
}
];
return [
{
type: 'block',
name: 'code-block',
includeEditors,
excludeEditors,
renderMap: getCodeBlockRenderMap({ syntaxs, showLineNumber, showTools }),
importer: (nodeName, node) => {
if (nodeName.toLowerCase() === 'pre') {
try {
const syntax = node.dataset.lang;
node.innerHTML = node.innerHTML
.replace(/<code(.*?)>/g, '')
.replace(/<\/code>/g, '');
return syntax
? {
type: 'code-block',
data: { syntax }
}
: null;
}
catch (error) {
return null;
}
}
return null;
},
exporter: (contentState, block) => {
if (block.type.toLowerCase() !== 'code-block') {
return null;
}
const previousBlock = contentState.getBlockBefore(block.key);
const nextBlock = contentState.getBlockAfter(block.key);
const previousBlockType = previousBlock === null || previousBlock === void 0 ? void 0 : previousBlock.getType();
const nextBlockType = nextBlock === null || nextBlock === void 0 ? void 0 : nextBlock.getType();
const syntax = block.data.syntax || syntaxs[0].syntax;
let start = '';
let end = '';
if (previousBlockType !== 'code-block') {
start = `<pre data-lang="${syntax}" class="lang-${syntax}"><code class="lang-${syntax}">`;
}
else {
start = '';
}
if (nextBlockType !== 'code-block') {
end = '</code></pre>';
}
else {
end = '<br/>';
}
return { start, end };
}
},
{
type: 'decorator',
includeEditors,
excludeEditors,
decorator: new PrismDecorator({
prism: Prism,
getSyntax: getCodeBlockBlock,
defaultSyntax: syntaxs[0].syntax
})
}
];
};
//# sourceMappingURL=index.js.map