Merge branch 'master' of https://github.com/panda2134/webhole
This commit is contained in:
@@ -2,7 +2,12 @@ import React, {Component, PureComponent} from 'react';
|
||||
import {format_time,Time,TitleLine} from './infrastructure/widgets';
|
||||
import {THUHOLE_API_ROOT} from './flows_api';
|
||||
|
||||
import HtmlToReact from 'html-to-react'
|
||||
|
||||
import './Common.css';
|
||||
import { URL_PID_RE, URL_RE, PID_RE, NICKNAME_RE, split_text } from './text_splitter';
|
||||
|
||||
import renderMd from './Markdown'
|
||||
|
||||
export {format_time,Time,TitleLine};
|
||||
|
||||
@@ -26,11 +31,13 @@ export function ColoredSpan(props) {
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
function normalize_url(url) {
|
||||
return /^https?:\/\//.test(url) ? url : 'http://'+url;
|
||||
}
|
||||
|
||||
export class HighlightedText extends PureComponent {
|
||||
render() {
|
||||
function normalize_url(url) {
|
||||
return /^https?:\/\//.test(url) ? url : 'http://'+url;
|
||||
}
|
||||
return (
|
||||
<pre>
|
||||
{this.props.parts.map((part,idx)=>{
|
||||
@@ -51,6 +58,71 @@ export class HighlightedText extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
// props: text, show_pid, color_picker
|
||||
export class HighlightedMarkdown extends Component {
|
||||
render() {
|
||||
const props = this.props
|
||||
const processDefs = new HtmlToReact.ProcessNodeDefinitions(React)
|
||||
const processInstructions = [
|
||||
{
|
||||
shouldProcessNode: (node) => node.name === 'img', // disable images
|
||||
processNode (node) {
|
||||
return (<div>[图片]</div>)
|
||||
}
|
||||
},
|
||||
{
|
||||
shouldProcessNode: (node) => (/^h[123456]$/.test(node.name)),
|
||||
processNode (node, children, index) {
|
||||
let currentLevel = +(node.name[1])
|
||||
if (currentLevel < 3) currentLevel = 3;
|
||||
const HeadingTag = `h${currentLevel}`
|
||||
return (
|
||||
<HeadingTag key={index}>{children}</HeadingTag>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
shouldProcessNode (node) {
|
||||
return node.type === 'text' // pid, nickname, search
|
||||
},
|
||||
processNode (node) {
|
||||
const originalText = node.data
|
||||
const splitted = split_text(originalText, [
|
||||
['url_pid', URL_PID_RE],
|
||||
['url',URL_RE],
|
||||
['pid',PID_RE],
|
||||
['nickname',NICKNAME_RE],
|
||||
])
|
||||
|
||||
return (
|
||||
<>
|
||||
{splitted.map(([rule, p], idx) => {
|
||||
return (<span key={idx}>
|
||||
{
|
||||
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> :
|
||||
p}
|
||||
</span>)
|
||||
})}
|
||||
</>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
shouldProcessNode: () => true,
|
||||
processNode: processDefs.processDefaultNode
|
||||
}
|
||||
]
|
||||
const renderedMarkdown = renderMd(this.props.text)
|
||||
const parser = new HtmlToReact.Parser()
|
||||
|
||||
return parser.parseWithInstructions(renderedMarkdown, node => node.type !== 'script', processInstructions)
|
||||
}
|
||||
}
|
||||
|
||||
window.TEXTAREA_BACKUP={};
|
||||
|
||||
export class SafeTextarea extends Component {
|
||||
|
||||
19
src/Flows.js
19
src/Flows.js
@@ -2,7 +2,7 @@ import React, {Component, PureComponent} from 'react';
|
||||
import copy from 'copy-to-clipboard';
|
||||
import {ColorPicker} from './color_picker';
|
||||
import {split_text, NICKNAME_RE, PID_RE, URL_RE, URL_PID_RE} from './text_splitter';
|
||||
import {format_time, build_highlight_re, Time, TitleLine, HighlightedText, ClickHandler, ColoredSpan} from './Common';
|
||||
import {format_time, build_highlight_re, Time, TitleLine, HighlightedText, ClickHandler, ColoredSpan, HighlightedMarkdown} from './Common';
|
||||
import './Flows.css';
|
||||
import LazyLoad from './react-lazyload/src';
|
||||
import {AudioWidget} from './AudioWidget';
|
||||
@@ -74,13 +74,6 @@ class Reply extends PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
let parts=split_text(this.props.info.text,[
|
||||
['url_pid',URL_PID_RE],
|
||||
['url',URL_RE],
|
||||
['pid',PID_RE],
|
||||
['nickname',NICKNAME_RE],
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className={'flow-reply box'} style={this.props.info._display_color ? {
|
||||
'--box-bgcolor-light': this.props.info._display_color[0],
|
||||
@@ -102,7 +95,7 @@ class Reply extends PureComponent {
|
||||
<Time stamp={this.props.info.timestamp} />
|
||||
</div>
|
||||
<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>
|
||||
);
|
||||
@@ -129,12 +122,6 @@ class FlowItem extends PureComponent {
|
||||
|
||||
render() {
|
||||
let props=this.props;
|
||||
let parts=props.parts||split_text(props.info.text,[
|
||||
['url_pid',URL_PID_RE],
|
||||
['url',URL_RE],
|
||||
['pid',PID_RE],
|
||||
['nickname',NICKNAME_RE],
|
||||
]);
|
||||
return (
|
||||
<div className={'flow-item'+(props.is_quote ? ' flow-item-quote' : '')}>
|
||||
{!!props.is_quote &&
|
||||
@@ -175,7 +162,7 @@ class FlowItem extends PureComponent {
|
||||
<Time stamp={props.info.timestamp} />
|
||||
</div>
|
||||
<div className="box-content">
|
||||
<HighlightedText parts={parts} color_picker={props.color_picker} show_pid={props.show_pid} />
|
||||
<HighlightedMarkdown text={props.info.text} color_picker={props.color_picker} show_pid={props.show_pid} />
|
||||
{props.info.type==='image' &&
|
||||
<p className="img">
|
||||
{props.img_clickable ?
|
||||
|
||||
15
src/Markdown.js
Normal file
15
src/Markdown.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import MarkdownIt from 'markdown-it'
|
||||
import MarkdownItKaTeX from 'markdown-it-katex'
|
||||
|
||||
import 'katex/dist/katex.min.css'
|
||||
|
||||
let md = new MarkdownIt({
|
||||
html: false,
|
||||
linkify: false,
|
||||
breaks: true
|
||||
}).use(MarkdownItKaTeX, {
|
||||
"throwOnError" : false,
|
||||
"errorColor" : "#aa0000"
|
||||
})
|
||||
|
||||
export default (text) => md.render(text)
|
||||
Reference in New Issue
Block a user