Browse Source

update

add setflag directive
add deletion detect and star brush
remove paginator
fix location.hash detection
dev
xmcp 7 years ago
parent
commit
f6e24c2803
  1. 11
      README.md
  2. 4
      src/Flows.css
  3. 74
      src/Flows.js
  4. 12
      src/Title.js

11
README.md

@ -1,7 +1,5 @@
# AsHole # AsHole
React版P大树洞,[hole.xmcp.ml](http://hole.xmcp.ml) React 版 P大树洞,[hole.xmcp.ml](http://hole.xmcp.ml)
与 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`*

4
src/Flows.css

@ -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

@ -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>
&nbsp;/&nbsp;
</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>

12
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,7 +61,8 @@ 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);
text=text.substr(0,text.lastIndexOf('?')); // fuck wechat '#param?nsukey=...' if(text.lastIndexOf('?')!==-1)
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);
} }

Loading…
Cancel
Save