diff --git a/package.json b/package.json
index 29506cf1..0cd64b56 100644
--- a/package.json
+++ b/package.json
@@ -101,6 +101,7 @@
"dateformat": "^1.0.12",
"deep-equal": "^1.0.1",
"fuzzy": "^0.1.1",
+ "hast-util-to-html": "^3.0.0",
"history": "^2.1.2",
"immutability-helper": "^2.0.0",
"immutable": "^3.7.6",
@@ -112,6 +113,7 @@
"lodash": "^4.13.1",
"markup-it": "^2.0.0",
"material-design-icons": "^3.0.1",
+ "mdast-util-to-hast": "^2.4.0",
"moment": "^2.11.2",
"netlify-auth-js": "^0.5.5",
"normalize.css": "^4.2.0",
@@ -157,6 +159,8 @@
"redux-notifications": "^2.1.1",
"redux-optimist": "^0.0.2",
"redux-thunk": "^1.0.3",
+ "remark": "6",
+ "remark-html": "^6.0.0",
"selection-position": "^1.0.0",
"semaphore": "^1.0.5",
"slate": "^0.14.14",
diff --git a/src/components/MarkupItReactRenderer/__tests__/MarkupItReactRenderer.spec.js b/src/components/MarkupItReactRenderer/__tests__/MarkupItReactRenderer.spec.js
index f9f2c158..a86d4f76 100644
--- a/src/components/MarkupItReactRenderer/__tests__/MarkupItReactRenderer.spec.js
+++ b/src/components/MarkupItReactRenderer/__tests__/MarkupItReactRenderer.spec.js
@@ -1,58 +1,14 @@
/* eslint max-len:0 */
-import React from 'react';
-import { shallow } from 'enzyme';
-import { padStart } from 'lodash';
-import { Map } from 'immutable';
-import MarkupIt from 'markup-it';
-import markdownSyntax from 'markup-it/syntaxes/markdown';
-import htmlSyntax from 'markup-it/syntaxes/html';
-import reInline from 'markup-it/syntaxes/markdown/re/inline';
-import MarkupItReactRenderer from '../';
+import React from "react";
+import { shallow } from "enzyme";
+import { padStart } from "lodash";
+import MarkupItReactRenderer from "../";
-function getAsset(path) {
- return path;
-}
-
-describe('MarkitupReactRenderer', () => {
- describe('basics', () => {
- it('should re-render properly after a value and syntax update', () => {
- const component = shallow(
-
- );
- const tree1 = component.html();
- component.setProps({
- value: '
Title
',
- syntax: htmlSyntax,
- });
- const tree2 = component.html();
- expect(tree1).toEqual(tree2);
- });
-
- it('should not update the parser if syntax didn\'t change', () => {
- const component = shallow(
-
- );
- const syntax1 = component.instance().props.syntax;
- component.setProps({
- value: '## Title',
- });
- const syntax2 = component.instance().props.syntax;
- expect(syntax1).toEqual(syntax2);
- });
- });
-
- describe('Markdown rendering', () => {
- describe('General', () => {
- it('should render markdown', () => {
+describe("MarkitupReactRenderer", () => {
+ describe("Markdown rendering", () => {
+ describe("General", () => {
+ it("should render markdown", () => {
const value = `
# H1
@@ -79,35 +35,23 @@ Text with **bold** & _em_ elements
###### H6
`;
- const component = shallow(
-
- );
+ const component = shallow();
expect(component.html()).toMatchSnapshot();
});
});
- describe('Headings', () => {
+ describe("Headings", () => {
for (const heading of [...Array(6).keys()]) {
it(`should render Heading ${ heading + 1 }`, () => {
- const value = padStart(' Title', heading + 7, '#');
- const component = shallow(
-
- );
+ const value = padStart(" Title", heading + 7, "#");
+ const component = shallow();
expect(component.html()).toMatchSnapshot();
});
}
});
- describe('Lists', () => {
- it('should render lists', () => {
+ describe("Lists", () => {
+ it("should render lists", () => {
const value = `
1. ol item 1
1. ol item 2
@@ -119,19 +63,13 @@ Text with **bold** & _em_ elements
1. Sub-Sublist 3
1. ol item 3
`;
- const component = shallow(
-
- );
+ const component = shallow();
expect(component.html()).toMatchSnapshot();
});
});
- describe('Links', () => {
- it('should render links', () => {
+ describe("Links", () => {
+ it("should render links", () => {
const value = `
I get 10 times more traffic from [Google] [1] than from [Yahoo] [2] or [MSN] [3].
@@ -139,45 +77,27 @@ I get 10 times more traffic from [Google] [1] than from [Yahoo] [2] or [MSN] [3]
[2]: http://search.yahoo.com/ "Yahoo Search"
[3]: http://search.msn.com/ "MSN Search"
`;
- const component = shallow(
-
- );
+ const component = shallow();
expect(component.html()).toMatchSnapshot();
});
});
- describe('Code', () => {
- it('should render code', () => {
- const value = 'Use the `printf()` function.';
- const component = shallow(
-
- );
+ describe("Code", () => {
+ it("should render code", () => {
+ const value = "Use the `printf()` function.";
+ const component = shallow();
expect(component.html()).toMatchSnapshot();
});
- it('should render code 2', () => {
- const value = '``There is a literal backtick (`) here.``';
- const component = shallow(
-
- );
+ it("should render code 2", () => {
+ const value = "``There is a literal backtick (`) here.``";
+ const component = shallow();
expect(component.html()).toMatchSnapshot();
});
});
- describe('HTML', () => {
- it('should render HTML as is when using Markdown', () => {
+ describe("HTML", () => {
+ it("should render HTML as is when using Markdown", () => {
const value = `
# Title
@@ -193,71 +113,16 @@ I get 10 times more traffic from [Google] [1] than from [Yahoo] [2] or [MSN] [3]
Test
`;
- const component = shallow(
-
- );
+ const component = shallow();
expect(component.html()).toMatchSnapshot();
});
});
});
- describe('custom elements', () => {
- it('should extend default renderers with custom ones', () => {
- const myRule = MarkupIt.Rule('mediaproxy') // eslint-disable-line
- .regExp(reInline.link, (state, match) => {
- if (match[0].charAt(0) !== '!') {
- return null;
- }
-
- return {
- data: Map({
- alt: match[1],
- src: match[2],
- title: match[3],
- }).filter(Boolean),
- };
- });
-
- const myCustomSchema = {
- mediaproxy: ({ token }) => { //eslint-disable-line
- const src = token.getIn(['data', 'src']);
- const alt = token.getIn(['data', 'alt']);
- return
;
- },
- };
-
- const myMarkdownSyntax = markdownSyntax.addInlineRules(myRule);
- const value = `
-## Title
-
-
-`;
- const component = shallow(
-
- );
- expect(component.html()).toMatchSnapshot();
- });
- });
-
- describe('HTML rendering', () => {
- it('should render HTML', () => {
- const value = 'Paragraph with inline element
';
- const component = shallow(
-
- );
+ describe("HTML rendering", () => {
+ it("should render HTML", () => {
+ const value = "Paragraph with inline element
";
+ const component = shallow();
expect(component.html()).toMatchSnapshot();
});
});
diff --git a/src/components/MarkupItReactRenderer/__tests__/__snapshots__/MarkupItReactRenderer.spec.js.snap b/src/components/MarkupItReactRenderer/__tests__/__snapshots__/MarkupItReactRenderer.spec.js.snap
index 1495c18c..b51ff97e 100644
--- a/src/components/MarkupItReactRenderer/__tests__/__snapshots__/MarkupItReactRenderer.spec.js.snap
+++ b/src/components/MarkupItReactRenderer/__tests__/__snapshots__/MarkupItReactRenderer.spec.js.snap
@@ -1,15 +1,35 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`MarkitupReactRenderer HTML rendering should render HTML 1`] = `"Paragraph with inline element
"`;
+exports[`MarkitupReactRenderer HTML rendering should render HTML 1`] = `"Paragraph with inline element
"`;
-exports[`MarkitupReactRenderer Markdown rendering Code should render code 1`] = `"Use the printf()
function.
"`;
+exports[`MarkitupReactRenderer Markdown rendering Code should render code 1`] = `"Use the printf()
function.
"`;
-exports[`MarkitupReactRenderer Markdown rendering Code should render code 2 1`] = `"There is a literal backtick (\`) here.
"`;
+exports[`MarkitupReactRenderer Markdown rendering Code should render code 2 1`] = `"There is a literal backtick (\`) here.
"`;
-exports[`MarkitupReactRenderer Markdown rendering General should render markdown 1`] = `"H1
Text with bold & em elements
H2
H3
- ol item 1
- ol item 2
- ol item 3
H4
link title
H5

H6
"`;
+exports[`MarkitupReactRenderer Markdown rendering General should render markdown 1`] = `
+"H1
+
Text with bold & em elements
+
H2
+
+
H3
+
+- ol item 1
+- ol item 2
+- ol item 3
+
+
H4
+
link title
+
H5
+

+
H6
"
+`;
exports[`MarkitupReactRenderer Markdown rendering HTML should render HTML as is when using Markdown 1`] = `
-"Title
"
`;
-exports[`MarkitupReactRenderer Markdown rendering Headings should render Heading 1 1`] = `"Title
"`;
+exports[`MarkitupReactRenderer Markdown rendering Headings should render Heading 1 1`] = `"Title
"`;
-exports[`MarkitupReactRenderer Markdown rendering Headings should render Heading 2 1`] = `"Title
"`;
+exports[`MarkitupReactRenderer Markdown rendering Headings should render Heading 2 1`] = `"Title
"`;
-exports[`MarkitupReactRenderer Markdown rendering Headings should render Heading 3 1`] = `"Title
"`;
+exports[`MarkitupReactRenderer Markdown rendering Headings should render Heading 3 1`] = `"Title
"`;
-exports[`MarkitupReactRenderer Markdown rendering Headings should render Heading 4 1`] = `"Title
"`;
+exports[`MarkitupReactRenderer Markdown rendering Headings should render Heading 4 1`] = `"Title
"`;
-exports[`MarkitupReactRenderer Markdown rendering Headings should render Heading 5 1`] = `"Title
"`;
+exports[`MarkitupReactRenderer Markdown rendering Headings should render Heading 5 1`] = `"Title
"`;
-exports[`MarkitupReactRenderer Markdown rendering Headings should render Heading 6 1`] = `"Title
"`;
+exports[`MarkitupReactRenderer Markdown rendering Headings should render Heading 6 1`] = `"Title
"`;
-exports[`MarkitupReactRenderer Markdown rendering Links should render links 1`] = `"I get 10 times more traffic from Google than from Yahoo or MSN.
"`;
+exports[`MarkitupReactRenderer Markdown rendering Links should render links 1`] = `""`;
-exports[`MarkitupReactRenderer Markdown rendering Lists should render lists 1`] = `"- ol item 1
- ol item 2
- Sublist 1
- Sublist 2
- Sublist 3
- Sub-Sublist 1
- Sub-Sublist 2
- Sub-Sublist 3
- ol item 3
"`;
-
-exports[`MarkitupReactRenderer custom elements should extend default renderers with custom ones 1`] = `"Title

"`;
+exports[`MarkitupReactRenderer Markdown rendering Lists should render lists 1`] = `
+"
+- ol item 1
+- ol item 2
+
+
+- Sublist 1
+- Sublist 2
+-
+
Sublist 3
+
+- Sub-Sublist 1
+- Sub-Sublist 2
+- Sub-Sublist 3
+
+
+
+
+- ol item 3
+
"
+`;
diff --git a/src/components/MarkupItReactRenderer/index.js b/src/components/MarkupItReactRenderer/index.js
index 79a2bc98..03d46637 100644
--- a/src/components/MarkupItReactRenderer/index.js
+++ b/src/components/MarkupItReactRenderer/index.js
@@ -1,130 +1,35 @@
-import React, { PropTypes } from 'react';
-import MarkupIt, { Syntax, BLOCKS, STYLES, ENTITIES } from 'markup-it';
-import { omit } from 'lodash';
-import registry from '../../lib/registry';
+import React, { PropTypes } from "react";
+import Remark from "remark";
+import toHAST from "mdast-util-to-hast";
+import hastToHTML from "hast-util-to-html";
+import registry from "../../lib/registry";
-const defaultSchema = {
- [BLOCKS.DOCUMENT]: 'article',
- [BLOCKS.TEXT]: null,
- [BLOCKS.CODE]: ({ token }) => {
- const className = token.getIn(['data', 'syntax']) && `language-${ token.getIn(['data', 'syntax']) }`;
- return token.text).join('') }} />
;
- },
- [BLOCKS.BLOCKQUOTE]: 'blockquote',
- [BLOCKS.PARAGRAPH]: 'p',
- [BLOCKS.FOOTNOTE]: 'footnote',
- [BLOCKS.HTML]: ({ token }) => ,
- [BLOCKS.HR]: 'hr',
- [BLOCKS.HEADING_1]: 'h1',
- [BLOCKS.HEADING_2]: 'h2',
- [BLOCKS.HEADING_3]: 'h3',
- [BLOCKS.HEADING_4]: 'h4',
- [BLOCKS.HEADING_5]: 'h5',
- [BLOCKS.HEADING_6]: 'h6',
- [BLOCKS.TABLE]: 'table',
- [BLOCKS.TABLE_ROW]: 'tr',
- [BLOCKS.TABLE_CELL]: 'td',
- [BLOCKS.OL_LIST]: 'ol',
- [BLOCKS.UL_LIST]: 'ul',
- [BLOCKS.LIST_ITEM]: 'li',
-
- [STYLES.TEXT]: null,
- [STYLES.BOLD]: 'strong',
- [STYLES.ITALIC]: 'em',
- [STYLES.CODE]: 'code',
- [STYLES.STRIKETHROUGH]: 'del',
-
- [ENTITIES.LINK]: 'a',
- [ENTITIES.IMAGE]: 'img',
- [ENTITIES.FOOTNOTE_REF]: 'sup',
- [ENTITIES.HARD_BREAK]: 'br',
-};
-
-const notAllowedAttributes = ['loose', 'image'];
+// Setup Remark.
+const remark = new Remark({
+ commonmark: true,
+ footnotes: true,
+ pedantic: true,
+});
export default class MarkupItReactRenderer extends React.Component {
-
constructor(props) {
super(props);
- const { syntax } = props;
- this.parser = new MarkupIt(syntax);
this.plugins = {};
+ // TODO add back support for this.
registry.getEditorComponents().forEach((component) => {
- this.plugins[component.get('id')] = component;
+ this.plugins[component.get("id")] = component;
});
}
- componentWillReceiveProps(nextProps) {
- if (nextProps.syntax != this.props.syntax) {
- this.parser = new MarkupIt(nextProps.syntax);
- }
- }
-
- sanitizeProps(props) {
- const { getAsset } = this.props;
-
- if (props.image) {
- props = Object.assign({}, props, { src: getAsset(props.image).toString() });
- }
-
- return omit(props, notAllowedAttributes);
- }
-
-
- 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, ...this.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 typeof output === 'string' ?
- :
- output;
- }
-
- return null;
- }
-
-
render() {
- const { value, schema, getAsset } = this.props;
- const content = this.parser.toContent(value);
- return this.renderToken({ ...defaultSchema, ...schema }, content.get('token'));
+ const { value } = this.props;
+ const mast = remark.parse(value);
+ const hast = toHAST(mast, { allowDangerousHTML: true });
+ const html = hastToHTML(hast, { allowDangerousHTML: true });
+ return ; // eslint-disable-line react/no-danger
}
}
MarkupItReactRenderer.propTypes = {
value: PropTypes.string,
- syntax: PropTypes.instanceOf(Syntax).isRequired,
- schema: PropTypes.objectOf(PropTypes.oneOfType([
- PropTypes.string,
- PropTypes.func,
- ])),
- getAsset: PropTypes.func.isRequired,
};