Skip to content

Instantly share code, notes, and snippets.

@hellendag
Created February 26, 2016 04:03
Show Gist options
  • Select an option

  • Save hellendag/6cd425613caabb7f238d to your computer and use it in GitHub Desktop.

Select an option

Save hellendag/6cd425613caabb7f238d to your computer and use it in GitHub Desktop.

Revisions

  1. Isaac Salier-Hellendag created this gist Feb 26, 2016.
    223 changes: 223 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,223 @@
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8" />
    <title>Draft • Decorators</title>
    <link rel="stylesheet" href="../../dist/Draft.css" />
    </head>
    <body>
    <div id="target"></div>
    <script src="../../node_modules/react/dist/react.js"></script>
    <script src="../../node_modules/react-dom/dist/react-dom.js"></script>
    <script src="../../node_modules/immutable/dist/immutable.js"></script>
    <script src="../../node_modules/babel-core/browser.js"></script>
    <script src="../../dist/Draft.js"></script>
    <script type="text/babel">
    'use strict';

    const {CompositeDecorator, Editor, EditorState, Modifier, SelectionState} = Draft;


    const Draggable = (props) => {
    const onDragStart = (e) => {
    e.dataTransfer.dropEffect = 'move';
    e.dataTransfer.setData("text", props.block.key);
    };
    return (
    <div
    contentEditable={false}
    onDragStart={onDragStart}
    draggable="true"
    style={styles.draggable}
    />
    )
    };

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

    this.state = {
    editorState: EditorState.createEmpty(),
    };

    this.focus = () => this.refs.editor.focus();
    this.onChange = (editorState) => this.setState({editorState});
    this.logState = () => console.log(this.state.editorState.toJS());
    this.drop = this._drop.bind(this);

    this.blockRenderer = (contentBlock) => {
    const type = contentBlock.getType();
    if (type === 'draggable') {
    return {
    component: Draggable,
    props: {
    onDrop: this.drop,
    }
    };
    }
    }
    }

    addBlock() {
    const {editorState} = this.state;
    const contentState = editorState.getCurrentContent();
    const selectionState = editorState.getSelection();

    const afterRemoval = Modifier.removeRange(
    contentState,
    selectionState,
    'backward'
    );

    const targetSelection = afterRemoval.getSelectionAfter();
    const afterSplit = Modifier.splitBlock(
    afterRemoval,
    targetSelection
    );
    const insertionTarget = afterSplit.getSelectionAfter();

    const insertText = Modifier.insertText(
    afterSplit,
    insertionTarget,
    ' '
    );

    const asMedia = Modifier.setBlockType(
    insertText,
    insertText.getSelectionAfter(),
    'draggable'
    );

    this.setState({
    editorState: EditorState.push(
    editorState,
    asMedia,
    'insert-fragment'
    ),
    });
    }

    _drop(e, dropSelection) {
    const blockKey = e.dataTransfer.getData("text");
    // Set timeout to allow cursor/selection to move to drop location

    // Get content, selection, block
    const {editorState} = this.state;
    const content = editorState.getCurrentContent();
    const block = content.getBlockForKey(blockKey);

    const draggedRange = new SelectionState({
    anchorKey: blockKey,
    anchorOffset: 0,
    focusKey: blockKey,
    focusOffset: block.getLength(),
    isBackward: false,
    });

    // Split on drop location and set block type
    const afterFirstSplit = Modifier.splitBlock(content, dropSelection);
    const targetSelection = afterFirstSplit.getSelectionAfter();
    const afterSecondSplit = Modifier.splitBlock(
    afterFirstSplit,
    targetSelection
    );
    const afterMove = Modifier.moveText(
    afterSecondSplit,
    draggedRange,
    targetSelection
    );
    const resetAsDraggable = Modifier.setBlockType(
    afterMove,
    afterMove.getSelectionAfter(),
    block.getType()
    );

    const blockAfterDraggable = resetAsDraggable.getBlockAfter(blockKey);
    const cursorKey = blockAfterDraggable.getKey();
    const moveSelection = resetAsDraggable.merge({
    selectionBefore: dropSelection,
    selectionAfter: new SelectionState({
    anchorKey: cursorKey,
    anchorOffset: 0,
    focusKey: cursorKey,
    focusOffset: 0,
    isBackward: false,
    }),
    });

    this.setState({
    editorState: EditorState.push(
    editorState,
    moveSelection,
    'insert-fragment'
    ),
    });

    return true;
    }

    render() {
    return (
    <div style={styles.root}>
    <div style={styles.editor}
    onClick={this.focus}
    onDragOver={(e) => e.preventDefault()}>
    <Editor
    blockRendererFn={this.blockRenderer}
    editorState={this.state.editorState}
    handleDrop={this.drop}
    onChange={this.onChange}
    placeholder="Write a tweet..."
    ref="editor"
    spellCheck={true}
    />
    </div>
    <input
    onClick={this.logState}
    style={styles.button}
    type="button"
    value="Log State"
    />
    <input
    onClick={this.addBlock.bind(this)}
    style={styles.button}
    type="button"
    value="Add block"
    />
    </div>
    );
    }
    }

    const styles = {
    root: {
    fontFamily: '\'Helvetica\', sans-serif',
    padding: 20,
    width: 600,
    },
    editor: {
    border: '1px solid #ddd',
    cursor: 'text',
    fontSize: 16,
    minHeight: 40,
    padding: 10,
    },
    draggable: {
    backgroundColor: 'rgba(98, 177, 254, 1.0)',
    width: 40,
    height: 40,
    },
    button: {
    marginTop: 10,
    textAlign: 'center',
    }
    };

    ReactDOM.render(
    <MarkdownEditorExample />,
    document.getElementById('target')
    );
    </script>
    </body>
    </html>