Created
February 26, 2016 04:03
-
-
Save hellendag/6cd425613caabb7f238d to your computer and use it in GitHub Desktop.
Drag/Drop Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment