From 47be6d49f64addfeaa58c31964b87baccf1ef821 Mon Sep 17 00:00:00 2001 From: xmcp Date: Mon, 25 Mar 2019 00:49:31 +0800 Subject: [PATCH] update - add image quality indicator - add error tip - minor enhancement --- src/Flows.js | 30 +++++++++++++--- src/UserAction.css | 5 +++ src/UserAction.js | 84 +++++++++++++++++++++++++++++++++++--------- src/flows_api.js | 10 +++--- src/text_splitter.js | 2 +- 5 files changed, 104 insertions(+), 27 deletions(-) diff --git a/src/Flows.js b/src/Flows.js index ce3deae..2c5efea 100644 --- a/src/Flows.js +++ b/src/Flows.js @@ -48,7 +48,8 @@ function load_single_meta(show_sidebar,token) { show_sidebar( '帖子详情',
- load_single_meta(show_sidebar,token)}>重新加载 +

load_single_meta(show_sidebar,token)()}>重新加载

+

{''+e}

); }) @@ -139,6 +140,7 @@ class FlowSidebar extends PureComponent { info: props.info, replies: props.replies, loading_status: 'done', + error_msg: null, }; this.color_picker=props.color_picker; this.show_pid=load_single_meta(this.props.show_sidebar,this.props.token); @@ -172,6 +174,7 @@ class FlowSidebar extends PureComponent { load_replies(update_count=true) { this.setState({ loading_status: 'loading', + error_msg: null, }); API.load_replies(this.state.info.pid,this.props.token,this.color_picker) .then((json)=>{ @@ -182,6 +185,7 @@ class FlowSidebar extends PureComponent { }) : prev.info, attention: !!json.attention, loading_status: 'done', + error_msg: null, }), ()=>{ this.syncState({ replies: this.state.replies, @@ -195,6 +199,7 @@ class FlowSidebar extends PureComponent { this.setState({ replies: [], loading_status: 'done', + error_msg: ''+e, }); }); } @@ -240,8 +245,13 @@ class FlowSidebar extends PureComponent { show_reply_bar(name,event) { if(this.reply_ref.current && event.target.tagName.toLowerCase()!=='a') { let text=this.reply_ref.current.get(); - if(/^\s*(Re (洞主|\b[A-Z][a-z]+){0,2}:)?\s*$/.test(text)) // text is nearly empty so we can replace it - this.reply_ref.current.set('Re '+name+': '); + if(/^\s*(Re (洞主|\b[A-Z][a-z]+){0,2}:)?\s*$/.test(text)) {// text is nearly empty so we can replace it + let should_text='Re '+name+': '; + if(should_text===this.reply_ref.current.get()) + this.reply_ref.current.set(''); + else + this.reply_ref.current.set(should_text); + } } } @@ -278,7 +288,13 @@ class FlowSidebar extends PureComponent { set_variant={(variant)=>{this.set_variant(null,variant);}} /> - {(this.props.deletion_detect && parseInt(this.state.info.reply)>this.state.replies.length) && + {!!this.state.error_msg && +
+

回复加载失败

+

{this.state.error_msg}

+
+ } + {(this.props.deletion_detect && parseInt(this.state.info.reply)>this.state.replies.length) && !!this.state.replies.length &&
{parseInt(this.state.info.reply)-this.state.replies.length} 条回复被删除
@@ -422,6 +438,7 @@ export class Flow extends PureComponent { data: [], }, loading_status: 'done', + error_msg: null, }; this.on_scroll_bound=this.on_scroll.bind(this); window.LATEST_POST_ID=parseInt(localStorage['_LATEST_POST_ID'],10)||0; @@ -433,6 +450,7 @@ export class Flow extends PureComponent { this.setState((prev,props)=>({ loaded_pages: prev.loaded_pages-1, loading_status: 'failed', + error_msg: ''+err, })); }; @@ -508,6 +526,7 @@ export class Flow extends PureComponent { this.setState((prev,props)=>({ loaded_pages: prev.loaded_pages+1, loading_status: 'loading', + error_msg: null, })); } } @@ -540,7 +559,8 @@ export class Flow extends PureComponent { /> {this.state.loading_status==='failed' &&
- {this.load_page(this.state.loaded_pages+1)}}>重新加载 +

{this.load_page(this.state.loaded_pages+1)}}>重新加载

+

{this.state.error_msg}

} { let width=image.width; let height=image.height; + let compressed=false; if(width>MAX_IMG_PX) { height=height*MAX_IMG_PX/width; width=MAX_IMG_PX; + compressed=true; } if(height>MAX_IMG_PX) { width=width*MAX_IMG_PX/height; height=MAX_IMG_PX; + compressed=true; } let canvas=document.createElement('canvas'); @@ -354,23 +359,58 @@ export class PostForm extends Component { canvas.height=height; ctx.drawImage(image,0,0,width,height); - for(let quality=.9;quality>0;quality-=0.1) { - const url=canvas.toDataURL('image/jpeg',quality); - console.log('quality',quality,'size',url.length); - if(url.length<=MAX_IMG_FILESIZE) { - console.log('chosen img quality',quality); - return return_url(url); - } + let quality_l=.1,quality_r=.9,quality,new_url; + while(quality_r-quality_l>=.06) { + quality=(quality_r+quality_l)/2; + new_url=canvas.toDataURL('image/jpeg',quality); + console.log(quality_l,quality_r,'trying quality',quality,'size',new_url.length); + if(new_url.length<=MAX_IMG_FILESIZE) + quality_l=quality; + else + quality_r=quality; + } + if(quality_l>=.101) { + console.log('chosen img quality',quality); + resolve({ + img: return_url(new_url), + quality: quality, + width: Math.round(width), + height: Math.round(height), + compressed: compressed, + }); + } else { + reject('图片过大,无法上传'); } - // else - alert('图片过大,无法上传'); - reject('img too large'); }); }); reader.readAsDataURL(file); }); } + on_img_change() { + if(this.img_ref.current && this.img_ref.current.files.length) + this.setState({ + img_tip: '(正在处理图片……)' + },()=>{ + this.proc_img(this.img_ref.current.files[0]) + .then((d)=>{ + this.setState({ + img_tip: `(${d.compressed?'压缩到':'尺寸'} ${d.width}*${d.height} / `+ + `质量 ${Math.floor(d.quality*100)}% / ${Math.floor(d.img.length/1000)}KB)`, + }); + }) + .catch((e)=>{ + this.setState({ + img_tip: `图片无效:${e}`, + }); + }); + }); + else + this.setState({ + img_tip: null, + }); + } + on_submit(event) { if(event) event.preventDefault(); if(this.state.loading_status==='loading') @@ -380,12 +420,15 @@ export class PostForm extends Component { loading_status: 'processing', }); this.proc_img(this.img_ref.current.files[0]) - .then((img)=>{ + .then((d)=>{ this.setState({ loading_status: 'loading', }); - this.do_post(this.state.text,img); + this.do_post(this.state.text,d.img); }) + .catch((e)=>{ + alert(e); + }); } else { this.setState({ loading_status: 'loading', @@ -400,8 +443,9 @@ export class PostForm extends Component {
{this.state.loading_status!=='done' ? }
+ {!!this.state.img_tip && +

+ {this.img_ref.current.value=""; this.on_img_change();}}>删除图片 + {this.state.img_tip} +

+ } ) diff --git a/src/flows_api.js b/src/flows_api.js index 3646527..b1f801c 100644 --- a/src/flows_api.js +++ b/src/flows_api.js @@ -17,8 +17,10 @@ export const API={ ) .then((res)=>res.json()) .then((json)=>{ - if(json.code!==0) - throw new Error(json); + if(json.code!==0) { + if(json.msg) throw new Error(json.msg); + else throw new Error(json); + } json.data=json.data .sort((a,b)=>{ @@ -121,8 +123,8 @@ export const API={ .then((res)=>res.json()) .then((json)=>{ if(json.code!==0) { - if(json.msg) alert(json.msg); - throw new Error(json); + if(json.msg) throw new Error(json.msg); + else throw new Error(json); } return json; }); diff --git a/src/text_splitter.js b/src/text_splitter.js index 4eb694d..93e817a 100644 --- a/src/text_splitter.js +++ b/src/text_splitter.js @@ -1,6 +1,6 @@ export const PID_RE=/(^|[^\d])([1-9]\d{4,5})(?!\d|\u20e3)/g; export const NICKNAME_RE=/(^|[^A-Za-z])((?:(?:Angry|Baby|Crazy|Diligent|Excited|Fat|Greedy|Hungry|Interesting|Japanese|Kind|Little|Magic|Naïve|Old|Powerful|Quiet|Rich|Superman|THU|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=/(?:^|\b)((?:https?:\/\/)?(?:[\w-]+\.)+[a-zA-Z]{2,3}(?::\d{1,5})?(?:\/[\w~!@#$%^&*()-_=+[\];,./?]*)?)(?:$|\b)/gi; +export const URL_RE=/(?:^|\b)((?:https?:\/\/)?(?:[\w-]+\.)+[a-zA-Z]{2,3}(?::\d{1,5})?(?:\/[\w~!@#$%^&*()-_=+[\];,./?]*)?)/gi; export function split_text(txt,rules) { // rules: [['name',/regex/],...]