├── LICENSE
├── README.md
├── index.html
└── stdm-react.js
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Christopher Chedeau
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | markdown-react
2 | ==============
3 |
4 | React Render for Standard Markdown
5 |
6 | ```javascript
7 | /** @jsx React.DOM */
8 | var parser = new stmd.DocParser();
9 | var renderer = new stmdReact.ReactRenderer();
10 |
11 | React.renderComponent(
12 |
{renderer.render(parser.parse('Hello *world*'))}
,
13 | document.body
14 | );
15 | ```
16 |
17 |
18 | Demo: http://vjeux.github.io/markdown-react/
19 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
60 |
--------------------------------------------------------------------------------
/stdm-react.js:
--------------------------------------------------------------------------------
1 | // Basic usage:
2 | //
3 | // var stmd = require('stmd');
4 | // var parser = new stmd.DocParser();
5 | // var renderer = new stmdReact.ReactRenderer();
6 | // console.log(renderer.render(parser.parse('Hello *world*')));
7 |
8 | (function(exports) {
9 |
10 | // Helper function to produce content in a pair of HTML tags.
11 | var inTags = function(tag, attribs, contents, selfclosing) {
12 | var props = {};
13 | if (attribs) {
14 | var i = 0;
15 | var attrib;
16 | while ((attrib = attribs[i]) !== undefined) {
17 | props[attrib[0]] = attrib[1];
18 | i++;
19 | }
20 | }
21 |
22 | return React.DOM[tag](props, contents);
23 | };
24 |
25 | // Render an inline element as HTML.
26 | var renderInline = function(inline) {
27 | var attrs;
28 | switch (inline.t) {
29 | case 'Str':
30 | return this.escape(inline.c);
31 | case 'Softbreak':
32 | return this.softbreak;
33 | case 'Hardbreak':
34 | return [inTags('br',[],null,true), '\n'];
35 | case 'Emph':
36 | return inTags('em', [], this.renderInlines(inline.c));
37 | case 'Strong':
38 | return inTags('strong', [], this.renderInlines(inline.c));
39 | case 'Html':
40 | return inline.c;
41 | case 'Entity':
42 | return inline.c;
43 | case 'Link':
44 | attrs = [['href', this.escape(inline.destination, true)]];
45 | if (inline.title) {
46 | attrs.push(['title', this.escape(inline.title, true)]);
47 | }
48 | return inTags('a', attrs, this.renderInlines(inline.label));
49 | case 'Image':
50 | attrs = [['src', this.escape(inline.destination, true)],
51 | ['alt', this.escape(this.renderInlines(inline.label))]];
52 | if (inline.title) {
53 | attrs.push(['title', this.escape(inline.title, true)]);
54 | }
55 | return inTags('img', attrs, null, true);
56 | case 'Code':
57 | return inTags('code', [], this.escape(inline.c));
58 | default:
59 | console.log("Uknown inline type " + inline.t);
60 | return null;
61 | }
62 | };
63 |
64 | // Render a list of inlines.
65 | var renderInlines = function(inlines) {
66 | var result = [];
67 | for (var i=0; i < inlines.length; i++) {
68 | result.push(this.renderInline(inlines[i]));
69 | }
70 | return result;
71 | };
72 |
73 | // Render a single block element.
74 | var renderBlock = function(block, in_tight_list) {
75 | var tag;
76 | var attr;
77 | var info_words;
78 | switch (block.t) {
79 | case 'Document':
80 | var whole_doc = this.renderBlocks(block.children);
81 | return (whole_doc === '' ? null : [whole_doc, '\n']);
82 | case 'Paragraph':
83 | if (in_tight_list) {
84 | return this.renderInlines(block.inline_content);
85 | } else {
86 | return inTags('p', [], this.renderInlines(block.inline_content));;
87 | }
88 | break;
89 | case 'BlockQuote':
90 | var filling = this.renderBlocks(block.children);
91 | return inTags('blockquote', [], filling === '' ? this.innersep :
92 | [this.innersep, this.renderBlocks(block.children), this.innersep]);
93 | case 'ListItem':
94 | return inTags('li', [], this.renderBlocks(block.children, in_tight_list));//.trim());
95 | case 'List':
96 | tag = block.list_data.type == 'Bullet' ? 'ul' : 'ol';
97 | attr = (!block.list_data.start || block.list_data.start == 1) ?
98 | [] : [['start', block.list_data.start.toString()]];
99 | return inTags(tag, attr, [this.innersep,
100 | this.renderBlocks(block.children, block.tight),
101 | this.innersep]);
102 | case 'ATXHeader':
103 | case 'SetextHeader':
104 | tag = 'h' + block.level;
105 | return inTags(tag, [], this.renderInlines(block.inline_content));
106 | case 'IndentedCode':
107 | return inTags('pre', [],
108 | inTags('code', [], this.escape(block.string_content)));
109 | case 'FencedCode':
110 | info_words = block.info.split(/ +/);
111 | attr = info_words.length === 0 || info_words[0].length === 0 ?
112 | [] : [['class',this.escape(info_words[0],true)]];
113 | return inTags('pre', attr,
114 | inTags('code', [], this.escape(block.string_content)));
115 | case 'HtmlBlock':
116 | return block.string_content;
117 | case 'ReferenceDef':
118 | return null;
119 | case 'HorizontalRule':
120 | return inTags('hr',[],null,true);
121 | default:
122 | console.log("Uknown block type " + block.t);
123 | return null;
124 | }
125 | };
126 |
127 | // Render a list of block elements, separated by this.blocksep.
128 | var renderBlocks = function(blocks, in_tight_list) {
129 | var result = [];
130 | for (var i=0; i < blocks.length; i++) {
131 | if (blocks[i].t !== 'ReferenceDef') {
132 | result.push(this.renderBlock(blocks[i], in_tight_list));
133 | if (i !== blocks.length - 1) {
134 | result.push(this.blocksep);
135 | }
136 | }
137 | }
138 | return result;
139 | };
140 |
141 | // The ReactRenderer object.
142 | function ReactRenderer(){
143 | return {
144 | // default options:
145 | blocksep: '\n', // space between blocks
146 | innersep: '\n', // space between block container tag and contents
147 | softbreak: '\n', // by default, soft breaks are rendered as newlines in HTML
148 | // set to "
" to make them hard breaks
149 | // set to " " if you want to ignore line wrapping in source
150 | escape: function(s, preserve_entities) {
151 | return s;
152 | },
153 | renderInline: renderInline,
154 | renderInlines: renderInlines,
155 | renderBlock: renderBlock,
156 | renderBlocks: renderBlocks,
157 | render: renderBlock
158 | };
159 | }
160 |
161 | exports.ReactRenderer = ReactRenderer;
162 |
163 | })(typeof exports === 'undefined' ? this.stmdReact = {} : exports);
164 |
--------------------------------------------------------------------------------