1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-02-23 16:55:23 +01:00
Ian Storm Taylor ccac6102a5 fixes
2016-08-14 13:21:46 -07:00

215 lines
4.2 KiB
JavaScript

import { Editor, Html, Raw } from '../..'
import React from 'react'
import initialState from './state.json'
/**
* Define a schema.
*
* @type {Object}
*/
const schema = {
nodes: {
'bulleted-list': props => <ul {...props.attributes}>{props.children}</ul>,
'code': props => <pre><code {...props.attributes}>{props.children}</code></pre>,
'heading-one': props => <h1 {...props.attributes}>{props.children}</h1>,
'heading-two': props => <h2 {...props.attributes}>{props.children}</h2>,
'heading-three': props => <h3 {...props.attributes}>{props.children}</h3>,
'heading-four': props => <h4 {...props.attributes}>{props.children}</h4>,
'heading-five': props => <h5 {...props.attributes}>{props.children}</h5>,
'heading-six': props => <h6 {...props.attributes}>{props.children}</h6>,
'list-item': props => <li {...props.attributes}>{props.children}</li>,
'numbered-list': props => <ol {...props.attributes}>{props.children}</ol>,
'quote': props => <blockquote {...props.attributes}>{props.children}</blockquote>,
'link': (props) => {
const { data } = props.node
const href = data.get('href')
return <a href={href} {...props.attributes}>{props.children}</a>
}
},
marks: {
bold: props => <strong>{props.children}</strong>,
code: props => <code>{props.children}</code>,
italic: props => <em>{props.children}</em>,
underlined: props => <u>{props.children}</u>,
}
}
/**
* Tags to blocks.
*
* @type {Object}
*/
const BLOCK_TAGS = {
p: 'paragraph',
li: 'list-item',
ul: 'bulleted-list',
ol: 'numbered-list',
blockquote: 'quote',
pre: 'code',
h1: 'heading-one',
h2: 'heading-two',
h3: 'heading-three',
h4: 'heading-four',
h5: 'heading-five',
h6: 'heading-six'
}
/**
* Tags to marks.
*
* @type {Object}
*/
const MARK_TAGS = {
strong: 'bold',
em: 'italic',
u: 'underline',
s: 'strikethrough',
code: 'code'
}
/**
* Serializer rules.
*
* @type {Array}
*/
const RULES = [
{
deserialize(el, next) {
const block = BLOCK_TAGS[el.tagName]
if (!block) return
return {
kind: 'block',
type: block,
nodes: next(el.children)
}
}
},
{
deserialize(el, next) {
const mark = MARK_TAGS[el.tagName]
if (!mark) return
return {
kind: 'mark',
type: mark,
nodes: next(el.children)
}
}
},
{
// Special case for code blocks, which need to grab the nested children.
deserialize(el, next) {
if (el.tagName != 'pre') return
const code = el.children[0]
const children = code && code.tagName == 'code'
? code.children
: el.children
return {
kind: 'block',
type: 'code',
nodes: next(children)
}
}
},
{
// Special case for links, to grab their href.
deserialize(el, next) {
if (el.tagName != 'a') return
return {
kind: 'inline',
type: 'link',
nodes: next(el.children),
data: {
href: el.attribs.href
}
}
}
}
]
/**
* Create a new HTML serializer with `RULES`.
*
* @type {Html}
*/
const serializer = new Html({ rules: RULES })
/**
* The pasting html example.
*
* @type {Component}
*/
class PasteHtml extends React.Component {
/**
* Deserialize the raw initial state.
*
* @type {Object}
*/
state = {
state: Raw.deserialize(initialState, { terse: true })
};
/**
* On change, save the new state.
*
* @param {State} state
*/
onChange = (state) => {
this.setState({ state })
}
/**
* On paste, deserialize the HTML and then insert the fragment.
*
* @param {Event} e
* @param {Object} data
* @param {State} state
*/
onPaste = (e, data, state) => {
if (data.type != 'html') return
const { document } = serializer.deserialize(data.html)
return state
.transform()
.insertFragment(document)
.apply()
}
/**
* Render.
*
* @return {Component}
*/
render = () => {
return (
<div className="editor">
<Editor
schema={schema}
state={this.state.state}
onPaste={this.onPaste}
onChange={this.onChange}
/>
</div>
)
}
}
/**
* Export.
*/
export default PasteHtml