forked from newthuhole/hole_thu_frontend
fixed markdown, tested
This commit is contained in:
@@ -5,11 +5,9 @@ import {THUHOLE_API_ROOT} from './flows_api';
|
|||||||
import HtmlToReact from 'html-to-react'
|
import HtmlToReact from 'html-to-react'
|
||||||
|
|
||||||
import './Common.css';
|
import './Common.css';
|
||||||
import { URL_PID_RE, URL_RE, split_text } from './text_splitter';
|
import { URL_PID_RE, URL_RE, PID_RE, NICKNAME_RE, split_text } from './text_splitter';
|
||||||
import ProcessNodeDefinitions from 'html-to-react/lib/process-node-definitions';
|
|
||||||
|
|
||||||
import ReactMarkdown from 'react-markdown'
|
import renderMd from './Markdown'
|
||||||
import htmlParser from 'react-markdown/plugins/html-parser'
|
|
||||||
|
|
||||||
export {format_time,Time,TitleLine};
|
export {format_time,Time,TitleLine};
|
||||||
|
|
||||||
@@ -61,38 +59,20 @@ export class HighlightedText extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// props: text, show_pid, color_picker
|
// props: text, show_pid, color_picker
|
||||||
export class HighlightedMarkdown extends PureComponent {
|
export class HighlightedMarkdown extends Component {
|
||||||
render() {
|
render() {
|
||||||
|
const props = this.props
|
||||||
const processDefs = new HtmlToReact.ProcessNodeDefinitions(React)
|
const processDefs = new HtmlToReact.ProcessNodeDefinitions(React)
|
||||||
const astInst = [
|
const processInstructions = [
|
||||||
{
|
{
|
||||||
shouldProcessNode (node) {
|
shouldProcessNode (node) {
|
||||||
return node.name === 'link' // urls
|
return node.type === 'text' // pid, nickname, search
|
||||||
},
|
|
||||||
processNode (node) {
|
|
||||||
const originalHref = node.attribs.href
|
|
||||||
if (URL_PID_RE.test(originalHref)) { // url_pid
|
|
||||||
return (
|
|
||||||
<span className="url-pid-link" title={originalHref}>/##</span>
|
|
||||||
)
|
|
||||||
} else if (URL_RE.test(originalHref)) { // url
|
|
||||||
return (
|
|
||||||
<a href={normalize_url(originalHref)} target="_blank" rel="noopener">
|
|
||||||
{originalHref}
|
|
||||||
</a>
|
|
||||||
)
|
|
||||||
} else {// other cases are invalid, e.g. javascript:alert, etc
|
|
||||||
return (<a></a>)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
shouldProcessNode (node) {
|
|
||||||
return node.name === 'text' // pid, nickname, search
|
|
||||||
},
|
},
|
||||||
processNode (node) {
|
processNode (node) {
|
||||||
const originalText = node.data
|
const originalText = node.data
|
||||||
const splitted = split_text(originalText, [
|
const splitted = split_text(originalText, [
|
||||||
|
['url_pid', URL_PID_RE],
|
||||||
|
['url',URL_RE],
|
||||||
['pid',PID_RE],
|
['pid',PID_RE],
|
||||||
['nickname',NICKNAME_RE],
|
['nickname',NICKNAME_RE],
|
||||||
])
|
])
|
||||||
@@ -100,12 +80,15 @@ export class HighlightedMarkdown extends PureComponent {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{splitted.map(([rule, p], idx) => {
|
{splitted.map(([rule, p], idx) => {
|
||||||
<span key={p}>
|
return (<span key={idx}>
|
||||||
{rule==='pid' ? <a href={'#'+p} onClick={(e)=>{e.preventDefault(); this.props.show_pid(p.substring(1));}}>{p}</a> :
|
{
|
||||||
rule==='nickname' ? <ColoredSpan colors={this.props.color_picker.get(p)}>{p}</ColoredSpan> :
|
rule==='url_pid' ? <span className="url-pid-link" title={p}>/##</span> :
|
||||||
|
rule==='url' ? <a href={normalize_url(p)} target="_blank" rel="noopener">{p}</a> :
|
||||||
|
rule==='pid' ? <a href={'#'+p} onClick={(e)=>{e.preventDefault(); props.show_pid(p.substring(1));}}>{p}</a> :
|
||||||
|
rule==='nickname' ? <ColoredSpan colors={props.color_picker.get(p)}>{p}</ColoredSpan> :
|
||||||
rule==='search' ? <span className="search-query-highlight">{p}</span> :
|
rule==='search' ? <span className="search-query-highlight">{p}</span> :
|
||||||
p}
|
p}
|
||||||
</span>
|
</span>)
|
||||||
})}
|
})}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
@@ -116,16 +99,11 @@ export class HighlightedMarkdown extends PureComponent {
|
|||||||
processNode: processDefs.processDefaultNode
|
processNode: processDefs.processDefaultNode
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
return (
|
const renderedMarkdown = renderMd(this.props.text)
|
||||||
<ReactMarkdown source={this.props.text} astPlugins={
|
const parser = new HtmlToReact.Parser()
|
||||||
[
|
console.log(`prerender:${renderedMarkdown}`)
|
||||||
htmlParser({
|
|
||||||
isValidNode(node) { return node.type !== 'script' },
|
return parser.parseWithInstructions(renderedMarkdown, node => node.type !== 'script', processInstructions)
|
||||||
processingInstructions: astInst
|
|
||||||
})
|
|
||||||
]
|
|
||||||
}/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
10
src/Flows.js
10
src/Flows.js
@@ -7,7 +7,6 @@ import './Flows.css';
|
|||||||
import LazyLoad from './react-lazyload/src';
|
import LazyLoad from './react-lazyload/src';
|
||||||
import {AudioWidget} from './AudioWidget';
|
import {AudioWidget} from './AudioWidget';
|
||||||
import {TokenCtx, ReplyForm} from './UserAction';
|
import {TokenCtx, ReplyForm} from './UserAction';
|
||||||
import renderMd from './Markdown'
|
|
||||||
|
|
||||||
import {API, THUHOLE_API_ROOT} from './flows_api';
|
import {API, THUHOLE_API_ROOT} from './flows_api';
|
||||||
|
|
||||||
@@ -75,13 +74,6 @@ class Reply extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let parts=split_text(this.props.info.text,[
|
|
||||||
['url_pid',URL_PID_RE],
|
|
||||||
['url',URL_RE],
|
|
||||||
['pid',PID_RE],
|
|
||||||
['nickname',NICKNAME_RE],
|
|
||||||
]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'flow-reply box'} style={this.props.info._display_color ? {
|
<div className={'flow-reply box'} style={this.props.info._display_color ? {
|
||||||
'--box-bgcolor-light': this.props.info._display_color[0],
|
'--box-bgcolor-light': this.props.info._display_color[0],
|
||||||
@@ -103,7 +95,7 @@ class Reply extends PureComponent {
|
|||||||
<Time stamp={this.props.info.timestamp} />
|
<Time stamp={this.props.info.timestamp} />
|
||||||
</div>
|
</div>
|
||||||
<div className="box-content">
|
<div className="box-content">
|
||||||
<HighlightedText parts={parts} color_picker={this.props.color_picker} show_pid={this.props.show_pid} />
|
<HighlightedMarkdown text={this.props.info.text} color_picker={this.props.color_picker} show_pid={this.props.show_pid} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
8
src/Markdown.js
Normal file
8
src/Markdown.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import MarkdownIt from 'markdown-it'
|
||||||
|
|
||||||
|
let md = new MarkdownIt({
|
||||||
|
html: false,
|
||||||
|
linkify: false
|
||||||
|
})
|
||||||
|
|
||||||
|
export default (text) => md.render(text)
|
||||||
Reference in New Issue
Block a user