Home Reference Source

application/components/common/rich-editor2/util/draft-serializer.js

import {Block, Mark, Node, Value} from 'slate';
import {Set} from 'immutable';
import uuid from 'uuid';

let inList = false;
let parentList;

function makeNodes(block, entityMap) {
    const {key, text, entityRanges, inlineStyleRanges} = block;
    let nodes = []
    let type = 'paragraph';
    switch (block.type) {
        case 'header-one':
            type = 'heading-one';
            break;
        case 'header-two':
            type = 'heading-two';
            break;
        case 'header-three':
            type = 'heading-three';
            break;
        case 'header-four':
            type = 'heading-four';
            break;
        case 'header-five':
            type = 'heading-five';
            break;
        case 'header-six':
            type = 'heading-six';
            break;
        case 'unordered-list-item':
        case 'ordered-list-item':
            type = 'list-item';
            break;
    }

    if (!inList && (block.type == 'unordered-list-item' || block.type == 'ordered-list-item')) {
        inList = true;
        parentList = {
            object: 'block',
            type: block.type == 'unordered-list-item' ? 'bulleted-list' : 'ordered-list',
            data: {},
            nodes: []
        };
    }
    if (inList && block.type != 'unordered-list-item' && block.type != 'ordered-list-item') {
        inList = false;
        nodes = [];
        nodes.push(parentList);
        parentList = null;
    }

    let inlines = [];
    let blocks = [];
    let textPointer = 0;

    if (entityRanges.length || inlineStyleRanges.length) {
        entityRanges.forEach((range) => {
            const {key, length, offset} = range;
            const entity = entityMap[key];

            if (length && entity.type == 'COPYQUOTE') {
                const subStr = text.substring(offset, offset + length);
                const cq = makeCqEntity(subStr, entity.data);

                inlines[offset] = {
                    'offset': offset,
                    'next': offset + length,
                    'node': cq
                };

            } else if (length && entity.type == 'LINK') {
                const subStr = text.substring(offset, offset + length);
                const link = makeLinkEntity(subStr, entity.data);

                inlines[offset] = {
                    'offset': offset,
                    'next': offset + length,
                    'node': link
                };
            } else if (length == 1 && entity.type == 'TOKEN' && entity.data.customType == 'embed') {
                const content = entity.data.content;
                blocks.push(makeEmbedEntity(content));
            } else if (length == 1 && entity.type == 'TOKEN' && entity.data.customType == 'media') {
                blocks.push(makeMediaEntity(entity.data));
            } else {
                console.log('ENTITY', entity);
            }
        });

        const defaultStyles = [
            'BOLD', 'ITALIC', 'UNDERLINE',
        ];
        inlineStyleRanges.forEach((inline) => {
            const {style, offset, length} = inline;
            if (defaultStyles.indexOf(style) !== -1) {
                const subStr = text.substring(offset, offset + length);
                inlines[offset] = {
                    'offset': offset,
                    'next': offset + length,
                    'node': makeTextLeaf(subStr, [
                        {
                            object: 'mark',
                            type: style.toLowerCase()
                        }
                    ])
                }
            }
        });

        let leaves = [];

        inlines.forEach((inline) => {
            const subStr = text.substring(textPointer, inline.offset);
            leaves.push(makeTextLeaf(subStr));
            textPointer = inline.next;
            leaves.push(inline.node);
        });

        if (textPointer < text.length) {
            leaves.push(makeTextLeaf(text.substring(textPointer)));
        }
        if (parentList) {
            parentList.nodes.push(makeParagraph(leaves, type));
        } else {
            nodes.push(makeParagraph(leaves, type));
        }

        blocks.forEach((block) => {
            if (parentList) {
                parentList.nodes.push(block);
            } else {
                nodes.push(block);
            }
        });

    } else {
        if (parentList) {
            parentList.nodes.push(makeParagraph([makeTextLeaf(text)], type));
        } else {
            nodes.push(makeParagraph([makeTextLeaf(text)], type));
        }
    }
    return nodes;
}

function makeTextLeaf(text, marks = []) {
    return {
        object: 'text',
        leaves: [
            {
                object: 'leaf',
                text: text,
                marks: marks
            }
        ]
    };
}

function makeParagraph(leaves, ofType = 'paragraph') {
    return {
        object: 'block',
        type: ofType,
        data: {},
        nodes: leaves
    }
}

function makeLinkEntity(text, data) {
    return {
        object: 'inline',
        type: 'anchor',
        data: {
            href: data.url,
            target: data.target
        },
        nodes: [makeTextLeaf(text)]
    };
}

function makeEmbedEntity(text) {
    return {
        object: 'block',
        type: 'embed',
        nodes: [
            {
                object: 'text',
                leaves: [
                    {
                        text: text
                    }
                ]
            }
        ]
    }
}

function makeNoteEntity() {

}

function makeCqEntity(text, data) {
    return {
        object: 'inline',
        type: 'cq',
        data: {
            'name': data.user,
            'date': data.created_at,
            'version': data.version
        },
        nodes: [makeTextLeaf(text)]
    };
}

function makeMediaEntity(data) {
    let width = '100';
    if (data.align == 'left' || data.align == 'right') {
        width = '50';
    }

    return {
        object: 'block',
        type: 'media',
        data: {
            alignment: data.align ? data.align : '',
            width: width,
            link: data.linkTo ? data.linkTo : '',
            uuid: data.mediaUuid ? data.mediaUuid : uuid.v4(),
            src: data.origSrc
        }
    };
}

// https://github.com/ianstormtaylor/slate/blob/master/packages/slate-plain-serializer/src/index.js
function deserialize(json, options = {}) {
    console.log(json);

    let out = {
        object: 'value',
        document: {
            object: 'document',
            data: {},
            nodes: []
        }
    };

    json.blocks.forEach((block) => {
        const nodes = makeNodes(block, json.entityMap);
        nodes.map(node => out.document.nodes.push(node));
    });

    // let out = {
    //     object: 'value',
    //     document: {
    //         object: 'document',
    //         data: {},
    //         nodes: [
    //             {
    //                 object: 'block',
    //                 type: 'paragraph',
    //                 data: {},
    //                 nodes: [
    //                     {
    //                         object: 'text',
    //                         leaves: [
    //                             {
    //                                 object: 'leaf',
    //                                 text: 'Hello There',
    //                                 marks: []
    //                             }
    //                         ]
    //                     }
    //                 ]
    //             }
    //         ]
    //     }
    // };

    return Value.fromJSON(out);
};

function serialize(node, options = {}) {
    return node;
}

export default {
    deserialize,
    serialize
};