Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
ff-editor / src / App.js
Size: Mime:
'use strict';
import React from 'react';
import moment from 'moment';
import Immutable from 'immutable';
import { default as cx } from 'classnames';
import { render } from 'react-dom';
import {
    Entity,
    EditorState,
    CompositeDecorator,
    DefaultDraftBlockRenderMap,
    Modifier,
    convertFromRaw,
    convertToRaw } from 'draft-js';
import isSoftNewlineEvent from 'draft-js/lib/isSoftNewlineEvent';
import JSONPretty from 'react-json-pretty';

import RichTextEditor from './react-rte/src/RichTextEditor';
import EditorValue from './react-rte/src/lib/EditorValue';
import LinkDecorator from './react-rte/src/lib/LinkDecorator';
import InaudibleDecorator from './react-rte/src/lib/InaudibleDecorator';

import { stateToHTML } from 'draft-js-export-html';

const HTMLDiff = require('./HTMLDiff');
const decorator = new CompositeDecorator([LinkDecorator, InaudibleDecorator]);

//import { RichTextEditor, decorator } from './react-rte/src/RichTextEditor';
let toolbarConfig = require('./react-rte/src/lib/EditorToolbarConfig');
//toolbarConfig.INLINE_STYLE_BUTTONS.unshift({label: 'Inaudible', style: 'inaudible'});
//
//
import Media from './components/Media';
import TopsBlock from './components/TopsBlock';
import Tags from './components/Tags';

const extendedBlockRenderMap = DefaultDraftBlockRenderMap; //.merge(blockRenderMap);

import styles from './style/main.css';

const App = React.createClass({
    getInitialState() {
        return {
            value: EditorValue.createEmpty(decorator),
            diff: ''
        }
    },
    componentWillMount() {
        let editorState;
        if(this.props.content && this.props.content !== null) {
            const contentState = convertFromRaw(this.props.content);
            editorState = EditorState.createWithContent(contentState, decorator);

            if(this.props.originalContent && this.props.originalContent !== null) {
                this.originalContent = convertFromRaw(this.props.originalContent);
            } else this.originalContent = editorState.getCurrentContent();
        } else {
            editorState = EditorState.createEmpty(decorator);
        }
        this.props.onChange && this.props.onChange(editorState);
    },
    onChange(editorState) {
        if(!this.props.readOnly) this.addTimestamp(editorState);
        else this.props.onChange && this.props.onChange(editorState);
    },
    addTimestamp(editorState, replace) {
        const content = editorState.getCurrentContent();
        const selection = editorState.getSelection();

        const blockKey = selection.getStartKey();
        const block = content.getBlockForKey(blockKey);
        const now = this.props.currentTime || 0;
        const data = block.getData();
        if(replace || (!data.get('timestamp') && data.get('timestamp') !== 0)) {
            console.log('update');
            const newContentState = Modifier.mergeBlockData(
                content,
                selection,
                {timestamp: now}
            );
            const newEditorState = EditorState.push(editorState, newContentState, 'change-block-data');
            const editorStateUpdate = EditorState.forceSelection(
                newEditorState, newContentState.getSelectionAfter()
            );
            //value = RichTextEditor.EditorValue.createFromState(editorStateUpdate);
            this.props.onChange && this.props.onChange(editorStateUpdate);
        } else this.props.onChange && this.props.onChange(editorState);
    },
    setTimestamp() {
        this.addTimestamp(this.props.editorState, true)
    },
    createImmutableEntity(text, _Entity) {
        if(this.props.readOnly) return;
        const editorState = this.props.editorState;
        const content = editorState.getCurrentContent();
        const selection = editorState.getSelection();
        //@TODO: we need to only add extra space needs leading/trailing space
        const newContentState = Modifier.replaceText(
            content,
            selection,
            text,
            undefined,
            _Entity
        );
        const newEditorState = EditorState.push(editorState, newContentState, 'insert-fragment');
        const editorStateUpdate = EditorState.forceSelection(
            newEditorState, newContentState.getSelectionAfter()
        );
        this.props.onChange && this.props.onChange(editorStateUpdate);
    },
    inaudible(event) {
        this.createImmutableEntity(
            '[INAUDIBLE]',
            Entity.create(
                'TOKEN',
                'IMMUTABLE',
                { type: 'inaudible', timestamp: this.props.currentTime || 0 }
            )
        );
    },
    crosstalk(event) {
        this.createImmutableEntity(
            '[CROSSTALK]',
            Entity.create(
                'TOKEN',
                'IMMUTABLE',
                { type: 'crosstalk', timestamp: this.props.currentTime || 0 }
            )
        );
    },
    getRaw() {
        const raw = convertToRaw(this.props.editorState.getCurrentContent());
        return raw;
    },
    blockStyleFn(block) {
        return;
    },
    blockRendererFn(block) {
        const type = block.getType();
        if(type === 'unstyled') {
            return {
                component: TopsBlock,
                editable: !this.props.readOnly,
                props: {
                    timestamp: block.getData().get('timestamp')
                }
            }
        }
        return '';
    },
    scribeKeyHandler(event) {
        return this.props.scribeKeyHandler && this.props.scribeKeyHandler(event);
    },
    onAllClick(event) {
        // Handle clicking on the tags
        if(event.entity && this.props.setCurrentTime) {
            this.props.setCurrentTime(event.entity.timestamp);
        } else return;
    },
    componentWillReceiveProps(nextProps) {
        if(nextProps.trackChanges && nextProps.editorState !== null) {
            const currentContentObj = nextProps.editorState.getCurrentContent();
            if(Immutable.is(currentContentObj, this.originalContent)) return;
            const originalContent = stateToHTML(this.originalContent);
            const rawCurrentContent = convertToRaw(currentContentObj);
            const currentContent = stateToHTML(currentContentObj);
            let diff = HTMLDiff(originalContent, currentContent);
            const tagCheck = /\[INAUDIBLE\]|\[CROSSTALK\]/g;
            let tags = [];
            Object.keys(rawCurrentContent.entityMap).forEach( (key, index) => {
                const entity = rawCurrentContent.entityMap[key];
                if(!entity.data.type) return;
                const value = entity.data.type.toUpperCase();
                const className = styles[entity.data.type];
                const element = `<span class="${className}" data-timestamp="${entity.data.timestamp}">${value}</span>`;
                tags.push(element);
            });
            let iter = 0;
            const delCheck = /\bdel\b/;
            const newdiff = diff.replace(tagCheck, (match, index, source) => {
                if(delCheck.test(source.substr(index-5, 5))) return match;
                const element = tags[iter];
                iter++;
                return element;
            });
            this.setState({diff: newdiff});
        }
    },
    render() {
        let rte = null;
        let edit = null;
        if(this.props.editorState && this.props.editorState !== null) {
            rte = (
            <RichTextEditor
                toolbarConfig={toolbarConfig}
                currentTime={this.props.currentTime}
                editorState={this.props.editorState}
                placeholder={this.props.placeholder}
                scribeKeys={this.props.scribeKeys}
                scribeKeyHandler={this.scribeKeyHandler}
                blockStyleFn={this.blockStyleFn}
                blockRendererFn={this.blockRendererFn}
                blockRenderMap={extendedBlockRenderMap}
                readOnly={this.props.readOnly || false}
                spellCheck={this.props.spellCheck || false}
                setTimestamp={this.setTimestamp}
                onChange={this.onChange} />
            );
            if(this.props.trackChanges && this.state.diff !== '') {
                edit = (
                    <div className={styles['editor-split']}>
                        {rte}
                        <div className={styles['editor-diff-view']}
                        ref="diff"
                        dangerouslySetInnerHTML={{__html: this.state.diff}}
                        />
                    </div>
                );
            } else edit = rte;
        }

        return (
            <div onClick={this.onAllClick}>
                <Tags inaudible={this.inaudible}
                    crosstalk={this.crosstalk}
                    setTimestamp={this.setTimestamp}
                    editorState={this.props.editorState}
                />
                {edit}
            </div>
        );
    }
});

export default App;