mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-04-21 22:02:05 +02:00
add plaintext example
This commit is contained in:
parent
0caee5b687
commit
1413d57a04
28
Makefile
28
Makefile
@ -1,6 +1,7 @@
|
||||
|
||||
# Binaries.
|
||||
bin = ./node_modules/.bin
|
||||
babel = $(bin)/babel
|
||||
browserify = $(bin)/browserify
|
||||
standard = $(bin)/standard
|
||||
mocha = $(bin)/mocha
|
||||
@ -19,12 +20,21 @@ endif
|
||||
|
||||
# Remove the generated files.
|
||||
clean:
|
||||
@ rm -rf ./node_modules
|
||||
@ rm -rf ./dist ./node_modules
|
||||
|
||||
# Build the examples.
|
||||
examples: ./node_modules
|
||||
# Build the source.
|
||||
dist: ./node_modules $(shell find ./lib)
|
||||
@ $(babel) --out-dir ./dist ./lib
|
||||
@ touch ./dist
|
||||
|
||||
# Build the basic example.
|
||||
example-basic: ./node_modules
|
||||
@ $(browserify) --debug --transform babelify --outfile ./examples/basic/build.js ./examples/basic/index.js
|
||||
|
||||
# Build the plaintext example.
|
||||
example-plaintext: ./node_modules
|
||||
@ $(browserify) --debug --transform babelify --outfile ./examples/plaintext/build.js ./examples/plaintext/index.js
|
||||
|
||||
# Lint the sources files with Standard JS.
|
||||
lint: ./node_modules
|
||||
@ $(standard) ./lib
|
||||
@ -36,7 +46,7 @@ node_modules: ./package.json
|
||||
|
||||
# Build the test source.
|
||||
test/support/build.js: ./node_modules $(shell find ./lib) ./test/browser.js
|
||||
@ $(browserify) --transform babelify --outfile ./test/support/build.js ./test/browser.js
|
||||
@ $(browserify) --debug --transform babelify --outfile ./test/support/build.js ./test/browser.js
|
||||
|
||||
# Run the tests.
|
||||
test: test-browser test-server
|
||||
@ -49,9 +59,13 @@ test-browser: ./node_modules ./test/support/build.js
|
||||
test-server: ./node_modules
|
||||
@ $(mocha) --reporter spec --timeout 5000 ./test/server.js
|
||||
|
||||
# Watch the examples.
|
||||
watch-examples: ./node_modules
|
||||
@ $(MAKE) examples browserify=$(watchify)
|
||||
# Watch the basic example.
|
||||
watch-example-basic: ./node_modules
|
||||
@ $(MAKE) example-basic browserify=$(watchify)
|
||||
|
||||
# Watch the plaintext example.
|
||||
watch-example-plaintext: ./node_modules
|
||||
@ $(MAKE) example-plaintext browserify=$(watchify)
|
||||
|
||||
# Phony targets.
|
||||
.PHONY: examples
|
||||
|
@ -75,9 +75,6 @@ function renderNode(node) {
|
||||
)
|
||||
}
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Unknown node type "${node.type}".`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,9 +85,6 @@ function renderMark(mark) {
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Unknown mark type "${mark.type}".`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,6 +106,7 @@ class App extends React.Component {
|
||||
state={this.state.state}
|
||||
onChange={(state) => {
|
||||
console.log('State:', state.toJS())
|
||||
console.log('Content:', Raw.serialize(state))
|
||||
this.setState({ state })
|
||||
}}
|
||||
/>
|
||||
|
10
examples/plaintext/index.html
Normal file
10
examples/plaintext/index.html
Normal file
@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Editor | Basic Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<main></main>
|
||||
<script src="build.js"></script>
|
||||
</body>
|
||||
</html>
|
44
examples/plaintext/index.js
Normal file
44
examples/plaintext/index.js
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
import Editor from '../..'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { Plaintext } from '../..'
|
||||
|
||||
/**
|
||||
* State.
|
||||
*/
|
||||
|
||||
const state = 'A string of plain text.'
|
||||
|
||||
/**
|
||||
* App.
|
||||
*/
|
||||
|
||||
class App extends React.Component {
|
||||
|
||||
state = {
|
||||
state: Plaintext.deserialize(state)
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Editor
|
||||
state={this.state.state}
|
||||
onChange={(state) => {
|
||||
console.log('State:', state.toJS())
|
||||
console.log('Content:', Plaintext.serialize(state))
|
||||
this.setState({ state })
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach.
|
||||
*/
|
||||
|
||||
const app = <App />
|
||||
const root = document.body.querySelector('main')
|
||||
ReactDOM.render(app, root)
|
@ -46,6 +46,16 @@ class Editor extends React.Component {
|
||||
this.setState({ plugins })
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the editor's current `state`.
|
||||
*
|
||||
* @return {State} state
|
||||
*/
|
||||
|
||||
getState() {
|
||||
return this.props.state
|
||||
}
|
||||
|
||||
/**
|
||||
* When the `state` changes, pass through plugins, then bubble up.
|
||||
*
|
||||
@ -65,16 +75,6 @@ class Editor extends React.Component {
|
||||
this.props.onChange(state)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the editor's current `state`.
|
||||
*
|
||||
* @return {State} state
|
||||
*/
|
||||
|
||||
getState() {
|
||||
return this.props.state
|
||||
}
|
||||
|
||||
/**
|
||||
* When an event by `name` fires, pass it through the plugins, and update the
|
||||
* state if one of them chooses to.
|
||||
@ -102,15 +102,47 @@ class Editor extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<Content
|
||||
renderMark={this.props.renderMark}
|
||||
renderNode={this.props.renderNode}
|
||||
state={this.props.state}
|
||||
onChange={state => this.onChange(state)}
|
||||
onKeyDown={e => this.onEvent('onKeyDown', e)}
|
||||
renderMark={mark => this.renderMark(mark)}
|
||||
renderNode={node => this.renderNode(node)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a `node`, cascading through the plugins.
|
||||
*
|
||||
* @param {Node} node
|
||||
* @return {Component} component
|
||||
*/
|
||||
|
||||
renderNode(node) {
|
||||
for (const plugin of this.state.plugins) {
|
||||
if (!plugin.renderNode) continue
|
||||
const component = plugin.renderNode(node, this.props.state, this)
|
||||
if (component) return component
|
||||
throw new Error('No renderer found for node.')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a `mark`, cascading through the plugins.
|
||||
*
|
||||
* @param {Mark} mark
|
||||
* @return {Object} style
|
||||
*/
|
||||
|
||||
renderMark(mark) {
|
||||
for (const plugin of this.state.plugins) {
|
||||
if (!plugin.renderMark) continue
|
||||
const style = plugin.renderMark(mark, this.props.state, this)
|
||||
if (style) return style
|
||||
throw new Error('No renderer found for mark.')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the editor's current plugins from `props` when they change.
|
||||
*
|
||||
|
30
lib/index.js
30
lib/index.js
@ -1,36 +1,24 @@
|
||||
|
||||
/**
|
||||
* Components.
|
||||
* Editor.
|
||||
*/
|
||||
|
||||
import Editor from './components/editor'
|
||||
export default Editor
|
||||
|
||||
/**
|
||||
* Models.
|
||||
*/
|
||||
|
||||
import Character from './models/character'
|
||||
import Node from './models/node'
|
||||
import Selection from './models/selection'
|
||||
import State from './models/state'
|
||||
import Text from './models/text'
|
||||
export { default as Character } from './models/character'
|
||||
export { default as Node } from './models/node'
|
||||
export { default as Selection } from './models/selection'
|
||||
export { default as State } from './models/state'
|
||||
export { default as Text } from './models/text'
|
||||
|
||||
/**
|
||||
* Serializers.
|
||||
*/
|
||||
|
||||
import Raw from './serializers/raw'
|
||||
|
||||
/**
|
||||
* Export.
|
||||
*/
|
||||
|
||||
export default Editor
|
||||
export {
|
||||
Character,
|
||||
Node,
|
||||
Raw,
|
||||
Selection,
|
||||
State,
|
||||
Text
|
||||
}
|
||||
export { default as Raw } from './serializers/raw'
|
||||
export { default as Plaintext } from './serializers/plaintext'
|
||||
|
@ -66,9 +66,7 @@ class Node extends NodeRecord {
|
||||
get text() {
|
||||
return this
|
||||
.filterNodes(node => node.type == 'text')
|
||||
.map(node => node.characters)
|
||||
.flatten()
|
||||
.map(character => character.text)
|
||||
.map(node => node.text)
|
||||
.join('')
|
||||
}
|
||||
|
||||
|
@ -459,12 +459,14 @@ class State extends StateRecord {
|
||||
let { characters } = startNode
|
||||
|
||||
// Create a list of the new characters, with the right marks.
|
||||
const { marks } = characters.get(startOffset)
|
||||
const marks = characters.has(startOffset)
|
||||
? characters.get(startOffset).marks
|
||||
: null
|
||||
|
||||
const newCharacters = data.split('').reduce((list, char) => {
|
||||
return list.push(Character.create({
|
||||
text: char,
|
||||
marks
|
||||
}))
|
||||
const obj = { text: char }
|
||||
if (marks) obj.marks = marks
|
||||
return list.push(Character.create(obj))
|
||||
}, Character.createList())
|
||||
|
||||
// Splice in the new characters.
|
||||
|
@ -1,4 +1,5 @@
|
||||
|
||||
import React from 'react'
|
||||
import keycode from 'keycode'
|
||||
import { IS_WINDOWS, IS_MAC } from '../utils/environment'
|
||||
|
||||
@ -62,6 +63,28 @@ export default {
|
||||
console.log('Unhandled key down.')
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Default `node` renderer.
|
||||
*
|
||||
* @param {Node} node
|
||||
* @return {Component} component
|
||||
*/
|
||||
|
||||
renderNode(node) {
|
||||
return (props) => <div>{props.children}</div>
|
||||
},
|
||||
|
||||
/**
|
||||
* Default `mark` renderer.
|
||||
*
|
||||
* @param {Mark} mark
|
||||
* @return {Object} style
|
||||
*/
|
||||
|
||||
renderMark(mark) {
|
||||
return {}
|
||||
}
|
||||
|
||||
}
|
||||
|
53
lib/serializers/plaintext.js
Normal file
53
lib/serializers/plaintext.js
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
import Character from '../models/character'
|
||||
import Node from '../models/node'
|
||||
import Text from '../models/text'
|
||||
import State from '../models/state'
|
||||
|
||||
/**
|
||||
* Serialize a `state` into a plaintext `string`.
|
||||
*
|
||||
* @param {State} state
|
||||
* @return {String} string
|
||||
*/
|
||||
|
||||
function serialize(state) {
|
||||
return state.nodes
|
||||
.map(node => node.text)
|
||||
.join('\n')
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize a plaintext `string` into a `state`.
|
||||
*
|
||||
* @param {String} string
|
||||
* @return {State} state
|
||||
*/
|
||||
|
||||
function deserialize(string) {
|
||||
const characters = string
|
||||
.split('')
|
||||
.reduce((list, char) => {
|
||||
return list.push(Character.create({ text: char }))
|
||||
}, Character.createList())
|
||||
|
||||
const text = Text.create({ characters })
|
||||
const texts = Node.createMap([text])
|
||||
const node = Node.create({
|
||||
type: 'paragraph',
|
||||
nodes: texts,
|
||||
})
|
||||
|
||||
const nodes = Node.createMap([node])
|
||||
const state = State.create({ nodes })
|
||||
return state
|
||||
}
|
||||
|
||||
/**
|
||||
* Export.
|
||||
*/
|
||||
|
||||
export default {
|
||||
serialize,
|
||||
deserialize
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
"uid": "0.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.10.1",
|
||||
"babel-core": "^6.9.1",
|
||||
"babel-polyfill": "^6.9.1",
|
||||
"babel-preset-es2015": "^6.9.0",
|
||||
|
Loading…
x
Reference in New Issue
Block a user