Home Reference Source

application/components/common/rich-editor2/plugins/embed.js

import React from 'react';
import ReactDOMServer from 'react-dom/server';
import ToolbarButton from '../common/toolbar-button';
import {getEventTransfer} from 'slate-react';
import he from 'he';
import {ensureEmptyGraf} from '../util/ensure-empty-graf';

function defaultClickHandler() {
    const {editor} = this;
    const {editorContent} = this.state;
    const hasEmbed = this.hasBlock('embed');

    if (hasEmbed) {
        editor.setBlocks('paragraph');
    } else {
        editor.setBlocks('embed');
    }

}

export const SERIALIZER_RULES = [

    {
        serialize(obj, children) {
            const danger = (children) => {
                // renderToStaticMarkup converts all linebreaks to <br />, which is
                // no bueno in these code blocks. Luckily the actual "static markup" is
                // encoded so we can safely remove any <br /> elements.
                const markup = ReactDOMServer.renderToStaticMarkup(children).replace(/\<br ?\/\>/ig, '');

                return {
                    __html: he.decode(markup, {strict: false})
                }
            }
            if (obj.object == 'block' && obj.type == 'embed') {
                return <div className="embed" dangerouslySetInnerHTML={danger(children)}></div>;
            }
        }
    }
];

export class EmbedButton extends ToolbarButton
{
    handleOnClick(e) {
        defaultClickHandler.call(this.props.editor, e);
    }

    getLabel() {
        return <i className='fa fa-code'></i>;
    }
}

export class EmbedNode extends React.Component
{
    constructor(props) {
        super(props);

        this.parentEditor = this.props.editor;
    }

    render() {
        return (
            <pre {...this.props.attributes} className='embed-node'>
                <code>
                    {this.props.children}
                </code>
            </pre>
        )
    }
}
let inEmbed = false;

export function embedHasCursor() {
    return inEmbed;
}

export function EmbedPlugin(options) {

    return {
        renderEditor(props, editor, next) {
            const children = next();
            if (editor.value.blocks.some(inline => inline.type == 'embed')) {
                inEmbed = true;
            } else {
                inEmbed = false;
            }
            return (
                <React.Fragment>
                    {children}
                </React.Fragment>
            );
        },
        onPaste(e, editor, next) {

            if (inEmbed == false) {
                return next();
            }
            const xfer = getEventTransfer(e);
            const text = xfer.text.replace(/\\n/ig, '');

            const {start} = editor.value.selection;
            const {document} = editor.value;

            const sibling = editor.value.document.getNextNode(start.key);

            if (document.getClosestBlock(start.key).get('type') == 'embed') {
                editor.insertText(text);
            } else {
                editor.insertBlock({
                    object: 'block',
                    type: 'embed',
                    nodes: [
                        {
                            object: 'text',
                            leaves: [
                                {
                                    text: text
                                }
                            ]
                        }
                    ]
                });
            }
            if (!sibling) {
                // make sure we have a blank line
                ensureEmptyGraf(editor);
            }

        },
        renderNode(props, editor, next) {
            const {attributes, children} = props;

            switch(props.node.type) {
                case 'embed':
                    return <EmbedNode {...props} editor={editor}/>;
                default:
                    return next();
            }

        }
    };
};