diff --git a/examples/code-highlighting/index.js b/examples/code-highlighting/index.js index 90c014bb8..6c09e2830 100644 --- a/examples/code-highlighting/index.js +++ b/examples/code-highlighting/index.js @@ -11,7 +11,41 @@ import initialState from './state.json' */ const NODES = { - code: props =>
{props.children}
+ code: (props) => { + const { attributes, children, editor, node } = props + const language = node.data.get('language') + + function onChange(e) { + const state = editor.getState() + const next = state + .transform() + .setNodeByKey(node.key, { + data: { + language: e.target.value + } + }) + .apply() + editor.onChange(next) + } + + return ( +
+
+          {props.children}
+        
+
+ +
+
+ ) + } } /** @@ -136,8 +170,9 @@ class CodeHighlighting extends React.Component { if (block.type != 'code') return text.characters let characters = text.characters.asMutable() + const language = block.data.get('language') const string = text.text - const grammar = Prism.languages.javascript + const grammar = Prism.languages[language] const tokens = Prism.tokenize(string, grammar) let offset = 0 diff --git a/examples/code-highlighting/state.json b/examples/code-highlighting/state.json index 14ec76035..582d11868 100644 --- a/examples/code-highlighting/state.json +++ b/examples/code-highlighting/state.json @@ -13,6 +13,9 @@ { "kind": "block", "type": "code", + "data": { + "language": "js" + }, "nodes": [ { "kind": "text", diff --git a/lib/components/node.js b/lib/components/node.js index bd1e8e445..ffd7e8147 100644 --- a/lib/components/node.js +++ b/lib/components/node.js @@ -4,7 +4,7 @@ import Debug from 'debug' import React from 'react' import ReactDOM from 'react-dom' import TYPES from '../utils/types' -import Text from './text' +import Leaf from './leaf' import Void from './void' import scrollTo from '../utils/scroll-to' @@ -31,6 +31,7 @@ class Node extends React.Component { */ static propTypes = { + block: React.PropTypes.object, editor: React.PropTypes.object.isRequired, node: React.PropTypes.object.isRequired, renderDecorations: React.PropTypes.func.isRequired, @@ -47,7 +48,7 @@ class Node extends React.Component { static defaultProps = { style: {} - } + }; /** * Constructor. @@ -130,6 +131,17 @@ class Node extends React.Component { return true } + // For text nodes, which can have custom decorations, we need to check to + // see if the block has changed, which has caused the decorations to change. + if ( + props.node.kind == 'text' && + props.block != this.props.block + ) { + const nextRanges = props.node.getDecoratedRanges(props.block, props.renderDecorations) + const ranges = this.props.node.getDecoratedRanges(this.props.block, this.props.renderDecorations) + if (!ranges.equals(nextRanges)) return true + } + // Otherwise, don't update. return false } @@ -216,10 +228,12 @@ class Node extends React.Component { */ renderNode = (child) => { - const { editor, renderDecorations, renderMark, renderNode, state } = this.props + const { editor, node, renderDecorations, renderMark, renderNode, state } = this.props + const block = node.kind == 'block' ? node : this.props.block return ( { - const { node, editor, renderDecorations, renderMark, state } = this.props + const { node, block, renderDecorations } = this.props + const ranges = node.getDecoratedRanges(block, renderDecorations) + let offset = 0 + + const leaves = ranges.map((range, i, original) => { + const leaf = this.renderLeaf(ranges, range, i, offset) + offset += range.text.length + return leaf + }) + return ( - + {leaves} + + ) + } + + /** + * Render a single leaf node given a `range` and `offset`. + * + * @param {List} ranges + * @param {Range} range + * @param {Number} index + * @param {Number} offset + * @return {Element} leaf + */ + + renderLeaf = (ranges, range, index, offset) => { + const { node, renderMark, state } = this.props + const text = range.text + const marks = range.marks + + return ( + ) } @@ -298,6 +345,8 @@ class Node extends React.Component { /** * Export. + * + * @type {Component} */ export default Node diff --git a/lib/components/text.js b/lib/components/text.js deleted file mode 100644 index 4175d145b..000000000 --- a/lib/components/text.js +++ /dev/null @@ -1,109 +0,0 @@ - -import Leaf from './leaf' -import React from 'react' -import { List } from 'immutable' - -/** - * Text. - */ - -class Text extends React.Component { - - /** - * Properties. - */ - - static propTypes = { - editor: React.PropTypes.object.isRequired, - node: React.PropTypes.object.isRequired, - renderDecorations: React.PropTypes.func.isRequired, - renderMark: React.PropTypes.func.isRequired, - state: React.PropTypes.object.isRequired - }; - - /** - * Should the component update? - * - * @param {Object} props - * @param {Object} state - * @return {Boolean} shouldUpdate - */ - - shouldComponentUpdate(props, state) { - return ( - props.node != this.props.node || - (props.state.isFocused && props.state.selection.hasEdgeIn(props.node)) - ) - } - - /** - * Render. - * - * @return {Element} element - */ - - render() { - const { node } = this.props - return ( - - {this.renderLeaves()} - - ) - } - - /** - * Render the leaf nodes. - * - * @return {Array} leaves - */ - - renderLeaves() { - const { node, state, renderDecorations } = this.props - const block = state.document.getClosestBlock(node) - const ranges = node.getDecoratedRanges(block, renderDecorations) - - return ranges.map((range, i, original) => { - const previous = original.slice(0, i) - const offset = previous.size - ? previous.map(r => r.text).join('').length - : 0 - return this.renderLeaf(ranges, range, i, offset) - }) - } - - /** - * Render a single leaf node given a `range` and `offset`. - * - * @param {List} ranges - * @param {Range} range - * @param {Number} index - * @param {Number} offset - * @return {Element} leaf - */ - - renderLeaf(ranges, range, index, offset) { - const { node, renderMark, state } = this.props - const text = range.text - const marks = range.marks - - return ( - - ) - } - -} - -/** - * Export. - */ - -export default Text