From aca88ef441a57a429aa03182bb976486e883b0ee Mon Sep 17 00:00:00 2001 From: Mathias Biilmann Christensen Date: Sun, 30 Oct 2016 23:38:12 -0700 Subject: [PATCH] Make editor plugins work in preview --- src/components/MarkupItReactRenderer/index.js | 79 +++++++++++-------- .../RawEditor/BlockMenu.css | 1 + .../RawEditor/index.js | 26 +++--- 3 files changed, 61 insertions(+), 45 deletions(-) diff --git a/src/components/MarkupItReactRenderer/index.js b/src/components/MarkupItReactRenderer/index.js index f5ede88b..06ca60ee 100644 --- a/src/components/MarkupItReactRenderer/index.js +++ b/src/components/MarkupItReactRenderer/index.js @@ -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 : + ; + } + + 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')); } } diff --git a/src/components/Widgets/MarkdownControlElements/RawEditor/BlockMenu.css b/src/components/Widgets/MarkdownControlElements/RawEditor/BlockMenu.css index 5183a9e7..6f602ca7 100644 --- a/src/components/Widgets/MarkdownControlElements/RawEditor/BlockMenu.css +++ b/src/components/Widgets/MarkdownControlElements/RawEditor/BlockMenu.css @@ -3,6 +3,7 @@ left: -18px; display: none; width: 100%; + z-index: 1000; } .visible { diff --git a/src/components/Widgets/MarkdownControlElements/RawEditor/index.js b/src/components/Widgets/MarkdownControlElements/RawEditor/index.js index 5f68e04a..d8ad8eb3 100644 --- a/src/components/Widgets/MarkdownControlElements/RawEditor/index.js +++ b/src/components/Widgets/MarkdownControlElements/RawEditor/index.js @@ -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 => `${ data.alt }`, + toPreview: (data) => { + return {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 {