import React, {Component, PureComponent} from 'react'; import copy from 'copy-to-clipboard'; import {ColorPicker} from './color_picker'; import {Time, TitleLine, HighlightedText} from './Common'; import './Flows.css'; import LazyLoad from 'react-lazyload'; import {AudioWidget} from './AudioWidget'; import {TokenCtx, ReplyForm} from './UserAction'; import {API} from './flows_api'; const IMAGE_BASE='http://www.pkuhelper.com/services/pkuhole/images/'; const AUDIO_BASE='/audio_proxy/'; const SEARCH_PAGESIZE=50; const CLICKABLE_TAGS={a: true, audio: true}; const PREVIEW_REPLY_COUNT=10; window.LATEST_POST_ID=parseInt(localStorage['_LATEST_POST_ID'],10)||0; function load_single_meta(show_sidebar,token) { return (pid)=>{ const color_picker=new ColorPicker(); show_sidebar( '帖子详情',
正在加载 #{pid}
); Promise.all([ API.get_single(pid,token), API.load_replies(pid,token,color_picker), ]) .then((res)=>{ const [single,replies]=res; show_sidebar( '帖子详情', ) }) .catch((e)=>{ console.trace(e); show_sidebar( '帖子详情',
load_single_meta(show_sidebar,token)}>重新加载
); }) }; } function Reply(props) { return (
#{props.info.cid} 
); } function FlowItem(props) { function copy_link(event) { event.preventDefault(); copy(event.target.href); } return (
{parseInt(props.info.pid,10)>window.LATEST_POST_ID &&
}
{!!parseInt(props.info.likenum,10) && {props.info.likenum}  } {!!parseInt(props.info.reply,10) && {props.info.reply}  } #{props.info.pid}  
{props.info.type==='image' ?

: null} {props.info.type==='audio' ? : null}
); } class FlowSidebar extends PureComponent { constructor(props) { super(props); this.state={ attention: props.attention, info: props.info, replies: props.replies, loading_status: 'done', }; this.color_picker=props.color_picker; this.show_pid=load_single_meta(this.props.show_sidebar,this.props.token); this.syncState=props.sync_state||(()=>{}); } load_replies() { this.setState({ loading_status: 'loading', }); API.load_replies(this.state.info.pid,this.props.token,this.color_picker) .then((json)=>{ this.setState((prev,props)=>({ replies: json.data, info: Object.assign({}, prev.info, { reply: ''+json.data.length, }), attention: !!json.attention, loading_status: 'done', }), ()=>{ this.syncState({ replies: this.state.replies, attention: this.state.attention, info: this.state.info, }); }); }) .catch((e)=>{ console.trace(e); this.setState({ replies: [], loading_status: 'done', }); }); } toggle_attention() { this.setState({ loading_status: 'loading', }); const next_attention=!this.state.attention; API.set_attention(this.state.info.pid,next_attention,this.props.token) .then((json)=>{ this.setState({ loading_status: 'done', attention: next_attention, }); this.syncState({ attention: next_attention, }); }) .catch((e)=>{ this.setState({ loading_status: 'done' }); alert('设置关注失败'); console.trace(e); }); } render() { if(this.state.loading_status==='loading') return (

加载中……

); return (
刷新回复 {this.props.token &&  /  { this.toggle_attention(); }}> {this.state.attention ?  已关注 :  未关注 } }
{this.state.replies.map((reply)=>( ))} {this.props.token && }
) } } class FlowItemRow extends PureComponent { constructor(props) { super(props); this.state={ replies: [], reply_status: 'done', info: props.info, attention: false, }; this.color_picker=new ColorPicker(); this.show_pid=load_single_meta(this.props.show_sidebar,this.props.token); } componentDidMount() { if(parseInt(this.state.info.reply,10)) { this.load_replies(); } } load_replies(callback) { console.log('fetching reply',this.state.info.pid); this.setState({ reply_status: 'loading', }); API.load_replies(this.state.info.pid,this.props.token,this.color_picker) .then((json)=>{ this.setState((prev,props)=>({ replies: json.data, info: Object.assign({}, prev.info, { reply: ''+json.data.length, }), attention: !!json.attention, reply_status: 'done', }),callback); }) .catch((e)=>{ console.trace(e); this.setState({ replies: [], reply_status: 'failed', },callback); }); } show_sidebar() { this.props.show_sidebar( '帖子详情', ); } render() { return (
{ if(!CLICKABLE_TAGS[event.target.tagName.toLowerCase()]) this.show_sidebar(); }}>
{this.state.reply_status==='loading' &&
加载中
} {this.state.reply_status==='failed' && } {this.state.replies.slice(0,PREVIEW_REPLY_COUNT).map((reply)=>( ))} {this.state.replies.length>PREVIEW_REPLY_COUNT &&
还有 {this.state.replies.length-PREVIEW_REPLY_COUNT} 条
}
); } } function FlowChunk(props) { return ( {({value: token})=>(
{props.list.map((info)=>( ))}
)}
); } export class Flow extends PureComponent { constructor(props) { super(props); this.state={ mode: props.mode, search_param: props.search_text, loaded_pages: 0, chunks: [], loading_status: 'done', }; this.on_scroll_bound=this.on_scroll.bind(this); window.LATEST_POST_ID=parseInt(localStorage['_LATEST_POST_ID'],10)||0; } load_page(page) { const failed=(err)=>{ console.trace(err); this.setState((prev,props)=>({ loaded_pages: prev.loaded_pages-1, loading_status: 'failed', })); }; if(page>this.state.loaded_pages+1) throw new Error('bad page'); if(page===this.state.loaded_pages+1) { console.log('fetching page',page); if(this.state.mode==='list') { API.get_list(page,this.props.token) .then((json)=>{ json.data.forEach((x)=>{ if(parseInt(x.pid,10)>(parseInt(localStorage['_LATEST_POST_ID'],10)||0)) localStorage['_LATEST_POST_ID']=x.pid; }); this.setState((prev,props)=>({ chunks: prev.chunks.concat([{ title: 'Page '+page, data: json.data.filter((x)=>( prev.chunks.length===0 || !(prev.chunks[prev.chunks.length-1].data.some((p)=>p.pid===x.pid)) )), }]), loading_status: 'done', })); }) .catch(failed); } else if(this.state.mode==='search') { API.get_search(SEARCH_PAGESIZE*page,this.state.search_param,this.props.token) .then((json)=>{ const finished=json.data.length{ this.setState({ chunks: [{ title: 'PID = '+pid, data: [json.data], }], mode: 'single_finished', loading_status: 'done', }); }) .catch(failed); } else if(this.state.mode==='attention') { API.get_attention(this.props.token) .then((json)=>{ this.setState({ chunks: [{ title: 'Attention List', data: json.data, }], mode: 'attention_finished', loading_status: 'done', }); }) .catch(failed); } else { console.log('nothing to load'); return; } this.setState((prev,props)=>({ loaded_pages: prev.loaded_pages+1, loading_status: 'loading', })); } } on_scroll(event) { if(event.target===document) { const avail=document.body.scrollHeight-window.scrollY-window.innerHeight; if(avail {this.state.chunks.map((chunk)=>( ))} {this.state.loading_status==='failed' && }  Loading... : '© xmcp' } />
); } }