From 94251b394b2d8edd29a7c36cc54c693b268b0f87 Mon Sep 17 00:00:00 2001 From: xmcp Date: Sat, 25 Aug 2018 23:50:38 +0800 Subject: [PATCH] add post form --- public/index.html | 2 +- public/static/fonts_1/icomoon.svg | 18 -- public/static/fonts_1/icomoon.ttf | Bin 2280 -> 0 bytes public/static/fonts_1/icomoon.woff | Bin 2356 -> 0 bytes .../static/{fonts_1 => fonts_2}/icomoon.css | 24 ++- public/static/fonts_2/icomoon.svg | 21 ++ public/static/fonts_2/icomoon.ttf | Bin 0 -> 2972 bytes public/static/fonts_2/icomoon.woff | Bin 0 -> 3048 bytes src/Flows.js | 19 +- src/Sidebar.js | 1 - src/Title.js | 41 +++- src/UserAction.css | 26 ++- src/UserAction.js | 204 ++++++++++++++++-- 13 files changed, 293 insertions(+), 63 deletions(-) delete mode 100644 public/static/fonts_1/icomoon.svg delete mode 100644 public/static/fonts_1/icomoon.ttf delete mode 100644 public/static/fonts_1/icomoon.woff rename public/static/{fonts_1 => fonts_2}/icomoon.css (66%) create mode 100644 public/static/fonts_2/icomoon.svg create mode 100644 public/static/fonts_2/icomoon.ttf create mode 100644 public/static/fonts_2/icomoon.woff diff --git a/public/index.html b/public/index.html index bccb22a..c9f0ae9 100644 --- a/public/index.html +++ b/public/index.html @@ -6,7 +6,7 @@ - + diff --git a/public/static/fonts_1/icomoon.svg b/public/static/fonts_1/icomoon.svg deleted file mode 100644 index 14934e9..0000000 --- a/public/static/fonts_1/icomoon.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - -Generated by IcoMoon - - - - - - - - - - - - - - \ No newline at end of file diff --git a/public/static/fonts_1/icomoon.ttf b/public/static/fonts_1/icomoon.ttf deleted file mode 100644 index af51e902d892d0396aeede954b3b9d6e66800778..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2280 zcma)7U2GIp6h3F}?oPLb)`jk@-FCP8KTBKIZFi@OP;tbh0xb|BDGvtRrCqj^c6aHI zq2j|NCXEq@JeiP~riltZ7(-0($;64q$b&v_6JQbgPpu((Y?hG)CHF_sA_dEaR z-h0kmKmce14H#sP9D8o4W1HAZoGFsmv~) ze&_NxXNkT6;JP(kE=_Hlxg-L3&Xat2ni%5O><6Mr4vFcx#q%kkSm61I=_sJ?l2dX9<&=^y z?8U;c05c~}UQE-tc=E(dXS#F8&YdT+*=+6*;y^q;*uIrZm==wk8y}yT7#}|ui85hF zuq)(t3*Euvd9g$6NhFSDGJ}@TTo`4`^U>)HcK~=%76a&xDioL}!83@*cv}8WDd4v< z^hcR){8m)gu=r3%b?EIeWsI?eEbreh%L&HDlviIFt%O6UW6{y^5>`9`>E-@`tTPuGauOrl9T+q9dqVj6v&F4j*9Q74^QK||RRqdgs3Mx|{Xs8;bs6EhBvs%sly+h}H zovb>^F4=}#ktN+MiDE&15qnV#xWHIlT{Tt_Mv$Hn1OtBUySY)XZ`|w?ayfj-_$s$y ztX;c?#SPh7_Br}uyQeA*HHE*_sfqpIEyWpbDE$8kssp%_;R zN>nLWXCT_A-pT7VAo0mQg~G7&FzlL*D}ztfwzHH`*EEFgq^{|PuJ@(WW3gB$ECqU7 zX!Hi8a3~fVOQ-w(UE*v72S(5YHQB9eDm`oe(^pfJqSamwpEDM=&(iE&9ip(0_R4C{ zN6nG5+B9daJ0M1V;`T?4%@;2hs9u`3PGN7x`}>NDvdfB5v|2Ya(0?Qr5514Yl~gmw zSX*f_V8K*xZ-3hsD`~5%TfK>3SHv_nt~GJU*s0BH$E+Xp{ruYN9V352n|TEQ-2V8( zZ=cNe-+_MkW-aqUHvFG$77z{k5~pcwu_PAHG&5<(t2r>|b4{~D!f+Zsg$>~V@jolyt-HhDUL;RyQZiPI2bY`+PSF2Uw3`{}|=IE_K zb)r1KaHdv`3}&)0L47z63#32-@-qk-$Zl%2Df4K#vNT(or=Vp@bO~mm1oN9}j@GJ+ zkxIE*o-Zwyry{48BL^mHhbXrUjPlrv6um-jsyw3-EYdthyi>4D-vfLBhpYuqj@B*h IJe8;L-=;>Qng9R* diff --git a/public/static/fonts_1/icomoon.woff b/public/static/fonts_1/icomoon.woff deleted file mode 100644 index f43f6ec5f77b8741c8686b53224eb0fee2e74b68..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2356 zcma)7U2GIp6h3EWcc`pam3?@?gMS+GR^=cT0bi ziVu^RG)5ruMAF1GO;mU>hM3^16Mv!)`eY*E!D!^g;;TMT%dF?#8DJJ_^iIy)?|$dp zbI-l^oS8R|4h;bUHE#}@Sl{rwHDYd#A%>qR z^{j>Yo3BEslXMJs(wkXzf(s~acm}o+(?DE!?cCbJ+Lg5**KV)fx#zu?u05#L$bvj= zs=?Y_d0Dj%%^5eMwldBmn5OwIK&GrXE z7?Ay~QZq`PSTw14IFi(TsOFMNQc0tdRCD=#m>&>e^5m&YDQcHaot$htrUA z$sR`Rjm7$!w{nfBN5bbvMn*?RM$U&LqOh~QE$DU&9qlJ_Qj63Xj~`2?`z$5f14YZ@ zG3X9=((R%m1<)N)X<;4&k02K1VfkC-fZvMH9}x}n*Mhc+g$D*|{qGE`!=e~hlmiD8 zB`%7?>Z>mgl|w-^uwdI2=0Zu28d^Fum{X6)fq;BO%?%z}3aOre{8CSE#u4o%nf(Y<`>y@bM^XlEUcR!ym9|#{O;ZO&HF4a%DYGY zo!+1J`J^NIoIJXFk+S*#P{m``AH#k*h*C_=s}VJC-GOA^dMnS@fXqAl7V-nm%dm4c zruIFN+s;%*L)Q^H5{7P=hS8l$4M(HFkR0f0pw<BXNjn}EHs8FGr+le9 zI#qlt*3(^3)!o(_1*>$^y*)>xvEVfgs9QVg+qgb)z@l-WFz) z&FggxO?F!I++q2HzMo!uy=Cw(XrhFmcKhQGzj@r-UkCO-qFm;U=J0PeOCW0WCZ?`! zu{0LPrm?X@bO+`TwBD`Q@H~qc+HuexdY~x1yKfVX_r*V0SX(o+@1;S+;i-e!Iv5WBAHg8wr3W2N%KRB@ITEm5EgFa<@J-PCfZTA2@*OO?`WalSMjKD`(|I95GOv87>%uRTwz im&r|qM^uD)>c@#Y4U6 + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/static/fonts_2/icomoon.ttf b/public/static/fonts_2/icomoon.ttf new file mode 100644 index 0000000000000000000000000000000000000000..132accf5e0ec4a120d75d00ded663a2e9bb33fb0 GIT binary patch literal 2972 zcmai0U2Gf25uUw0@^t(WNs&C7ltl4JiIgaZ6#tI0E!!svaUz>ST3fK6sEUzk$*LtP zlHA%(fbz*GY6K1PP&7dy_#v>-Jfv>Z)O{$>LtmPQqCk-rfq|lF>!N^E^yeWh5LY^O zZts{-j*#y0Zf9m^cE6dOSuPL&a6%I(jJkxKS0UP@LgD3t*zhxp#EC`(ue$8 zOSR2)?7hfq*mo^myLshL|M>2&kbfUQm|L#bF88d~{sJHx`pPm2gkR9#AU}uv;PUF$ zjXVLg6>lIvajmgf6W@0J9{C?5A6u>6Scd?tAdhQ8Y^}Chf8(t9U*tc=HEyprHn$Kb zHs>qGI8gdK@*3CxxHmXN0pB)z@;4|D(a`H?1YsX+D!}dos6|j4)O+ z-aZ^Nd&;!>fQN6QJc`kv(2cU#4(xn&=jP6^^Aiw_0qbFB&JU z$01&NQ+idpC6%PSl#_@A!H*PLGBuVMd`SmOQT)#mpvo7)<*DTTGY<6>c`gw26i@)cmr#G`%`7oKTo>5OP zr;>rofn;j=w0h<#mc$31JE9(WZopd@h~>Q&GjQWv-44F{7-Qvbg!U zAoxrW(BY%>dr#KapS+jm3I#H$|Ge--zkBZ}ZH15jk)qJ zEFyDYe?pQ{njk5AGM6E_q>_u0oW#zk_HnC}Go(Bwh0MQ#Q#foFqFB=A*=$gDtnYIB zpkx6^w2$XVq&lfq{9dv$)ssr3lEd+;#P>Ky)9I-|urJKJg41WCld?P+Jv$wA@!`H; zU^+cA+8rcbe`QjwMk1!e^j++$^DA?+v(0Qa%=b7%B^H`HI&egw`4fWUNZes_xyQ5F zne?;0;!KI=xu&iYkou6)ahiMr( zAmD(Bk3)LFqAAjfMe|5sw`d#Q7K0XTNBKF6c0dHa1$bZKMU-^oh)HuuFIlv4Q#xtU zJkqaNv<)PPS+pJH=PlX+MR@D#Vq>+@Sc9vWqzzcbw*hMx>l>R_8*8y#W(+Pu9X4PS z6>tFO$w3Cj4z)T|c)q@L{aS4U7p)`E>u?QfuyLs7na0{yY^lCh->7ZXFUMZI8Jk&b r%p$f7oMCHk;p$5`%^E{ggDvbYqwGbviQgIKz^v&2Vl?g*U)cT!i+m$S literal 0 HcmV?d00001 diff --git a/public/static/fonts_2/icomoon.woff b/public/static/fonts_2/icomoon.woff new file mode 100644 index 0000000000000000000000000000000000000000..25b7f5b25d30629f3e497166c988bdfd515b89a5 GIT binary patch literal 3048 zcmai0U2Gf25uUw0^29%p6v?AWNfeKiNQrVtQ6!JDE!!svQ6gJ}8{4p-sEUzk$*Ltf zlHAx%f%3^HY6K1PP&7dx=pnGtJfu#7)O{;a6lflT06`iA28yPwi=tA|pNFJF`2p+UL(qPXhsLjz5Eg_pcc|!~5HrbD2>9(t*->M(!@@Ckrc; zYbaYn{&hz8KC1qDv9gXb!HGQ6W#n1Bdh;^M`~cE6=RBADVR^N( zQbn1DKHg^Z$|>7_uGQ8zFy8mL4zs6-DE*kc1Qzu172$p4e_-_FFOVZPGtHc=10cAPXH1x5K)`9=AbT#!fQtW0DGd>WWDSK|}>j}HNYE4aB= zhKc}CJi*7!W9Bo6KTqHbkIxIE>6_FhYWIz>l6tR_2qHBdKtL6!M8= zf;p8a~6(bNSARBQ}wzasa=)Qu1Mo2I5^O=-15gz7K!^b^df$ZKU zg4c6=IF)Zn=&hDy?^ka3k)f2TriPBV-9n?C`==_)YH!x3U-o5t8CFY9@^5E}G?Ywc zeQN4yPt=2dPfty)XEMq`GF_Y2PA(-A{!9Kua_OWt{Uw&f`kp$Z9eS$Ilk1C)dQ7J8 z#_8GT+1_F1@w03|5^}h6F@AV#lW^bUW2BH{zhVS4%G^`FZ@w5Fsft+^@LPq(1Fsayc@g|2+3t-@1F3 z%s{<9Nz5AXDlsc2mYh?( zY}ZHCf>#+;G4T@gclwsk)o}UrEtk*dBJ-Rf^T-Gq?_38dFh9l5&(;kgD8MtgVqV4B zWtPLZZld5*@Oa~eoHs{XC(qM<|7p`$dlBdMRXl0*_@n+F{%JHp(;8a6y~x|KQL^o| z&9U&3Y2V}5zk&8m5E{k}(Qa(u-TAMWo7Y5pE-NsJu^J^EHv`KVm2P?;loYSzYh7B# zT~Nf_GOE56KD`wmPR$nzW5(j<+Udi?XJYZ*ACmdo3B#L~MBlo-&wz##eSO0YrxA@2 zzTMUz4n>)ZH#?z~!(k&}`VRKxx#jbvQazIi ziCuP^8V#O5+;>Q#qsJusp_tv`bd6;)GpQ%LZ8HU$?XcN8va~Q`>wYqIDw7^_x-5>7 zcz)Jp?-E0qk?)pD=a=Wo_#ecqL$*h0`M1??y2t+o4orA#pWN&G*%y8D0k1apX2N@c zH?-mJ3J?+TGU2^3$iHr5CPTu^m?o1UX=YzH`res.json()) .then((json)=>{ - if(json.code!==0 && (!json.msg || json.msg!=='已经关注过辣')) - throw new Error(json); + if(json.code!==0) { + if(json.msg && json.msg==='已经关注过辣') {} + else { + if(json.msg) alert(json.msg); + throw new Error(json); + } + } this.setState({ attention: next_attention, @@ -164,8 +169,8 @@ class FlowItemRow extends PureComponent { this.toggle_attention(this.show_sidebar.bind(this)); }}> {this.state.attention ? - 已关注 : - 未关注 +  已关注 : +  未关注 } @@ -382,7 +387,11 @@ export class Flow extends PureComponent { {this.load_page(this.state.loaded_pages+1)}}>重新加载 } - +  Loading... : + '© xmcp' + } /> ); } diff --git a/src/Sidebar.js b/src/Sidebar.js index f436df5..f573aa6 100644 --- a/src/Sidebar.js +++ b/src/Sidebar.js @@ -10,7 +10,6 @@ export function Sidebar(props) { ×  {props.title}

-
{props.content} diff --git a/src/Title.js b/src/Title.js index 671de7f..c69027c 100644 --- a/src/Title.js +++ b/src/Title.js @@ -1,5 +1,5 @@ import React, {Component, PureComponent} from 'react'; -import {LoginForm} from './UserAction'; +import {LoginForm, PostForm} from './UserAction'; import {TokenCtx} from './UserAction'; import './Title.css'; @@ -112,15 +112,30 @@ class ControlBar extends PureComponent { - {this.props.show_sidebar('登录',)}}> - - - {this.props.show_sidebar( - '关于 P大树洞(非官方) 网页版', - HELP_TEXT - )}}> - + { + this.props.show_sidebar( + 'P大树洞(非官方)网页版', +
+ + {HELP_TEXT} +
+ ) + }}> +
+ {!!token && + { + this.props.show_sidebar( + '发表树洞', + { + this.props.show_sidebar('',null); + this.do_refresh(); + }} /> + ) + }}> + + + } )} ) @@ -131,7 +146,13 @@ export function Title(props) { return (
-

P大树洞

+

+ P大树洞 +   + + + +

diff --git a/src/UserAction.css b/src/UserAction.css index b594a44..0a2300a 100644 --- a/src/UserAction.css +++ b/src/UserAction.css @@ -2,11 +2,9 @@ margin: 1em 0; text-align: center; } - .login-form button { min-width: 100px; } - .reply-form { display: flex; } @@ -17,5 +15,27 @@ height: 5em; } .reply-form button { - flex: 0 0 50px; + flex: 0 0 3em; +} + +.post-form-bar { + line-height: 2em; + display: flex; +} +.post-form-bar label { + flex: 1; +} +@media screen and (max-width: 600px) { + .post-form-bar input[type=file] { + width: 150px; + } +} +.post-form-bar button { + flex: 0 0 8em; +} +.post-form textarea { + resize: vertical; + width: 100%; + min-height: 5em; + height: 20em; } \ No newline at end of file diff --git a/src/UserAction.js b/src/UserAction.js index 709555f..f2addb6 100644 --- a/src/UserAction.js +++ b/src/UserAction.js @@ -5,6 +5,8 @@ import './UserAction.css'; import {API_BASE} from './Common'; const LOGIN_BASE=window.location.protocol==='https:' ? '/login_proxy' : 'http://www.pkuhelper.com/services/login'; +const MAX_IMG_PX=1000; +const MAX_IMG_FILESIZE=100000; export const TokenCtx=React.createContext({ value: null, @@ -42,8 +44,10 @@ export class LoginForm extends Component { }) .then((res)=>res.json()) .then((json)=>{ - if(json.code!==0) + if(json.code!==0) { + if(json.msg) alert(json.msg); throw new Error(json); + } set_token(json.token); alert(`成功以 ${json.name} 的身份登录`); @@ -63,8 +67,8 @@ export class LoginForm extends Component { render() { return ( {(token)=> -
-
this.do_login(e,token.set_value)} className="box"> +
+ this.do_login(e,token.set_value)}>

{token.value ? 您已登录。Token: {token.value||'(null)'} : '登录后可以使用关注、回复等功能' @@ -83,19 +87,23 @@ export class LoginForm extends Component {

{this.state.loading_status==='loading' ? - : - + : + }

- -
  • 我们不会记录您的密码和个人信息
  • 请勿泄露 Token,它代表您的登录状态,与您的账户唯一对应且泄露后无法重置
  • 如果您不愿输入密码,可以直接修改 localStorage['TOKEN']
-
+
} ) @@ -121,7 +129,6 @@ export class ReplyForm extends Component { on_submit(event) { event.preventDefault(); - if(this.state.loading_status==='loading') return; this.setState({ @@ -142,8 +149,10 @@ export class ReplyForm extends Component { }) .then((res)=>res.json()) .then((json)=>{ - if(json.code!==0) + if(json.code!==0) { + if(json.msg) alert(json.msg); throw new Error(json); + } this.setState({ loading_status: 'done', @@ -163,16 +172,175 @@ export class ReplyForm extends Component { render() { return ( -
-
- - {this.state.loading_status==='loading' ? - : - + + + {this.state.loading_status==='loading' ? + : + + } + + ) + } +} + +export class PostForm extends Component { + constructor(props) { + super(props); + this.state={ + text: '', + loading_status: 'done', + }; + this.img_ref=React.createRef(); + this.area_ref=React.createRef(); + this.on_change_bound=this.on_change.bind(this); + } + + on_change(value) { + this.setState({ + text: value, + }); + } + + do_post(text,img) { + let data=new URLSearchParams(); + data.append('action','dopost'); + data.append('text',this.state.text); + data.append('type',img ? 'image' : 'text'); + data.append('token',this.props.token); + if(img) + data.append('data',img); + + fetch(API_BASE+'/api.php', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: data, + }) + .then((res)=>res.json()) + .then((json)=>{ + if(json.code!==0) { + if(json.msg) alert(json.msg); + throw new Error(json); + } + + this.setState({ + loading_status: 'done', + text: '', + }); + this.area_ref.current.clear(); + this.props.on_complete(); + }) + .catch((e)=>{ + console.trace(e); + alert('发表失败'); + this.setState({ + loading_status: 'done', + }); + }); + } + + proc_img(file) { // http://pkuhole.chenpong.com/ + return new Promise((resolve,reject)=>{ + function return_url(url) { + const idx=url.indexOf(';base64,'); + if(idx===-1) + throw new Error('img not base64 encoded'); + + resolve(url.substr(idx+8)); + } + + let reader=new FileReader(); + reader.onload=((event)=>{ // check size + const url=event.target.result; + const image = new Image(); + image.src=url; + + image.onload=(()=>{ + let width=image.width; + let height=image.height; + if(width>MAX_IMG_PX) { + height=height*MAX_IMG_PX/width; + width=MAX_IMG_PX; + } + if(height>MAX_IMG_PX) { + width=width*MAX_IMG_PX/height; + height=MAX_IMG_PX; } - -
+ let canvas=document.createElement('canvas'); + let ctx=canvas.getContext('2d'); + canvas.width=width; + 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); + } + } + // else + alert('图片过大,无法上传'); + reject('img too large'); + }); + }); + reader.readAsDataURL(file); + }); + } + + on_submit(event) { + event.preventDefault(); + if(this.state.loading_status==='loading') + return; + if(this.img_ref.current.files.length) { + this.setState({ + loading_status: 'processing', + }); + this.proc_img(this.img_ref.current.files[0]) + .then((img)=>{ + this.setState({ + loading_status: 'loading', + }); + this.do_post(this.state.text,img); + }) + } else { + this.setState({ + loading_status: 'loading', + }); + this.do_post(this.state.text,null); + } + } + + render() { + return ( +
+
+ + {this.state.loading_status!=='done' ? + : + + } +
+
+ + ) } } \ No newline at end of file