Home Reference Source

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

import React from 'react';
import Dialog from 'material-ui/Dialog';
import TextField from 'material-ui/TextField';
import FlatButton from 'material-ui/FlatButton';
import RaisedButton from 'material-ui/RaisedButton';
import toStyle from 'css-to-style';
import ToolbarButton from '../common/toolbar-button';

export const SERIALIZER_RULES = [
    {
        serialize(obj, children) {
            if (obj.object == 'inline' && obj.type == 'styler') {
                return <span style={obj.data.get('style').length ? toStyle(obj.data.get('style')) : {}} className={obj.data.get('klass')}>{children}</span>;
            }
        }
    }
];

class StylerButton extends ToolbarButton
{
    handleOnClick(e) {
        return stylerClickHandler.call(this.props.editor, e);
    }

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

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

        this.parentEditor = this.props.editor;
    }

    render() {
        const {data} = this.props.node;

        const handleClick = e => {
            e.preventDefault();

            // open the modal and store the styler data
            this.props.editor.setState({
                'myStylerModalOpen': true,
                'myStylerData': data
            });

        }
        return (
            <span {...this.props.attributes} className='styler-panted' onClick={handleClick}>
                {this.props.children}
            </span>
        )
    }
}

function stylerClickHandler(e, defaultUrl = '') {
    const {editor} = this;
    const {editorContent} = this.state;
    const hasStyler = this.hasInline('styler');

    if (hasStyler) {
        // user highlighted a link and clicked the button, so remove the link
        editor.unwrapInline('styler');
    } else if (editorContent.selection.isExpanded) {
        // open the modal
        editor.setState({'myStylerModalOpen': true});
        return;
    }
}

class StylerModal extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            style: '',
            klass: '',
        };
    }

    closeModal() {
        this.props.editor.setState({
            'myStylerModalOpen': false,
            'myStylerData': null,
        });
        this.setState({
            style: '',
            klass: '',
        });
    }

    handleCancel(e) {
        this.closeModal.call(this);
    }

    componentWillReceiveProps(newProps) {
        if (newProps.editor && newProps.editor.state.myStylerData) {
            this.setState({
                'style': newProps.editor.state.myStylerData.get('style'),
                'klass': newProps.editor.state.myStylerData.get('klass')
            });
        }
    }

    handleSave(e) {

        // remove any existing links, expand the selection then replace the URL
        // if it's set
        this.props.editor
            .focus()
            .moveAnchorToStartOfInline()
            .moveFocusToEndOfInline()
            .unwrapInline('styler')
            .wrapInline({
                type: 'styler',
                data: {
                    'style': this.state.style,
                    'klass': this.state.klass
                }
            });
        this.props.editor.moveToEnd();

        setTimeout(() => {
            this.closeModal.call(this);
        }, 250);
    }

    updateStyle(e) {
        this.setState({
            style: e.target.value
        });
    }

    updateKlass(e) {
        this.setState({
            klass: e.target.value
        });
    }

    handleKeyPress(e) {
        if (e.key == 'Enter') {
            this.handleSave.call(this, e);
        }
    }

    render() {
        const buttons = [
            <FlatButton
                label='Cancel'
                onClick={this.handleCancel.bind(this)}
                />,
            <RaisedButton
                label='Save'
                onClick={this.handleSave.bind(this)}
                primary={true}
                />
        ]

        return (
            <Dialog
                modal={true}
                actions={buttons}
                title='Edit Styles'
                open={this.props.editor.state.myStylerModalOpen ? true : false}
                >
                <TextField
                    floatingLabelText="Style"
                    value={this.state.style}
                    onChange={this.updateStyle.bind(this)}
                    onKeyPress={this.handleKeyPress.bind(this)}
                    fullWidth={true}
                    />
                <TextField
                    floatingLabelText="Class"
                    value={this.state.klass}
                    onChange={this.updateKlass.bind(this)}
                    onKeyPress={this.handleKeyPress.bind(this)}
                    fullWidth={true}
                    />
            </Dialog>
        );
    }
};

function StylerPlugin(options) {
    return {
        renderEditor(props, editor, next) {
            const children = next();
            return (
                <React.Fragment>
                    {children}
                    <StylerModal editor={editor} />
                </React.Fragment>
            );
        },
        renderNode(props, editor, next) {
            const {attributes, children} = props;

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

        }
    };
};
export {StylerPlugin, StylerButton, stylerClickHandler};