点击tag搜索,插图依靠图片外链
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
|||||||
URL_RE,
|
URL_RE,
|
||||||
PID_RE,
|
PID_RE,
|
||||||
NICKNAME_RE,
|
NICKNAME_RE,
|
||||||
|
TAG_RE,
|
||||||
split_text,
|
split_text,
|
||||||
} from './text_splitter';
|
} from './text_splitter';
|
||||||
|
|
||||||
@@ -67,6 +68,7 @@ function normalize_url(url) {
|
|||||||
return /^https?:\/\//.test(url) ? url : 'http://' + url;
|
return /^https?:\/\//.test(url) ? url : 'http://' + url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
export class HighlightedText extends PureComponent {
|
export class HighlightedText extends PureComponent {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
@@ -109,6 +111,7 @@ export class HighlightedText extends PureComponent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// props: text, show_pid, color_picker
|
// props: text, show_pid, color_picker
|
||||||
export class HighlightedMarkdown extends Component {
|
export class HighlightedMarkdown extends Component {
|
||||||
@@ -116,12 +119,6 @@ export class HighlightedMarkdown extends Component {
|
|||||||
const props = this.props;
|
const props = this.props;
|
||||||
const processDefs = new HtmlToReact.ProcessNodeDefinitions(React);
|
const processDefs = new HtmlToReact.ProcessNodeDefinitions(React);
|
||||||
const processInstructions = [
|
const processInstructions = [
|
||||||
{
|
|
||||||
shouldProcessNode: (node) => node.name === 'img', // disable images
|
|
||||||
processNode(node, children, index) {
|
|
||||||
return <div key={index}>[图片]</div>;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
shouldProcessNode: (node) => /^h[123456]$/.test(node.name),
|
shouldProcessNode: (node) => /^h[123456]$/.test(node.name),
|
||||||
processNode(node, children, index) {
|
processNode(node, children, index) {
|
||||||
@@ -131,6 +128,26 @@ export class HighlightedMarkdown extends Component {
|
|||||||
return <HeadingTag key={index}>{children}</HeadingTag>;
|
return <HeadingTag key={index}>{children}</HeadingTag>;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
shouldProcessNode: (node) => node.name === 'img',
|
||||||
|
processNode(node, index) {
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
href={normalize_url(node.attribs.src)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopenner noreferrer"
|
||||||
|
className="ext-link"
|
||||||
|
key={index}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={normalize_url(node.attribs.src)}
|
||||||
|
alt={node.alt}
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
shouldProcessNode: (node) => node.name === 'a',
|
shouldProcessNode: (node) => node.name === 'a',
|
||||||
processNode(node, children, index) {
|
processNode(node, children, index) {
|
||||||
@@ -164,7 +181,7 @@ export class HighlightedMarkdown extends Component {
|
|||||||
['url', URL_RE],
|
['url', URL_RE],
|
||||||
['pid', PID_RE],
|
['pid', PID_RE],
|
||||||
['nickname', NICKNAME_RE],
|
['nickname', NICKNAME_RE],
|
||||||
//TODO: tag
|
['tag', TAG_RE],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -202,6 +219,12 @@ export class HighlightedMarkdown extends Component {
|
|||||||
</ColoredSpan>
|
</ColoredSpan>
|
||||||
) : rule === 'search' ? (
|
) : rule === 'search' ? (
|
||||||
<span className="search-query-highlight">{p}</span>
|
<span className="search-query-highlight">{p}</span>
|
||||||
|
) : rule === 'tag' ? (
|
||||||
|
<a
|
||||||
|
href={p}
|
||||||
|
>
|
||||||
|
{p}
|
||||||
|
</a>
|
||||||
) : (
|
) : (
|
||||||
p
|
p
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -193,6 +193,17 @@
|
|||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.box-content img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 2000px;
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-container .box-content img {
|
||||||
|
max-height: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
.left-container .box-content {
|
.left-container .box-content {
|
||||||
max-height: calc(100vh + 15em);
|
max-height: calc(100vh + 15em);
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
PID_RE,
|
PID_RE,
|
||||||
URL_RE,
|
URL_RE,
|
||||||
URL_PID_RE,
|
URL_PID_RE,
|
||||||
|
TAG_RE,
|
||||||
} from './text_splitter';
|
} from './text_splitter';
|
||||||
import {
|
import {
|
||||||
format_time,
|
format_time,
|
||||||
@@ -665,7 +666,7 @@ class FlowItemRow extends PureComponent {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.needFold = props.info.cw &&
|
this.needFold = props.info.cw &&
|
||||||
(props.search_param === '热榜' || !props.search_param) &&
|
!props.search_param &&
|
||||||
(window.config.whitelist_cw.indexOf('*')==-1 && window.config.whitelist_cw.indexOf(props.info.cw)==-1) &&
|
(window.config.whitelist_cw.indexOf('*')==-1 && window.config.whitelist_cw.indexOf(props.info.cw)==-1) &&
|
||||||
props.mode !== 'attention' && props.mode !== 'attention_finished';
|
props.mode !== 'attention' && props.mode !== 'attention_finished';
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -770,6 +771,7 @@ class FlowItemRow extends PureComponent {
|
|||||||
['url', URL_RE],
|
['url', URL_RE],
|
||||||
['pid', PID_RE],
|
['pid', PID_RE],
|
||||||
['nickname', NICKNAME_RE],
|
['nickname', NICKNAME_RE],
|
||||||
|
['tag', TAG_RE],
|
||||||
];
|
];
|
||||||
if (this.props.search_param) {
|
if (this.props.search_param) {
|
||||||
hl_rules.push([
|
hl_rules.push([
|
||||||
@@ -781,6 +783,8 @@ class FlowItemRow extends PureComponent {
|
|||||||
}
|
}
|
||||||
let parts = split_text(this.state.info.text, hl_rules);
|
let parts = split_text(this.state.info.text, hl_rules);
|
||||||
|
|
||||||
|
//console.log('hl:', parts,this.state.info.pid);
|
||||||
|
|
||||||
let quote_id = null;
|
let quote_id = null;
|
||||||
if (!this.props.is_quote)
|
if (!this.props.is_quote)
|
||||||
for (let [mode, content] of parts) {
|
for (let [mode, content] of parts) {
|
||||||
|
|||||||
23
src/Title.js
23
src/Title.js
@@ -35,6 +35,24 @@ class ControlBar extends PureComponent {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.addEventListener("hashchange",
|
||||||
|
() => {
|
||||||
|
let text = decodeURIComponent(window.location.hash).substr(1);
|
||||||
|
if(text && text[0]!='#') {
|
||||||
|
console.log('search', text);
|
||||||
|
this.setState(
|
||||||
|
{
|
||||||
|
search_text: text,
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
this.on_keypress({ key: 'Enter' });
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
on_change(event) {
|
on_change(event) {
|
||||||
@@ -116,9 +134,8 @@ class ControlBar extends PureComponent {
|
|||||||
<input
|
<input
|
||||||
className="control-search"
|
className="control-search"
|
||||||
value={this.state.search_text}
|
value={this.state.search_text}
|
||||||
placeholder={`${
|
placeholder={
|
||||||
this.props.mode === 'attention' ? '在关注列表中' : ''
|
this.props.mode === 'attention' ? '在关注列表中搜索' : '搜tag或 #树洞号, 如: 新手导引'}
|
||||||
}搜索 或 #树洞号`}
|
|
||||||
onChange={this.on_change_bound}
|
onChange={this.on_change_bound}
|
||||||
onKeyPress={this.on_keypress_bound}
|
onKeyPress={this.on_keypress_bound}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -541,6 +541,7 @@ export class PostForm extends Component {
|
|||||||
on_submit(event) {
|
on_submit(event) {
|
||||||
if (event) event.preventDefault();
|
if (event) event.preventDefault();
|
||||||
if (this.state.loading_status === 'loading') return;
|
if (this.state.loading_status === 'loading') return;
|
||||||
|
/*
|
||||||
if (this.img_ref.current.files.length) {
|
if (this.img_ref.current.files.length) {
|
||||||
this.setState({
|
this.setState({
|
||||||
loading_status: 'processing',
|
loading_status: 'processing',
|
||||||
@@ -555,7 +556,8 @@ export class PostForm extends Component {
|
|||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
alert(e);
|
alert(e);
|
||||||
});
|
});
|
||||||
} else {
|
} else */
|
||||||
|
{
|
||||||
this.setState({
|
this.setState({
|
||||||
loading_status: 'loading',
|
loading_status: 'loading',
|
||||||
});
|
});
|
||||||
@@ -573,6 +575,7 @@ export class PostForm extends Component {
|
|||||||
return (
|
return (
|
||||||
<form onSubmit={this.on_submit.bind(this)} className="post-form box">
|
<form onSubmit={this.on_submit.bind(this)} className="post-form box">
|
||||||
<div className="post-form-bar">
|
<div className="post-form-bar">
|
||||||
|
{/*
|
||||||
<label>
|
<label>
|
||||||
图片
|
图片
|
||||||
<input
|
<input
|
||||||
@@ -583,6 +586,7 @@ export class PostForm extends Component {
|
|||||||
onChange={this.on_img_change_bound}
|
onChange={this.on_img_change_bound}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
*/}
|
||||||
|
|
||||||
{this.state.preview ? (
|
{this.state.preview ? (
|
||||||
<button
|
<button
|
||||||
@@ -665,7 +669,28 @@ export class PostForm extends Component {
|
|||||||
<a href="https://thuhole.com/policy.html" target="_blank">
|
<a href="https://thuhole.com/policy.html" target="_blank">
|
||||||
树洞管理规范(试行)
|
树洞管理规范(试行)
|
||||||
</a>
|
</a>
|
||||||
,文明发言
|
,文明发言。
|
||||||
|
</small>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<small>
|
||||||
|
插入图片请使用图片外链,Markdown格式 , 支持动图,支持多图。推荐的图床:
|
||||||
|
<a href="https://imgchr.com/" target="_blank">
|
||||||
|
路过图床
|
||||||
|
</a>
|
||||||
|
、
|
||||||
|
<a href="https://sm.ms/" target="_blank">
|
||||||
|
sm.ms
|
||||||
|
</a>
|
||||||
|
、
|
||||||
|
<a href="https://bbs.pku.edu.cn/v2/post-read.php?bid=154&threadid=3743" target="_blank">
|
||||||
|
未名BBS
|
||||||
|
</a>
|
||||||
|
、
|
||||||
|
<a href="https://zhuanlan.zhihu.com/write" target="_blank">
|
||||||
|
知乎
|
||||||
|
</a>
|
||||||
|
。
|
||||||
</small>
|
</small>
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ export const URL_PID_RE = /((?:https?:\/\/)?thuhole\.com\/?#(?:#|%23)(\d{1,7}))(
|
|||||||
export const NICKNAME_RE = /(^|[^A-Za-z])((?:(?:Angry|Baby|Crazy|Diligent|Excited|Fat|Greedy|Hungry|Interesting|Jolly|Kind|Little|Magic|Naïve|Old|PKU|Quiet|Rich|Superman|Tough|Undefined|Valuable|Wifeless|Xiangbuchulai|Young|Zombie)\s)?(?:Alice|Bob|Carol|Dave|Eve|Francis|Grace|Hans|Isabella|Jason|Kate|Louis|Margaret|Nathan|Olivia|Paul|Queen|Richard|Susan|Thomas|Uma|Vivian|Winnie|Xander|Yasmine|Zach)|You Win(?: \d+)?|洞主)(?![A-Za-z])/gi;
|
export const NICKNAME_RE = /(^|[^A-Za-z])((?:(?:Angry|Baby|Crazy|Diligent|Excited|Fat|Greedy|Hungry|Interesting|Jolly|Kind|Little|Magic|Naïve|Old|PKU|Quiet|Rich|Superman|Tough|Undefined|Valuable|Wifeless|Xiangbuchulai|Young|Zombie)\s)?(?:Alice|Bob|Carol|Dave|Eve|Francis|Grace|Hans|Isabella|Jason|Kate|Louis|Margaret|Nathan|Olivia|Paul|Queen|Richard|Susan|Thomas|Uma|Vivian|Winnie|Xander|Yasmine|Zach)|You Win(?: \d+)?|洞主)(?![A-Za-z])/gi;
|
||||||
export const URL_RE = /(^|[^.@a-zA-Z0-9_])((?:https?:\/\/)?(?:(?:[\w-]+\.)+[a-zA-Z]{2,3}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?::\d{1,5})?(?:\/[\w~!@#$%^&*()\-_=+[\]{};:,./?|]*)?)(?![a-zA-Z0-9])/gi;
|
export const URL_RE = /(^|[^.@a-zA-Z0-9_])((?:https?:\/\/)?(?:(?:[\w-]+\.)+[a-zA-Z]{2,3}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?::\d{1,5})?(?:\/[\w~!@#$%^&*()\-_=+[\]{};:,./?|]*)?)(?![a-zA-Z0-9])/gi;
|
||||||
|
|
||||||
|
export const TAG_RE = /(^|\s)(#[^#\s]{1,32})($|\s|#)/g;
|
||||||
|
|
||||||
export function split_text(txt, rules) {
|
export function split_text(txt, rules) {
|
||||||
// rules: [['name',/regex/],...]
|
// rules: [['name',/regex/],...]
|
||||||
// return: [['name','part'],[null,'part'],...]
|
// return: [['name','part'],[null,'part'],...]
|
||||||
|
|||||||
Reference in New Issue
Block a user