mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
1 parent
d8117d0df6
commit
36aefcb8cc
6 files changed
+22
-1322
No files matched your search
@@ -1,6 +1,4 @@
|
||||
var MARKDOWN_COMPONENT = `
|
||||
var converter = new Showdown.converter();
|
||||
|
||||
var MarkdownEditor = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {value: 'Type some *markdown* here!'};
|
||||
@@ -20,7 +18,7 @@ var MarkdownEditor = React.createClass({
|
||||
<div
|
||||
className="content"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: converter.makeHtml(this.state.value)
|
||||
__html: marked(this.state.value, {sanitize: true})
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
<script type="text/javascript" src="/react/js/react.js"></script>
|
||||
<script type="text/javascript" src="/react/js/JSXTransformer.js"></script>
|
||||
<script type="text/javascript" src="/react/js/live_editor.js"></script>
|
||||
<script type="text/javascript" src="/react/js/showdown.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
+9
-11
@@ -212,7 +212,7 @@ Note that we have passed some data from the parent `CommentList` component to th
|
||||
|
||||
Markdown is a simple way to format your text inline. For example, surrounding text with asterisks will make it emphasized.
|
||||
|
||||
First, add the third-party **Showdown** library to your application. This is a JavaScript library which takes Markdown text and converts it to raw HTML. This requires a script tag in your head (which we have already included in the React playground):
|
||||
First, add the third-party library **marked** to your application. This is a JavaScript library which takes Markdown text and converts it to raw HTML. This requires a script tag in your head (which we have already included in the React playground):
|
||||
|
||||
```html{7}
|
||||
<!-- index.html -->
|
||||
@@ -221,15 +221,14 @@ First, add the third-party **Showdown** library to your application. This is a J
|
||||
<script src="https://fb.me/react-{{site.react_version}}.js"></script>
|
||||
<script src="https://fb.me/JSXTransformer-{{site.react_version}}.js"></script>
|
||||
<script src="https://code.jquery.com/jquery-1.10.0.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js"></script>
|
||||
</head>
|
||||
```
|
||||
|
||||
Next, let's convert the comment text to Markdown and output it:
|
||||
|
||||
```javascript{2,10}
|
||||
```javascript{9}
|
||||
// tutorial6.js
|
||||
var converter = new Showdown.converter();
|
||||
var Comment = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
@@ -237,25 +236,24 @@ var Comment = React.createClass({
|
||||
<h2 className="commentAuthor">
|
||||
{this.props.author}
|
||||
</h2>
|
||||
{converter.makeHtml(this.props.children.toString())}
|
||||
{marked(this.props.children.toString())}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
All we're doing here is calling the Showdown library. We need to convert `this.props.children` from React's wrapped text to a raw string that Showdown will understand so we explicitly call `toString()`.
|
||||
All we're doing here is calling the marked library. We need to convert `this.props.children` from React's wrapped text to a raw string that marked will understand so we explicitly call `toString()`.
|
||||
|
||||
But there's a problem! Our rendered comments look like this in the browser: "`<p>`This is `<em>`another`</em>` comment`</p>`". We want those tags to actually render as HTML.
|
||||
|
||||
That's React protecting you from an XSS attack. There's a way to get around it but the framework warns you not to use it:
|
||||
|
||||
```javascript{5,11}
|
||||
```javascript{4,10}
|
||||
// tutorial7.js
|
||||
var converter = new Showdown.converter();
|
||||
var Comment = React.createClass({
|
||||
render: function() {
|
||||
var rawMarkup = converter.makeHtml(this.props.children.toString());
|
||||
var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
|
||||
return (
|
||||
<div className="comment">
|
||||
<h2 className="commentAuthor">
|
||||
@@ -268,9 +266,9 @@ var Comment = React.createClass({
|
||||
});
|
||||
```
|
||||
|
||||
This is a special API that intentionally makes it difficult to insert raw HTML, but for Showdown we'll take advantage of this backdoor.
|
||||
This is a special API that intentionally makes it difficult to insert raw HTML, but for marked we'll take advantage of this backdoor.
|
||||
|
||||
**Remember:** by using this feature you're relying on Showdown to be secure.
|
||||
**Remember:** by using this feature you're relying on marked to be secure. In this case, we pass `sanitize: true` which tells marked to escape any HTML markup in the source instead of passing it through unchanged.
|
||||
|
||||
### Hook up the data model
|
||||
|
||||
|
||||
+6
-5
@@ -72,16 +72,17 @@ id: home
|
||||
<h3>A Component Using External Plugins</h3>
|
||||
<p>
|
||||
React is flexible and provides hooks that allow you to interface with
|
||||
other libraries and frameworks. This example uses Showdown, an external
|
||||
other libraries and frameworks. This example uses **marked**, an external
|
||||
Markdown library, to convert the textarea's value in real-time.
|
||||
</p>
|
||||
<div id="markdownExample"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript" src="js/examples/hello.js"></script>
|
||||
<script type="text/javascript" src="js/examples/timer.js"></script>
|
||||
<script type="text/javascript" src="js/examples/todo.js"></script>
|
||||
<script type="text/javascript" src="js/examples/markdown.js"></script>
|
||||
<script type="text/javascript" src="/react/js/marked.min.js"></script>
|
||||
<script type="text/javascript" src="/react/js/examples/hello.js"></script>
|
||||
<script type="text/javascript" src="/react/js/examples/timer.js"></script>
|
||||
<script type="text/javascript" src="/react/js/examples/todo.js"></script>
|
||||
<script type="text/javascript" src="/react/js/examples/markdown.js"></script>
|
||||
</section>
|
||||
<hr class="home-divider" />
|
||||
<section class="home-bottom-section">
|
||||
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* marked - a markdown parser
|
||||
* Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
|
||||
* https://github.com/chjj/marked
|
||||
*/
|
||||
(function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",/<!--[\s\S]*?-->/)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,paragraph:/^/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].split(/ *\| */)}this.tokens.push(item);continue}if(cap=this.rules.lheading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[2]==="="?1:2,text:cap[1]});continue}if(cap=this.rules.hr.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"hr"});continue}if(cap=this.rules.blockquote.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"blockquote_start"});cap=cap[0].replace(/^ *> ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i<l;i++){item=cap[i];space=item.length;item=item.replace(/^ *([*+-]|\d+\.) +/,"");if(~item.indexOf("\n ")){space-=item.length;item=!this.options.pedantic?item.replace(new RegExp("^ {1,"+space+"}","gm"),""):item.replace(/^ {1,4}/gm,"")}if(this.options.smartLists&&i!==l-1){b=block.bullet.exec(cap[i+1])[0];if(bull!==b&&!(bull.length>1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq);this.tokLine truncated
|
||||
-1302
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user