From dea734ec21994335d2f6ba76a2fb214735fe5691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A1ssio=20Zen?= <cassiozen@gmail.com> Date: Wed, 17 Aug 2016 09:52:06 -0300 Subject: [PATCH] updated slate version --- src/components/Widgets/MarkdownControl.js | 7 +- .../RawEditor/index.js | 119 +++++++++--------- .../VisualEditor/index.js | 19 +-- .../VisualEditor/localRenderers.js | 60 --------- .../VisualEditor/schema.js | 65 ++++++++++ 5 files changed, 133 insertions(+), 137 deletions(-) delete mode 100644 src/components/Widgets/MarkdownControlElements/VisualEditor/localRenderers.js create mode 100644 src/components/Widgets/MarkdownControlElements/VisualEditor/schema.js diff --git a/src/components/Widgets/MarkdownControl.js b/src/components/Widgets/MarkdownControl.js index 0e7e9850..a4c6f22a 100644 --- a/src/components/Widgets/MarkdownControl.js +++ b/src/components/Widgets/MarkdownControl.js @@ -5,17 +5,17 @@ import { connect } from 'react-redux'; import { switchVisualMode } from '../../actions/editor'; class MarkdownControl extends React.Component { - constructor(props){ + constructor(props) { super(props); this.useVisualEditor = this.useVisualEditor.bind(this); this.useRawEditor = this.useRawEditor.bind(this); } - useVisualEditor(){ + useVisualEditor() { this.props.switchVisualMode(true); } - useRawEditor(){ + useRawEditor() { this.props.switchVisualMode(false); } @@ -29,6 +29,7 @@ class MarkdownControl extends React.Component { onChange={onChange} onAddMedia={onAddMedia} getMedia={getMedia} + registeredComponents={editor.get('registeredComponents')} value={value} /> </div> diff --git a/src/components/Widgets/MarkdownControlElements/RawEditor/index.js b/src/components/Widgets/MarkdownControlElements/RawEditor/index.js index 2cabeaa0..175f2471 100644 --- a/src/components/Widgets/MarkdownControlElements/RawEditor/index.js +++ b/src/components/Widgets/MarkdownControlElements/RawEditor/index.js @@ -4,25 +4,6 @@ import Prism from 'prismjs'; import marks from './prismMarkdown'; import styles from './index.css'; -const MARKS = { - 'highlight-comment': { - opacity: '0.33' - }, - 'highlight-important': { - fontWeight: 'bold', - color: '#006', - }, - 'highlight-keyword': { - fontWeight: 'bold', - color: '#006', - }, - 'highlight-url': { - color: '#006', - }, - 'highlight-punctuation': { - color: '#006', - } -}; Prism.languages.markdown = Prism.languages.extend('markup', {}); Prism.languages.insertBefore('markdown', 'prolog', marks); @@ -31,6 +12,66 @@ Prism.languages.markdown['italic'].inside['url'] = Prism.util.clone(Prism.langua Prism.languages.markdown['bold'].inside['italic'] = Prism.util.clone(Prism.languages.markdown['italic']); Prism.languages.markdown['italic'].inside['bold'] = Prism.util.clone(Prism.languages.markdown['bold']); +function renderDecorations(text, block) { + let characters = text.characters.asMutable(); + const string = text.text; + const grammar = Prism.languages.markdown; + const tokens = Prism.tokenize(string, grammar); + let offset = 0; + + for (const token of tokens) { + if (typeof token == 'string') { + offset += token.length; + continue; + } + + const length = offset + token.matchedStr.length; + const name = token.alias || token.type; + const type = `highlight-${name}`; + + for (let i = offset; i < length; i++) { + let char = characters.get(i); + let { marks } = char; + marks = marks.add(Mark.create({ type })); + char = char.merge({ marks }); + characters = characters.set(i, char); + } + + offset = length; + } + + return characters.asImmutable(); +} + + +const SCHEMA = { + rules: [ + { + match: (object) => object.kind == 'block', + decorate: renderDecorations + } + ], + marks: { + 'highlight-comment': { + opacity: '0.33' + }, + 'highlight-important': { + fontWeight: 'bold', + color: '#006', + }, + 'highlight-keyword': { + fontWeight: 'bold', + color: '#006', + }, + 'highlight-url': { + color: '#006', + }, + 'highlight-punctuation': { + color: '#006', + } + } +}; + class RawEditor extends React.Component { constructor(props) { @@ -44,8 +85,6 @@ class RawEditor extends React.Component { this.handleChange = this.handleChange.bind(this); this.handleDocumentChange = this.handleDocumentChange.bind(this); - this.renderMark = this.renderMark.bind(this); - this.renderDecorations = this.renderDecorations.bind(this); } @@ -64,48 +103,12 @@ class RawEditor extends React.Component { this.props.onChange(content); } - renderMark(mark) { - return MARKS[mark.type] || {}; - } - - renderDecorations(text, block) { - let characters = text.characters.asMutable(); - const string = text.text; - const grammar = Prism.languages.markdown; - const tokens = Prism.tokenize(string, grammar); - let offset = 0; - - for (const token of tokens) { - if (typeof token == 'string') { - offset += token.length; - continue; - } - - const length = offset + token.matchedStr.length; - const name = token.alias || token.type; - const type = `highlight-${name}`; - - for (let i = offset; i < length; i++) { - let char = characters.get(i); - let { marks } = char; - marks = marks.add(Mark.create({ type })); - char = char.merge({ marks }); - characters = characters.set(i, char); - } - - offset = length; - } - - return characters.asImmutable(); - } - - render() { return ( <Editor placeholder={'Enter some rich text...'} state={this.state.state} - renderMark={this.renderMark} + schema={SCHEMA} onChange={this.handleChange} onDocumentChange={this.handleDocumentChange} renderDecorations={this.renderDecorations} diff --git a/src/components/Widgets/MarkdownControlElements/VisualEditor/index.js b/src/components/Widgets/MarkdownControlElements/VisualEditor/index.js index 33dea48d..86dcc739 100644 --- a/src/components/Widgets/MarkdownControlElements/VisualEditor/index.js +++ b/src/components/Widgets/MarkdownControlElements/VisualEditor/index.js @@ -5,7 +5,7 @@ import position from 'selection-position'; import MarkupIt, { SlateUtils } from 'markup-it'; import getSyntax from '../syntax'; import { emptyParagraphBlock } from '../constants'; -import { DEFAULT_NODE, NODES, MARKS } from './localRenderers'; +import { DEFAULT_NODE, SCHEMA } from './schema'; import StylesMenu from './StylesMenu'; import BlockTypesMenu from './BlockTypesMenu'; import styles from './index.css'; @@ -22,7 +22,7 @@ class VisualEditor extends React.Component { this.markdown = new MarkupIt(MarkdownSyntax); this.customImageNodeRenderer = this.customImageNodeRenderer.bind(this); - NODES['mediaproxy'] = this.customImageNodeRenderer; + SCHEMA.nodes['mediaproxy'] = this.customImageNodeRenderer; this.blockEdit = false; this.menuPositions = { @@ -63,8 +63,6 @@ class VisualEditor extends React.Component { this.calculateHoverMenuPosition = _.throttle(this.calculateHoverMenuPosition.bind(this), 30); this.calculateBlockMenuPosition = _.throttle(this.calculateBlockMenuPosition.bind(this), 100); this.renderBlockTypesMenu = this.renderBlockTypesMenu.bind(this); - this.renderNode = this.renderNode.bind(this); - this.renderMark = this.renderMark.bind(this); } getMedia(src) { @@ -290,16 +288,6 @@ class VisualEditor extends React.Component { } } - /** - * Return renderers for Slate - */ - renderNode(node) { - return NODES[node.type]; - } - renderMark(mark) { - return MARKS[mark.type]; - } - renderBlockTypesMenu() { const currentBlock = this.state.state.blocks.get(0); const isOpen = (this.props.value !== undefined && currentBlock.isEmpty && currentBlock.type !== 'horizontal-rule'); @@ -340,8 +328,7 @@ class VisualEditor extends React.Component { <Editor placeholder={'Enter some rich text...'} state={this.state.state} - renderNode={this.renderNode} - renderMark={this.renderMark} + schema={SCHEMA} onChange={this.handleChange} onKeyDown={this.handleKeyDown} onDocumentChange={this.handleDocumentChange} diff --git a/src/components/Widgets/MarkdownControlElements/VisualEditor/localRenderers.js b/src/components/Widgets/MarkdownControlElements/VisualEditor/localRenderers.js deleted file mode 100644 index 2dfac7d2..00000000 --- a/src/components/Widgets/MarkdownControlElements/VisualEditor/localRenderers.js +++ /dev/null @@ -1,60 +0,0 @@ -import React from 'react'; -import Block from './Block'; -import styles from './index.css'; - -/* eslint react/prop-types: 0, react/no-multi-comp: 0 */ - -// Define the default node type. -export const DEFAULT_NODE = 'paragraph'; - -// Local node renderers. -export const NODES = { - 'blockquote': (props) => <Block type='blockquote' {...props.attributes}>{props.children}</Block>, - 'unordered_list': props => <Block type='List'><ul {...props.attributes}>{props.children}</ul></Block>, - 'header_one': props => <Block type='Heading1' {...props.attributes}>{props.children}</Block>, - 'header_two': props => <Block type='Heading2' {...props.attributes}>{props.children}</Block>, - 'header_three': props => <Block type='Heading2' {...props.attributes}>{props.children}</Block>, - 'header_four': props => <Block type='Heading2' {...props.attributes}>{props.children}</Block>, - 'header_five': props => <Block type='Heading2' {...props.attributes}>{props.children}</Block>, - 'header_six': props => <Block type='Heading2' {...props.attributes}>{props.children}</Block>, - 'list_item': props => <li {...props.attributes}>{props.children}</li>, - 'paragraph': props => <Block type='Paragraph' {...props.attributes}>{props.children}</Block>, - 'hr': props => { - const { node, state } = props; - const isFocused = state.selection.hasEdgeIn(node); - const className = isFocused ? styles.active : null; - return ( - <hr className={className} {...props.attributes} /> - ); - }, - 'link': (props) => { - const { data } = props.node; - const href = data.get('href'); - return <a {...props.attributes} href={href}>{props.children}</a>; - }, - 'image': (props) => { - const { node, state } = props; - const isFocused = state.selection.hasEdgeIn(node); - const className = isFocused ? styles.active : null; - const src = node.data.get('src'); - return ( - <img {...props.attributes} src={src} className={className} /> - ); - } -}; - -// Local mark renderers. -export const MARKS = { - BOLD: { - fontWeight: 'bold' - }, - ITALIC: { - fontStyle: 'italic' - }, - CODE: { - fontFamily: 'monospace', - backgroundColor: '#eee', - padding: '3px', - borderRadius: '4px' - } -}; diff --git a/src/components/Widgets/MarkdownControlElements/VisualEditor/schema.js b/src/components/Widgets/MarkdownControlElements/VisualEditor/schema.js new file mode 100644 index 00000000..ea00ade2 --- /dev/null +++ b/src/components/Widgets/MarkdownControlElements/VisualEditor/schema.js @@ -0,0 +1,65 @@ +import React from 'react'; +import Block from './Block'; +import styles from './index.css'; + +/* eslint react/prop-types: 0, react/no-multi-comp: 0 */ + +// Define the default node type. +export const DEFAULT_NODE = 'paragraph'; + +/** + * Define a schema. + * + * @type {Object} + */ + +export const SCHEMA = { + nodes: { + 'blockquote': (props) => <Block type='blockquote' {...props.attributes}>{props.children}</Block>, + 'unordered_list': props => <Block type='List'><ul {...props.attributes}>{props.children}</ul></Block>, + 'header_one': props => <Block type='Heading1' {...props.attributes}>{props.children}</Block>, + 'header_two': props => <Block type='Heading2' {...props.attributes}>{props.children}</Block>, + 'header_three': props => <Block type='Heading2' {...props.attributes}>{props.children}</Block>, + 'header_four': props => <Block type='Heading2' {...props.attributes}>{props.children}</Block>, + 'header_five': props => <Block type='Heading2' {...props.attributes}>{props.children}</Block>, + 'header_six': props => <Block type='Heading2' {...props.attributes}>{props.children}</Block>, + 'list_item': props => <li {...props.attributes}>{props.children}</li>, + 'paragraph': props => <Block type='Paragraph' {...props.attributes}>{props.children}</Block>, + 'hr': props => { + const { node, state } = props; + const isFocused = state.selection.hasEdgeIn(node); + const className = isFocused ? styles.active : null; + return ( + <hr className={className} {...props.attributes} /> + ); + }, + 'link': (props) => { + const { data } = props.node; + const href = data.get('href'); + return <a {...props.attributes} href={href}>{props.children}</a>; + }, + 'image': (props) => { + const { node, state } = props; + const isFocused = state.selection.hasEdgeIn(node); + const className = isFocused ? styles.active : null; + const src = node.data.get('src'); + return ( + <img {...props.attributes} src={src} className={className} /> + ); + } + }, + marks: { + BOLD: { + fontWeight: 'bold' + }, + ITALIC: { + fontStyle: 'italic' + }, + CODE: { + fontFamily: 'monospace', + backgroundColor: '#eee', + padding: '3px', + borderRadius: '4px' + } + } +}