Make editor plugins work in preview

This commit is contained in:
Mathias Biilmann Christensen 2016-10-30 23:38:12 -07:00
parent 378be79a76
commit aca88ef441
3 changed files with 61 additions and 45 deletions

View File

@ -1,6 +1,7 @@
import React, { PropTypes } from 'react';
import MarkupIt, { Syntax, BLOCKS, STYLES, ENTITIES } from 'markup-it';
import { omit } from 'lodash';
import registry from '../../lib/registry';
const defaultSchema = {
[BLOCKS.DOCUMENT]: 'article',
@ -44,43 +45,16 @@ function sanitizeProps(props) {
return omit(props, notAllowedAttributes);
}
function renderToken(schema, token, index = 0, key = '0') {
const type = token.get('type');
const data = token.get('data');
const text = token.get('text');
const tokens = token.get('tokens');
const nodeType = schema[type];
key = `${ key }.${ index }`;
// Only render if type is registered as renderer
if (typeof nodeType !== 'undefined') {
let children = null;
if (tokens.size) {
children = tokens.map((token, idx) => renderToken(schema, token, idx, key));
} else if (type === 'text') {
children = text;
}
if (nodeType !== null) {
let props = { key, token };
if (typeof nodeType !== 'function') {
props = { key, ...sanitizeProps(data.toJS()) };
}
// If this is a react element
return React.createElement(nodeType, props, children);
} else {
// If this is a text node
return children;
}
}
return null;
}
export default class MarkupItReactRenderer extends React.Component {
constructor(props) {
super(props);
const { syntax } = props;
this.parser = new MarkupIt(syntax);
this.plugins = {};
registry.getEditorComponents().forEach((component) => {
this.plugins[component.get('id')] = component;
});
}
componentWillReceiveProps(nextProps) {
@ -89,10 +63,51 @@ export default class MarkupItReactRenderer extends React.Component {
}
}
renderToken(schema, token, index = 0, key = '0') {
const type = token.get('type');
const data = token.get('data');
const text = token.get('text');
const tokens = token.get('tokens');
const nodeType = schema[type];
key = `${ key }.${ index }`;
// Only render if type is registered as renderer
if (typeof nodeType !== 'undefined') {
let children = null;
if (tokens.size) {
children = tokens.map((token, idx) => this.renderToken(schema, token, idx, key));
} else if (type === 'text') {
children = text;
}
if (nodeType !== null) {
let props = { key, token };
if (typeof nodeType !== 'function') {
props = { key, ...sanitizeProps(data.toJS()) };
}
// If this is a react element
return React.createElement(nodeType, props, children);
} else {
// If this is a text node
return children;
}
}
const plugin = this.plugins[token.get('type')];
if (plugin) {
const output = plugin.toPreview(token.get('data').toJS());
return output instanceof React.Component ?
output :
<span dangerouslySetInnerHTML={{ __html: output}} />;
}
return null;
}
render() {
const { value, schema } = this.props;
const content = this.parser.toContent(value);
return renderToken({ ...defaultSchema, ...schema }, content.get('token'));
return this.renderToken({ ...defaultSchema, ...schema }, content.get('token'));
}
}

View File

@ -3,6 +3,7 @@
left: -18px;
display: none;
width: 100%;
z-index: 1000;
}
.visible {

View File

@ -65,18 +65,17 @@ function getCleanPaste(e) {
});
}
const buildtInPlugins = fromJS([{
const buildtInPlugins = [{
label: 'Image',
id: 'image',
fromBlock: (data) => {
const m = data.match(/^!\[([^\]]+)\]\(([^\)]+)\)$/);
return m && {
image: m[2],
alt: m[1],
};
fromBlock: match => match && {
image: match[2],
alt: match[1],
},
toBlock: data => `![${ data.alt }](${ data.image })`,
toPreview: data => `<img src="${ data.image }" alt="${ data.alt }" />`,
toPreview: (data) => {
return <img src={data.image} alt={data.alt} />;
},
pattern: /^!\[([^\]]+)\]\(([^\)]+)\)$/,
fields: [{
label: 'Image',
@ -86,14 +85,15 @@ const buildtInPlugins = fromJS([{
label: 'Alt Text',
name: 'alt',
}],
}]);
}];
buildtInPlugins.forEach(plugin => registry.registerEditorComponent(plugin));
export default class RawEditor extends React.Component {
constructor(props) {
super(props);
const plugins = registry.getEditorComponents();
this.state = {
plugins: buildtInPlugins.concat(plugins),
plugins: plugins,
};
this.shortcuts = {
meta: {
@ -161,7 +161,7 @@ export default class RawEditor extends React.Component {
}
replaceSelection(chars) {
const { value } = this.props;
const value = this.props.value || '';
const selection = this.getSelection();
const newSelection = Object.assign({}, selection);
const beforeSelection = value.substr(0, selection.start);
@ -172,7 +172,7 @@ export default class RawEditor extends React.Component {
}
toggleHeader(header) {
const { value } = this.props;
const value = this.props.value || '';
const selection = this.getSelection();
const newSelection = Object.assign({}, selection);
const lastNewline = value.lastIndexOf('\n', selection.start);
@ -234,7 +234,7 @@ export default class RawEditor extends React.Component {
};
handleSelection = () => {
const { value } = this.props;
const value = this.props.value || '';
const selection = this.getSelection();
if (selection.start !== selection.end && !HAS_LINE_BREAK.test(selection.selected)) {
try {