forked from newthuhole/hole_thu_frontend
add auto link
This commit is contained in:
28
package-lock.json
generated
28
package-lock.json
generated
@@ -6305,6 +6305,14 @@
|
|||||||
"type-check": "0.3.2"
|
"type-check": "0.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"linkify-it": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz",
|
||||||
|
"integrity": "sha1-2UpGSPmxwXnWT6lykSaL22zpQ08=",
|
||||||
|
"requires": {
|
||||||
|
"uc.micro": "1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"load-json-file": {
|
"load-json-file": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
|
||||||
@@ -8788,6 +8796,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-lazyload/-/react-lazyload-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-lazyload/-/react-lazyload-2.3.0.tgz",
|
||||||
"integrity": "sha512-0z3qmL+qtSERdfKFpn0yKXm+1Gg1ZLZBXnCzHhSGiu1L8iDARuCkbOypxEx9+ETxZvMnXj98xvWCs5jyXTuM2w=="
|
"integrity": "sha512-0z3qmL+qtSERdfKFpn0yKXm+1Gg1ZLZBXnCzHhSGiu1L8iDARuCkbOypxEx9+ETxZvMnXj98xvWCs5jyXTuM2w=="
|
||||||
},
|
},
|
||||||
|
"react-linkify": {
|
||||||
|
"version": "0.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-linkify/-/react-linkify-0.2.2.tgz",
|
||||||
|
"integrity": "sha512-0S8cvUNtEgfJpIGDPKklyrnrTffJ63WuJAc4KaYLBihl5TjgH5cHUmYD+AXLpsV+CVmfoo/56SUNfrZcY4zYMQ==",
|
||||||
|
"requires": {
|
||||||
|
"linkify-it": "2.0.3",
|
||||||
|
"prop-types": "15.6.2",
|
||||||
|
"tlds": "1.203.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-scripts": {
|
"react-scripts": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-1.1.4.tgz",
|
||||||
@@ -10091,6 +10109,11 @@
|
|||||||
"setimmediate": "1.0.5"
|
"setimmediate": "1.0.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"tlds": {
|
||||||
|
"version": "1.203.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tlds/-/tlds-1.203.1.tgz",
|
||||||
|
"integrity": "sha512-7MUlYyGJ6rSitEZ3r1Q1QNV8uSIzapS8SmmhSusBuIc7uIxPPwsKllEP0GRp1NS6Ik6F+fRZvnjDWm3ecv2hDw=="
|
||||||
|
},
|
||||||
"tmp": {
|
"tmp": {
|
||||||
"version": "0.0.33",
|
"version": "0.0.33",
|
||||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
||||||
@@ -10234,6 +10257,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.18.tgz",
|
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.18.tgz",
|
||||||
"integrity": "sha512-LtzwHlVHwFGTptfNSgezHp7WUlwiqb0gA9AALRbKaERfxwJoiX0A73QbTToxteIAuIaFshhgIZfqK8s7clqgnA=="
|
"integrity": "sha512-LtzwHlVHwFGTptfNSgezHp7WUlwiqb0gA9AALRbKaERfxwJoiX0A73QbTToxteIAuIaFshhgIZfqK8s7clqgnA=="
|
||||||
},
|
},
|
||||||
|
"uc.micro": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg=="
|
||||||
|
},
|
||||||
"uglify-js": {
|
"uglify-js": {
|
||||||
"version": "3.4.7",
|
"version": "3.4.7",
|
||||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.7.tgz",
|
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.7.tgz",
|
||||||
|
|||||||
@@ -6,8 +6,9 @@
|
|||||||
"react": "^16.4.2",
|
"react": "^16.4.2",
|
||||||
"react-dom": "^16.4.2",
|
"react-dom": "^16.4.2",
|
||||||
"react-lazyload": "^2.3.0",
|
"react-lazyload": "^2.3.0",
|
||||||
|
"react-linkify": "^0.2.2",
|
||||||
"react-scripts": "1.1.4",
|
"react-scripts": "1.1.4",
|
||||||
"react-timeago": "^4.1.9"
|
"react-timeago": "^4.1.9",
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
|
|||||||
@@ -1,10 +1,21 @@
|
|||||||
import React, {Component} from 'react';
|
import React, {Component} from 'react';
|
||||||
|
|
||||||
import TimeAgo from 'react-timeago';
|
import TimeAgo from 'react-timeago';
|
||||||
|
import Linkify, {linkify} from 'react-linkify';
|
||||||
import chineseStrings from 'react-timeago/lib/language-strings/zh-CN';
|
import chineseStrings from 'react-timeago/lib/language-strings/zh-CN';
|
||||||
import buildFormatter from 'react-timeago/lib/formatters/buildFormatter';
|
import buildFormatter from 'react-timeago/lib/formatters/buildFormatter';
|
||||||
|
|
||||||
import './Common.css';
|
import './Common.css';
|
||||||
|
|
||||||
const chinese_format=buildFormatter(chineseStrings);
|
const chinese_format=buildFormatter(chineseStrings);
|
||||||
|
const PID_RE_TEXT=/(?:^|[^\d])(\d{5,6})(?!\d)/g;
|
||||||
|
|
||||||
|
linkify.add('#', {
|
||||||
|
validate: /^(\d{5,6})/,
|
||||||
|
normalize: (match) => {
|
||||||
|
match.url='#'+match.url;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
function pad2(x) {
|
function pad2(x) {
|
||||||
return x<10 ? '0'+x : ''+x;
|
return x<10 ? '0'+x : ''+x;
|
||||||
@@ -29,3 +40,11 @@ export function TitleLine(props) {
|
|||||||
</p>
|
</p>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function AutoLink(props) {
|
||||||
|
return (
|
||||||
|
<Linkify properties={{target: '_blank'}}>
|
||||||
|
<pre>{props.text.replace(new RegExp(PID_RE_TEXT,'g'),' #$1 ')}</pre>
|
||||||
|
</Linkify>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.left-container .flow-item-row {
|
.left-container .flow-item-row {
|
||||||
cursor: pointer;
|
cursor: default;
|
||||||
transition: margin-left 200ms ease-out;
|
transition: margin-left 200ms ease-out;
|
||||||
}
|
}
|
||||||
.left-container .flow-item-row:hover {
|
.left-container .flow-item-row:hover {
|
||||||
|
|||||||
25
src/Flows.js
25
src/Flows.js
@@ -1,5 +1,5 @@
|
|||||||
import React, {Component} from 'react';
|
import React, {Component} from 'react';
|
||||||
import {Time, TitleLine} from './Common.js';
|
import {Time, TitleLine, AutoLink} from './Common.js';
|
||||||
import './Flows.css';
|
import './Flows.css';
|
||||||
import LazyLoad from 'react-lazyload';
|
import LazyLoad from 'react-lazyload';
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ function Reply(props) {
|
|||||||
<span className="box-id">#{props.info.cid}</span>
|
<span className="box-id">#{props.info.cid}</span>
|
||||||
<Time stamp={props.info.timestamp} />
|
<Time stamp={props.info.timestamp} />
|
||||||
</div>
|
</div>
|
||||||
<pre>{props.info.text}</pre>
|
<AutoLink text={props.info.text} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,7 @@ function FlowItem(props) {
|
|||||||
<span className="box-id">#{props.info.pid}</span>
|
<span className="box-id">#{props.info.pid}</span>
|
||||||
<Time stamp={props.info.timestamp} />
|
<Time stamp={props.info.timestamp} />
|
||||||
</div>
|
</div>
|
||||||
<pre>{props.info.text}</pre>
|
<AutoLink text={props.info.text} />
|
||||||
{props.info.type==='image' ? <img src={IMAGE_BASE+props.info.url} /> : null}
|
{props.info.type==='image' ? <img src={IMAGE_BASE+props.info.url} /> : null}
|
||||||
{props.info.type==='audio' ? <audio src={AUDIO_BASE+props.info.url} /> : null}
|
{props.info.type==='audio' ? <audio src={AUDIO_BASE+props.info.url} /> : null}
|
||||||
</div>
|
</div>
|
||||||
@@ -79,13 +79,16 @@ class FlowItemRow extends Component {
|
|||||||
render() {
|
render() {
|
||||||
// props.do_show_details
|
// props.do_show_details
|
||||||
return (
|
return (
|
||||||
<div className="flow-item-row" onClick={()=>{this.props.callback(
|
<div className="flow-item-row" onClick={(event)=>{
|
||||||
'帖子详情',
|
if(event.target.tagName.toLowerCase()!=='a')
|
||||||
<div className="flow-item-row sidebar-flow-item">
|
this.props.callback(
|
||||||
<FlowItem info={this.info} />
|
'帖子详情',
|
||||||
{this.state.replies.map((reply)=><Reply info={reply} key={reply.cid} />)}
|
<div className="flow-item-row sidebar-flow-item">
|
||||||
</div>
|
<FlowItem info={this.info} />
|
||||||
)}}>
|
{this.state.replies.map((reply)=><Reply info={reply} key={reply.cid} />)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}>
|
||||||
<FlowItem info={this.info} />
|
<FlowItem info={this.info} />
|
||||||
{!!this.state.reply_loading && <ReplyPlaceholder count={this.info.reply} />}
|
{!!this.state.reply_loading && <ReplyPlaceholder count={this.info.reply} />}
|
||||||
{this.state.replies.map((reply)=><Reply info={reply} key={reply.cid} />)}
|
{this.state.replies.map((reply)=><Reply info={reply} key={reply.cid} />)}
|
||||||
@@ -121,7 +124,6 @@ export class Flow extends Component {
|
|||||||
chunks: [],
|
chunks: [],
|
||||||
loading: false,
|
loading: false,
|
||||||
};
|
};
|
||||||
setTimeout(this.load_page.bind(this,1), 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
load_page(page) {
|
load_page(page) {
|
||||||
@@ -212,6 +214,7 @@ export class Flow extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
this.load_page(1);
|
||||||
window.addEventListener('scroll',this.on_scroll.bind(this));
|
window.addEventListener('scroll',this.on_scroll.bind(this));
|
||||||
window.addEventListener('resize',this.on_scroll.bind(this));
|
window.addEventListener('resize',this.on_scroll.bind(this));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,10 @@
|
|||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.title-bar a {
|
||||||
|
padding: 0 .5em;
|
||||||
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
line-height: 3em;
|
line-height: 3em;
|
||||||
|
|||||||
10
src/Title.js
10
src/Title.js
@@ -42,6 +42,16 @@ class ControlBar extends Component {
|
|||||||
this.set_search_text=props.set_search_text;
|
this.set_search_text=props.set_search_text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if(window.location.hash) {
|
||||||
|
const text=window.location.hash.substr(1);
|
||||||
|
this.setState({
|
||||||
|
search_text: text,
|
||||||
|
});
|
||||||
|
this.set_search_text(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
on_change(event) {
|
on_change(event) {
|
||||||
this.setState({
|
this.setState({
|
||||||
search_text: event.target.value,
|
search_text: event.target.value,
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ a {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: #00c;
|
color: #00c;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 0 .5em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
|
|||||||
Reference in New Issue
Block a user