update
add setflag directive add deletion detect and star brush remove paginator fix location.hash detection
This commit is contained in:
@@ -1,8 +1,6 @@
|
|||||||
# AsHole
|
# AsHole
|
||||||
React 版 P大树洞,[hole.xmcp.ml](http://hole.xmcp.ml)
|
React 版 P大树洞,[hole.xmcp.ml](http://hole.xmcp.ml)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
与 PKU Helper 客户端比较,本项目……
|
与 PKU Helper 客户端比较,本项目……
|
||||||
|
|
||||||
**支持** PKU Helper 树洞**支持**的以下功能:
|
**支持** PKU Helper 树洞**支持**的以下功能:
|
||||||
@@ -31,10 +29,15 @@ React版P大树洞,[hole.xmcp.ml](http://hole.xmcp.ml)
|
|||||||
- 精确显示发帖时间
|
- 精确显示发帖时间
|
||||||
- 复制树洞链接
|
- 复制树洞链接
|
||||||
- 3D Touch 支持
|
- 3D Touch 支持
|
||||||
- 自定义背景图片(没有提供相关 UI,请自行修改 `localStorage['REPLACE_ERIRI_WITH_URL']`)
|
- 自定义背景图片(请修改 Flag `REPLACE_ERIRI_WITH_URL=http://...`)
|
||||||
|
- 检测被删除的树洞(请修改 Flag `DELETION_DETECT=on`)
|
||||||
|
- 刷树洞负关注数(请修改 Flag `STAR_BRUSH=on`)
|
||||||
|
- 用 Token 登录(请修改 Flag `TOKEN=...`)
|
||||||
|
|
||||||
**不支持** PKU Helper 树洞**支持**的以下功能:
|
**不支持** PKU Helper 树洞**支持**的以下功能:
|
||||||
|
|
||||||
- 搜索时筛选有图片、语音的树洞
|
- 搜索时筛选有图片、语音的树洞
|
||||||
- 发表语音树洞
|
- 发表语音树洞
|
||||||
- 关注的树洞有回复时推送提醒
|
- 关注的树洞有回复时推送提醒
|
||||||
|
|
||||||
|
*注:设置 Flag 请在搜索框输入 `//setflag KEY=value`*
|
||||||
@@ -12,6 +12,10 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.box-danger {
|
||||||
|
background-color: #faa;
|
||||||
|
}
|
||||||
|
|
||||||
.left-container .flow-item {
|
.left-container .flow-item {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 600px;
|
width: 600px;
|
||||||
|
|||||||
74
src/Flows.js
74
src/Flows.js
@@ -189,12 +189,36 @@ class FlowSidebar extends PureComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
star_brush() {
|
||||||
|
let count=prompt('Count:');
|
||||||
|
if(count) {
|
||||||
|
let reqs=[];
|
||||||
|
for(let i=parseInt(count);i;i--)
|
||||||
|
reqs.push(API.set_attention(this.state.info.pid,false,this.props.token));
|
||||||
|
Promise.all(reqs)
|
||||||
|
.then(()=>{
|
||||||
|
alert('Completed!')
|
||||||
|
})
|
||||||
|
.catch((e)=>{
|
||||||
|
alert('Failed!\n\n'+e);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const star_brush=localStorage['STAR_BRUSH']==='on';
|
||||||
|
|
||||||
if(this.state.loading_status==='loading')
|
if(this.state.loading_status==='loading')
|
||||||
return (<p className="box box-tip">加载中……</p>);
|
return (<p className="box box-tip">加载中……</p>);
|
||||||
return (
|
return (
|
||||||
<div className="flow-item-row sidebar-flow-item">
|
<div className="flow-item-row sidebar-flow-item">
|
||||||
<div className="box box-tip">
|
<div className="box box-tip">
|
||||||
|
{star_brush &&
|
||||||
|
<span>
|
||||||
|
<a onClick={this.star_brush.bind(this)}>-</a>
|
||||||
|
/
|
||||||
|
</span>
|
||||||
|
}
|
||||||
{this.props.token &&
|
{this.props.token &&
|
||||||
<span>
|
<span>
|
||||||
<a onClick={this.report.bind(this)}>举报</a>
|
<a onClick={this.report.bind(this)}>举报</a>
|
||||||
@@ -314,9 +338,16 @@ function FlowChunk(props) {
|
|||||||
return (
|
return (
|
||||||
<TokenCtx.Consumer>{({value: token})=>(
|
<TokenCtx.Consumer>{({value: token})=>(
|
||||||
<div className="flow-chunk">
|
<div className="flow-chunk">
|
||||||
<TitleLine text={props.title} />
|
{!!props.title && <TitleLine text={props.title} />}
|
||||||
{props.list.map((info)=>(
|
{props.list.map((info,ind)=>(
|
||||||
<LazyLoad key={info.pid} offset={500} height="15em" once={true} >
|
<LazyLoad key={info.pid} offset={500} height="15em" once={true} >
|
||||||
|
{!!(props.deletion_detect && props.mode==='list' && ind && props.list[ind-1].pid-info.pid>1) &&
|
||||||
|
<div className="flow-item-row">
|
||||||
|
<div className="box box-tip flow-item box-danger">
|
||||||
|
{props.list[ind-1].pid-info.pid-1} 条被删除
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
<FlowItemRow info={info} show_sidebar={props.show_sidebar} token={token} />
|
<FlowItemRow info={info} show_sidebar={props.show_sidebar} token={token} />
|
||||||
</LazyLoad>
|
</LazyLoad>
|
||||||
))}
|
))}
|
||||||
@@ -332,7 +363,10 @@ export class Flow extends PureComponent {
|
|||||||
mode: props.mode,
|
mode: props.mode,
|
||||||
search_param: props.search_text,
|
search_param: props.search_text,
|
||||||
loaded_pages: 0,
|
loaded_pages: 0,
|
||||||
chunks: [],
|
chunks: {
|
||||||
|
title: '',
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
loading_status: 'done',
|
loading_status: 'done',
|
||||||
};
|
};
|
||||||
this.on_scroll_bound=this.on_scroll.bind(this);
|
this.on_scroll_bound=this.on_scroll.bind(this);
|
||||||
@@ -360,13 +394,13 @@ export class Flow extends PureComponent {
|
|||||||
localStorage['_LATEST_POST_ID']=x.pid;
|
localStorage['_LATEST_POST_ID']=x.pid;
|
||||||
});
|
});
|
||||||
this.setState((prev,props)=>({
|
this.setState((prev,props)=>({
|
||||||
chunks: prev.chunks.concat([{
|
chunks: {
|
||||||
title: 'Page '+page,
|
title: 'News Feed',
|
||||||
data: json.data.filter((x)=>(
|
data: prev.chunks.data.concat(json.data.filter((x)=>(
|
||||||
prev.chunks.length===0 ||
|
prev.chunks.data.length===0 ||
|
||||||
!(prev.chunks[prev.chunks.length-1].data.some((p)=>p.pid===x.pid))
|
!(prev.chunks.data.slice(-100).some((p)=>p.pid===x.pid))
|
||||||
)),
|
))),
|
||||||
}]),
|
},
|
||||||
loading_status: 'done',
|
loading_status: 'done',
|
||||||
}));
|
}));
|
||||||
})
|
})
|
||||||
@@ -376,10 +410,10 @@ export class Flow extends PureComponent {
|
|||||||
.then((json)=>{
|
.then((json)=>{
|
||||||
const finished=json.data.length<SEARCH_PAGESIZE;
|
const finished=json.data.length<SEARCH_PAGESIZE;
|
||||||
this.setState({
|
this.setState({
|
||||||
chunks: [{
|
chunks: {
|
||||||
title: 'Result for "'+this.state.search_param+'"',
|
title: 'Result for "'+this.state.search_param+'"',
|
||||||
data: json.data,
|
data: json.data,
|
||||||
}],
|
},
|
||||||
mode: finished ? 'search_finished' : 'search',
|
mode: finished ? 'search_finished' : 'search',
|
||||||
loading_status: 'done',
|
loading_status: 'done',
|
||||||
});
|
});
|
||||||
@@ -390,10 +424,10 @@ export class Flow extends PureComponent {
|
|||||||
API.get_single(pid,this.props.token)
|
API.get_single(pid,this.props.token)
|
||||||
.then((json)=>{
|
.then((json)=>{
|
||||||
this.setState({
|
this.setState({
|
||||||
chunks: [{
|
chunks: {
|
||||||
title: 'PID = '+pid,
|
title: 'PID = '+pid,
|
||||||
data: [json.data],
|
data: [json.data],
|
||||||
}],
|
},
|
||||||
mode: 'single_finished',
|
mode: 'single_finished',
|
||||||
loading_status: 'done',
|
loading_status: 'done',
|
||||||
});
|
});
|
||||||
@@ -403,10 +437,10 @@ export class Flow extends PureComponent {
|
|||||||
API.get_attention(this.props.token)
|
API.get_attention(this.props.token)
|
||||||
.then((json)=>{
|
.then((json)=>{
|
||||||
this.setState({
|
this.setState({
|
||||||
chunks: [{
|
chunks: {
|
||||||
title: 'Attention List',
|
title: 'Attention List',
|
||||||
data: json.data,
|
data: json.data,
|
||||||
}],
|
},
|
||||||
mode: 'attention_finished',
|
mode: 'attention_finished',
|
||||||
loading_status: 'done',
|
loading_status: 'done',
|
||||||
});
|
});
|
||||||
@@ -443,11 +477,13 @@ export class Flow extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const should_deletion_detect=localStorage['DELETION_DETECT']==='on';
|
||||||
return (
|
return (
|
||||||
<div className="flow-container">
|
<div className="flow-container">
|
||||||
{this.state.chunks.map((chunk)=>(
|
<FlowChunk
|
||||||
<FlowChunk title={chunk.title} list={chunk.data} key={chunk.title} show_sidebar={this.props.show_sidebar} />
|
title={this.state.chunks.title} list={this.state.chunks.data}
|
||||||
))}
|
show_sidebar={this.props.show_sidebar} mode={this.state.mode} deletion_detect={should_deletion_detect}
|
||||||
|
/>
|
||||||
{this.state.loading_status==='failed' &&
|
{this.state.loading_status==='failed' &&
|
||||||
<div className="box box-tip">
|
<div className="box box-tip">
|
||||||
<a onClick={()=>{this.load_page(this.state.loaded_pages+1)}}>重新加载</a>
|
<a onClick={()=>{this.load_page(this.state.loaded_pages+1)}}>重新加载</a>
|
||||||
|
|||||||
10
src/Title.js
10
src/Title.js
@@ -5,6 +5,8 @@ import {PromotionBar} from './Common';
|
|||||||
|
|
||||||
import './Title.css';
|
import './Title.css';
|
||||||
|
|
||||||
|
const flag_re=/^\/\/setflag ([a-zA-Z0-9_]+)=(.+)$/;
|
||||||
|
|
||||||
const HELP_TEXT=(
|
const HELP_TEXT=(
|
||||||
<div className="box">
|
<div className="box">
|
||||||
<p>使用提示:</p>
|
<p>使用提示:</p>
|
||||||
@@ -59,6 +61,7 @@ class ControlBar extends PureComponent {
|
|||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if(window.location.hash) {
|
if(window.location.hash) {
|
||||||
let text=window.location.hash.substr(1);
|
let text=window.location.hash.substr(1);
|
||||||
|
if(text.lastIndexOf('?')!==-1)
|
||||||
text=text.substr(0,text.lastIndexOf('?')); // fuck wechat '#param?nsukey=...'
|
text=text.substr(0,text.lastIndexOf('?')); // fuck wechat '#param?nsukey=...'
|
||||||
this.setState({
|
this.setState({
|
||||||
search_text: text,
|
search_text: text,
|
||||||
@@ -76,6 +79,13 @@ class ControlBar extends PureComponent {
|
|||||||
|
|
||||||
on_keypress(event) {
|
on_keypress(event) {
|
||||||
if(event.key==='Enter') {
|
if(event.key==='Enter') {
|
||||||
|
let flag_res=flag_re.exec(this.state.search_text);
|
||||||
|
if(flag_res) {
|
||||||
|
localStorage[flag_res[1]]=flag_res[2];
|
||||||
|
alert('Set Flag '+flag_res[1]+'='+flag_res[2]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const mode=this.state.search_text.startsWith('#') ? 'single' : 'search';
|
const mode=this.state.search_text.startsWith('#') ? 'single' : 'search';
|
||||||
this.set_mode(mode,this.state.search_text||null);
|
this.set_mode(mode,this.state.search_text||null);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user