1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-22 15:02:51 +02:00

initial plain text paste support

This commit is contained in:
Ian Storm Taylor
2016-06-24 12:06:59 -07:00
parent a0f5369525
commit 9e4f452c1c
3 changed files with 82 additions and 23 deletions

View File

@@ -19,6 +19,7 @@ class Content extends React.Component {
onBeforeInput: React.PropTypes.func, onBeforeInput: React.PropTypes.func,
onChange: React.PropTypes.func, onChange: React.PropTypes.func,
onKeyDown: React.PropTypes.func, onKeyDown: React.PropTypes.func,
onPaste: React.PropTypes.func,
onSelect: React.PropTypes.func, onSelect: React.PropTypes.func,
renderMark: React.PropTypes.func.isRequired, renderMark: React.PropTypes.func.isRequired,
renderNode: React.PropTypes.func.isRequired, renderNode: React.PropTypes.func.isRequired,
@@ -51,13 +52,49 @@ class Content extends React.Component {
} }
/** /**
* On key down, bubble up. * On certain events, bubble up.
*
* @param {String} name
* @param {Event} e
*/
onEvent(name, e) {
this.props[name](e)
}
/**
* On paste, determine the type and bubble up.
* *
* @param {Event} e * @param {Event} e
*/ */
onKeyDown(e) { onPaste(e) {
this.props.onKeyDown(e) e.preventDefault()
const data = e.clipboardData
const { types } = data
const paste = {}
// Handle files.
if (data.files.length != 0) {
paste.type = 'files'
paste.files = data.files
}
// Treat it as rich text if there is HTML content.
else if (types.includes('text/plain') && types.includes('text/html')) {
paste.type = 'html'
paste.text = data.getData('text/plain')
paste.html = data.getData('text/html')
}
// Treat everything else as plain text.
else {
paste.type = 'text'
paste.text = data.getData('text/plain')
}
paste.data = data
this.props.onPaste(e, paste)
} }
/** /**
@@ -105,16 +142,6 @@ class Content extends React.Component {
this.onChange(state) this.onChange(state)
} }
/**
* On before input, add the character to the state.
*
* @param {Event} e
*/
onBeforeInput(e) {
this.props.onBeforeInput(e)
}
/** /**
* Render the editor content. * Render the editor content.
* *
@@ -136,14 +163,12 @@ class Content extends React.Component {
return ( return (
<div <div
contentEditable contentEditable suppressContentEditableWarning
suppressContentEditableWarning
spellCheck={false}
data-type='content'
onKeyDown={e => this.onKeyDown(e)}
onSelect={e => this.onSelect(e)}
onBeforeInput={e => this.onBeforeInput(e)}
style={style} style={style}
onSelect={e => this.onSelect(e)}
onPaste={e => this.onPaste(e)}
onKeyDown={e => this.onEvent('onKeyDown', e)}
onBeforeInput={e => this.onEvent('onBeforeInput', e)}
> >
{children} {children}
</div> </div>

View File

@@ -80,13 +80,13 @@ class Editor extends React.Component {
* state if one of them chooses to. * state if one of them chooses to.
* *
* @param {String} name * @param {String} name
* @param {Event} e * @param {Mixed} ...args
*/ */
onEvent(name, e) { onEvent(name, ...args) {
for (const plugin of this.state.plugins) { for (const plugin of this.state.plugins) {
if (!plugin[name]) continue if (!plugin[name]) continue
const newState = plugin[name](e, this.props.state, this) const newState = plugin[name](...args, this.props.state, this)
if (!newState) continue if (!newState) continue
this.props.onChange(newState) this.props.onChange(newState)
break break
@@ -106,6 +106,7 @@ class Editor extends React.Component {
onChange={state => this.onChange(state)} onChange={state => this.onChange(state)}
renderMark={mark => this.renderMark(mark)} renderMark={mark => this.renderMark(mark)}
renderNode={node => this.renderNode(node)} renderNode={node => this.renderNode(node)}
onPaste={(e, paste) => this.onEvent('onPaste', e, paste)}
onBeforeInput={e => this.onEvent('onBeforeInput', e)} onBeforeInput={e => this.onEvent('onBeforeInput', e)}
onKeyDown={e => this.onEvent('onKeyDown', e)} onKeyDown={e => this.onEvent('onKeyDown', e)}
/> />

View File

@@ -127,6 +127,39 @@ export default {
} }
}, },
/**
* The core `onPaste` handler.
*
* @param {Event} e
* @param {Object} paste
* @param {State} state
* @param {Editor} editor
* @return {State or Null} newState
*/
onPaste(e, paste, state, editor) {
// Don't handle files in core.
if (paste.type == 'files') return
// If the paste type is html...
if (paste.type == 'html') {
// First, check for a match in the clipboard.
// Otherwise, check if we have a paste deserializer.
}
// Otherwise, just insert the plain text splitting at characters.
let transform = state.transform()
paste.text
.split('\n')
.forEach((block, i) => {
if (i > 0) transform = transform.splitBlock()
transform = transform.insertText(block)
})
return transform.apply()
},
/** /**
* Default `node` renderer. * Default `node` renderer.
* *