diff --git a/img/logo-unread.svg b/img/logo-unread.svg new file mode 100644 index 00000000..3a01524e --- /dev/null +++ b/img/logo-unread.svg @@ -0,0 +1,9 @@ + + + + M + + + diff --git a/img/logo.svg b/img/logo.svg index 69d84b99..7b453084 100644 --- a/img/logo.svg +++ b/img/logo.svg @@ -1 +1,7 @@ -t \ No newline at end of file + + + + M + diff --git a/img/logo192.png b/img/logo192.png index 9664ce8a..137183cd 100644 Binary files a/img/logo192.png and b/img/logo192.png differ diff --git a/img/logo32x32.png b/img/logo32x32.png index 64bc6d0b..a11b1cd1 100644 Binary files a/img/logo32x32.png and b/img/logo32x32.png differ diff --git a/img/logo32x32a.png b/img/logo32x32a.png index cc8d269e..9f8c7dad 100644 Binary files a/img/logo32x32a.png and b/img/logo32x32a.png differ diff --git a/img/logo96.png b/img/logo96.png index 8a584043..9d625d61 100644 Binary files a/img/logo96.png and b/img/logo96.png differ diff --git a/img/og-logo.jpeg b/img/og-logo.jpeg index d2704f78..621cb3dc 100644 Binary files a/img/og-logo.jpeg and b/img/og-logo.jpeg differ diff --git a/img/og-logo.svg b/img/og-logo.svg new file mode 100644 index 00000000..d57ee764 --- /dev/null +++ b/img/og-logo.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + M + + MeetingIM + 即时通讯 + diff --git a/umd/280.prod.js b/umd/280.prod.js new file mode 100644 index 00000000..c7ec0a78 --- /dev/null +++ b/umd/280.prod.js @@ -0,0 +1,2 @@ +"use strict";(self.webpackChunktinode_webapp=self.webpackChunktinode_webapp||[]).push([[280],{9280:function(e,t,s){s.r(t),s.d(t,{default:function(){return ee}});var i=s(1594),n=s.n(i),a=s(8181),o=s(4532),r=s(4752),l=s(8353),h=s(7256),d=s(7849),c=s(4848);const p={image:["image","#3ba55c"],video:["videocam","#3b82c4"],audio:["audiotrack","#8b5cf6"],document:["description","#e05d44"],file:["insert_drive_file","#8a8f98"]};class u extends n().Component{constructor(e){super(e),this.state={downloader:null,progress:0},this.downloadFile=this.downloadFile.bind(this),this.handleCancel=this.handleCancel.bind(this)}downloadFile(e,t,s){if(!e)return void this.props.onError("Invalid download URL '"+e+"'");const i=(0,l.mO)(this.props.tinode);this.setState({downloader:i}),i.download(e,t,s,e=>this.setState({progress:e/this.props.size}),e=>this.props.onError(e,"err")).then(e=>this.setState({downloader:null,progress:0})).catch(e=>{e&&this.props.onError("Error downloading file: "+e.message,"err"),this.setState({downloader:null,progress:0})})}handleCancel(){this.props.uploading?this.props.onCancelUpload():this.state.downloader&&this.state.downloader.cancel()}render(){let e=this.props.filename||"file_attachment";e.length>36&&(e=e.substr(0,16)+"..."+e.substr(-16));let t,s,i=this.props.size>0?(0,c.jsxs)("span",{className:"small gray",children:["(",(0,h.lX)(this.props.size),")"]}):null;this.props.uploading||this.state.downloader||!(0,d.YO)(this.props.downloadUrl)?(t=(0,d.Jf)(this.props.downloadUrl),s=null):(t="#",s=e=>{e.preventDefault(),this.downloadFile(this.props.downloadUrl,this.props.filename,this.props.mimetype)});const n=(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)("i",{className:"material-icons",children:"file_download"})," ",(0,c.jsx)(a.FormattedMessage,{id:"save_attachment",defaultMessage:"save",description:"Call to save an attachment"})]}),[o,l]=p[function(e){const t=(e||"").toLowerCase();return t.startsWith("image/")?"image":t.startsWith("video/")?"video":t.startsWith("audio/")?"audio":"application/pdf"===t||"text/plain"===t||t.includes("msword")||t.includes("wordprocessingml")||t.includes("spreadsheetml")||t.includes("presentationml")||"application/vnd.ms-excel"===t||"application/vnd.ms-powerpoint"===t?"document":"file"}(this.props.mimetype)];return(0,c.jsxs)("div",{className:"attachment",children:[(0,c.jsx)("div",{children:(0,c.jsx)("i",{className:"material-icons big",style:{color:l},children:o})}),(0,c.jsxs)("div",{className:"flex-column",children:[(0,c.jsxs)("div",{children:[e," ",i]}),this.props.uploading||this.state.downloader?(0,c.jsx)(r.A,{progress:this.props.uploading?this.props.progress:this.state.progress,onCancel:this.handleCancel}):(0,c.jsx)("div",{children:t?(0,c.jsx)("a",{href:t,download:this.props.filename,onClick:s,children:n}):(0,c.jsx)("span",{className:"light-gray",children:n})})]})]})}}const m={image:"[图片]",video:"[视频]",voice:"[语音]",file:"[文件]",link:"[链接]"};function g(e){if(!e)return"";return(e.summary||e.text||"").trim()||m[e.type]||""}class f extends n().PureComponent{constructor(e){super(e),this.state={expanded:!1},this.handleToggle=this.handleToggle.bind(this)}handleToggle(e){e.preventDefault(),e.stopPropagation(),this.setState(e=>({expanded:!e.expanded}))}render(){const e=this.props.content||{},t=Number(e.item_count)||(Array.isArray(e.items)?e.items.length:0),s=this.state.expanded?e.items||[]:e.preview||[],i=(e.comment||"").trim();return(0,c.jsxs)("div",{className:"forward-bundle",children:[(0,c.jsx)("div",{className:"forward-bundle-title",children:e.title||"聊天记录"}),(0,c.jsx)("ul",{className:"forward-bundle-lines",children:s.map((e,t)=>{const s=function(e,t){const s=(t||"").trim();if(!s)return"";const i=s.startsWith("usr")?s:"usr"+s,n=e&&e.getTopic?e.getTopic(i):null,a=n&&n.public;return a&&(a.fn||a.name)||""}(this.props.tinode,e.from);return(0,c.jsxs)("li",{children:[s?(0,c.jsxs)("b",{children:[s,":"]}):null,g(e)]},(null!=e.seq?e.seq:t)+":"+t)})}),t>s.length||this.state.expanded?(0,c.jsx)("button",{type:"button",className:"forward-bundle-more",onClick:this.handleToggle,children:this.state.expanded?"收起":`查看完整记录(共 ${t} 条)`}):(0,c.jsxs)("div",{className:"forward-bundle-count",children:["共 ",t," 条消息"]}),i?(0,c.jsx)("div",{className:"forward-bundle-comment",children:i}):null]})}}var v=s(5247);const b=(0,a.defineMessages)({message_sending:{id:"message_sending",defaultMessage:"sending...",description:"Message being sent, in place of time stamp"},message_sending_failed:{id:"message_sending_failed",defaultMessage:"failed",description:"Failed to send message, in place of time stamp"},message_edited_marker:{id:"message_edited_marker",defaultMessage:", edited",description:"Marker indicating that the message was edited"}});class S extends n().PureComponent{render(){const{formatMessage:e}=this.props.intl;let t;t=this.props.received<=o.Tinode.MESSAGE_STATUS_SENDING?e(b.message_sending):this.props.received==o.Tinode.MESSAGE_STATUS_FAILED||this.props.received==o.Tinode.MESSAGE_STATUS_FATAL?e(b.message_sending_failed):this.props.timestamp.toLocaleTimeString(this.props.intl.locale,{timeStyle:"short"});const s=(0,d.LO)(this.props.received),i=s?(0,c.jsx)("i",{className:"material-icons small "+(s.color||""),children:s.name}):null,n=this.props.edited?e(b.message_edited_marker):null;return(0,c.jsxs)("span",{className:"timestamp",children:[t,n," ",i]})}}var y=(0,a.injectIntl)(S),x=s(2067),C=s(184);const M="im-voice-played:";function w(e,t,s){try{const i=JSON.parse(localStorage.getItem(M+e+":"+t)||"[]");return Array.isArray(i)&&i.includes(s)}catch(e){return!1}}class j extends n().PureComponent{constructor(e){super(e),this.state={progress:0,voicePlayed:w(e.tinode.getCurrentUserID(),e.topic,e.seq)},e.uploader&&(e.uploader.onProgress=this.handleProgress.bind(this)),this.handleExpandImage=this.handleExpandImage.bind(this),this.handlePlayVideo=this.handlePlayVideo.bind(this),this.handleFormButtonClick=this.handleFormButtonClick.bind(this),this.handleQuoteClick=this.handleQuoteClick.bind(this),this.handleContextClick=this.handleContextClick.bind(this),this.handleCancelUpload=this.handleCancelUpload.bind(this),this.handleDraftyClick=this.handleDraftyClick.bind(this),this.handleVoicePlayed=this.handleVoicePlayed.bind(this),this.formatterContext={formatMessage:e.intl.formatMessage.bind(e.intl),viewportWidth:e.viewportWidth,authorizeURL:e.tinode.authorizeURL.bind(e.tinode),onHandleClick:this.handleDraftyClick,onVoicePlayed:this.handleVoicePlayed}}handleDraftyClick=(e,t)=>{switch(t){case"image":this.handleExpandImage(e);break;case"video":this.handlePlayVideo(e);break;case"form_button":this.handleFormButtonClick(e);break;case"quote":this.handleQuoteClick(e);break;case"contact_chat":e.preventDefault();try{const t=new URL(e.target.dataset.val)?.pathname,s=t.split("/").filter(Boolean);C.A.navigateTo(C.A.setUrlTopic("",s.pop()||""))}catch(e){console.error("Invalid URL:",e)}break;case"contact_find":e.preventDefault();let s=C.A.setUrlSidePanel(window.location.hash,"newtpk");s=C.A.addUrlParam(s,"q",e.target.dataset.val),s=C.A.addUrlParam(s,"tab","find"),C.A.navigateTo(s);break;default:console.info("Unhandled drafty action.",t,e.target.dataset)}};handleExpandImage(e){e.preventDefault(),this.props.onExpandMedia({url:e.target.src,filename:e.target.dataset.name,width:e.target.dataset.width,height:e.target.dataset.height,size:e.target.dataset.size,type:e.target.dataset.mime})}handlePlayVideo(e){e.preventDefault(),this.props.onExpandMedia({video:!0,url:e.target.dataset.src,preview:e.target.src,filename:e.target.dataset.name,width:e.target.dataset.width,height:e.target.dataset.height,duration:e.target.dataset.duration,size:e.target.dataset.size,type:e.target.dataset.mime})}handleFormButtonClick(e){e.preventDefault();const t={seq:this.props.seq,resp:{}};e.target.dataset.name&&(t.resp[e.target.dataset.name]=e.target.dataset.val?e.target.dataset.val:void 0===e.target.dataset.val?1:""+e.target.dataset.val),"url"==e.target.dataset.act&&(t.ref=(0,d.Jf)(e.target.dataset.ref)||"about:blank");const s=e.target.dataset.title||"unknown";this.props.onFormResponse(e.target.dataset.act,s,t)}handleContextClick(e){e.preventDefault(),e.stopPropagation();const t=[];if(this.props.received==o.Tinode.MESSAGE_STATUS_FAILED&&t.push("menu_item_send_retry"),this.props.received>o.Tinode.MESSAGE_STATUS_FATAL){if(this.props.userIsWriter&&(t.push("menu_item_reply"),!this.props.response)){let e=!1;o.Drafty.entities(this.props.content,(t,s,i)=>(e=["AU","EX","FM","IM","TC","VC","VD"].includes(i),e)),e||o.Drafty.styles(this.props.content,t=>(e=["QQ"].includes(t),e)),e||t.push("menu_item_edit")}this.props.userIsAdmin&&t.push(this.props.pinned?"menu_item_unpin":"menu_item_pin")}t.push("menu_item_forward"),this.props.showContextMenu({seq:this.props.seq,replace:this.props.edited?parseInt(this.props.edited.split(":")[1]):0,content:this.props.content,head:this.props.head,userFrom:this.props.userFrom,userName:this.props.userName,y:e.pageY,x:e.pageX,pickReply:this.props.pickReply,editMessage:this.props.editMessage,timestamp:this.props.timestamp},t)}handleProgress(e){this.setState({progress:e})}handleCancelUpload(){this.props.onCancelUpload(this.props.seq,this.props.uploader)}handleVoicePlayed(){this.state.voicePlayed||(function(e,t,s){try{const i=M+e+":"+t,n=JSON.parse(localStorage.getItem(i)||"[]"),a=Array.isArray(n)?n:[];a.includes(s)||localStorage.setItem(i,JSON.stringify(a.concat(s).slice(-500)))}catch(e){}}(this.props.tinode.getCurrentUserID(),this.props.topic,this.props.seq),this.setState({voicePlayed:!0}))}handleQuoteClick(e){e.preventDefault(),e.stopPropagation();const t=this.props.replyToSeq;t&&this.props.onQuoteClick(t)}renderFailReason(){return this.props.response||this.props.received!=o.Tinode.MESSAGE_STATUS_FAILED&&this.props.received!=o.Tinode.MESSAGE_STATUS_FATAL?null:"blocked_by_peer"==this.props.relationship||"blocked_by_me"==this.props.relationship?(0,c.jsx)("div",{className:"message-fail-reason",children:"消息已发送,但被对方拒收了"}):"none"==this.props.relationship?(0,c.jsxs)("div",{className:"message-fail-reason",children:["你还不是他(她)朋友。",(0,c.jsx)("a",{href:"#",onClick:this.props.onSendFriendVerification,children:"发送朋友验证"})]}):null}render(){const e=this.props.sequence+" "+(this.props.response?"left":"right"),t="single"==this.props.sequence||"last"==this.props.sequence?"bubble tip":"bubble",s=this.props.userAvatar||!0,i=!this.props.response&&(this.props.received==o.Tinode.MESSAGE_STATUS_FAILED||this.props.received==o.Tinode.MESSAGE_STATUS_FATAL),r=this.renderFailReason();let l=!1;this.props.response&&this.props.mimeType==o.Drafty.getContentType()&&o.Drafty.isValid(this.props.content)&&o.Drafty.entities(this.props.content,(e,t,s)=>("AU"===s&&(l=!0),l));const h=l&&!this.state.voicePlayed;let d="message-content";const p=this.props.isGroup&&this.props.response&&("single"==this.props.sequence||"last"==this.props.sequence);let m=this.props.content;this.props.head&&("system_notice"===this.props.head["x-im-type"]||"system_action"===this.props.head["x-im-type"])&&m&&"object"==typeof m&&"string"==typeof m.text&&(m=m.text);let g=null;this.props.head&&"forward_bundle"===this.props.head["x-im-type"]&&m&&"object"==typeof m&&(m.items||m.preview)&&(g=(0,c.jsx)(f,{content:m,tinode:this.props.tinode}));const b=[];if(this.props.mimeType==o.Drafty.getContentType()&&o.Drafty.isValid(m)){o.Drafty.attachments(m,(e,t)=>{o.Drafty.isFormResponseType(e.mime)||b.push((0,c.jsx)(u,{tinode:this.props.tinode,downloadUrl:o.Drafty.getDownloadUrl(e),filename:e.name,uploading:o.Drafty.isProcessing(e),mimetype:e.mime,size:o.Drafty.getEntitySize(e),progress:this.state.progress,onCancelUpload:this.handleCancelUpload,onError:this.props.onError},t))},this);const e=o.Drafty.format(m,x.e3,this.formatterContext);m=n().createElement(n().Fragment,null,e)}else"string"==typeof m?new RegExp("^\\p{RGI_Emoji}{1,5}$","v").test(m||"")&&(d+=" emoji-"+(m||"").match(/(?:👨🏻‍❤️‍💋‍👨🏻|👨🏻‍❤️‍💋‍👨🏼|👨🏻‍❤️‍💋‍👨🏽|👨🏻‍❤️‍💋‍👨🏾|👨🏻‍❤️‍💋‍👨🏿|👨🏼‍❤️‍💋‍👨🏻|👨🏼‍❤️‍💋‍👨🏼|👨🏼‍❤️‍💋‍👨🏽|👨🏼‍❤️‍💋‍👨🏾|👨🏼‍❤️‍💋‍👨🏿|👨🏽‍❤️‍💋‍👨🏻|👨🏽‍❤️‍💋‍👨🏼|👨🏽‍❤️‍💋‍👨🏽|👨🏽‍❤️‍💋‍👨🏾|👨🏽‍❤️‍💋‍👨🏿|👨🏾‍❤️‍💋‍👨🏻|👨🏾‍❤️‍💋‍👨🏼|👨🏾‍❤️‍💋‍👨🏽|👨🏾‍❤️‍💋‍👨🏾|👨🏾‍❤️‍💋‍👨🏿|👨🏿‍❤️‍💋‍👨🏻|👨🏿‍❤️‍💋‍👨🏼|👨🏿‍❤️‍💋‍👨🏽|👨🏿‍❤️‍💋‍👨🏾|👨🏿‍❤️‍💋‍👨🏿|👩🏻‍❤️‍💋‍👨🏻|👩🏻‍❤️‍💋‍👨🏼|👩🏻‍❤️‍💋‍👨🏽|👩🏻‍❤️‍💋‍👨🏾|👩🏻‍❤️‍💋‍👨🏿|👩🏻‍❤️‍💋‍👩🏻|👩🏻‍❤️‍💋‍👩🏼|👩🏻‍❤️‍💋‍👩🏽|👩🏻‍❤️‍💋‍👩🏾|👩🏻‍❤️‍💋‍👩🏿|👩🏼‍❤️‍💋‍👨🏻|👩🏼‍❤️‍💋‍👨🏼|👩🏼‍❤️‍💋‍👨🏽|👩🏼‍❤️‍💋‍👨🏾|👩🏼‍❤️‍💋‍👨🏿|👩🏼‍❤️‍💋‍👩🏻|👩🏼‍❤️‍💋‍👩🏼|👩🏼‍❤️‍💋‍👩🏽|👩🏼‍❤️‍💋‍👩🏾|👩🏼‍❤️‍💋‍👩🏿|👩🏽‍❤️‍💋‍👨🏻|👩🏽‍❤️‍💋‍👨🏼|👩🏽‍❤️‍💋‍👨🏽|👩🏽‍❤️‍💋‍👨🏾|👩🏽‍❤️‍💋‍👨🏿|👩🏽‍❤️‍💋‍👩🏻|👩🏽‍❤️‍💋‍👩🏼|👩🏽‍❤️‍💋‍👩🏽|👩🏽‍❤️‍💋‍👩🏾|👩🏽‍❤️‍💋‍👩🏿|👩🏾‍❤️‍💋‍👨🏻|👩🏾‍❤️‍💋‍👨🏼|👩🏾‍❤️‍💋‍👨🏽|👩🏾‍❤️‍💋‍👨🏾|👩🏾‍❤️‍💋‍👨🏿|👩🏾‍❤️‍💋‍👩🏻|👩🏾‍❤️‍💋‍👩🏼|👩🏾‍❤️‍💋‍👩🏽|👩🏾‍❤️‍💋‍👩🏾|👩🏾‍❤️‍💋‍👩🏿|👩🏿‍❤️‍💋‍👨🏻|👩🏿‍❤️‍💋‍👨🏼|👩🏿‍❤️‍💋‍👨🏽|👩🏿‍❤️‍💋‍👨🏾|👩🏿‍❤️‍💋‍👨🏿|👩🏿‍❤️‍💋‍👩🏻|👩🏿‍❤️‍💋‍👩🏼|👩🏿‍❤️‍💋‍👩🏽|👩🏿‍❤️‍💋‍👩🏾|👩🏿‍❤️‍💋‍👩🏿|🧑🏻‍❤️‍💋‍🧑🏼|🧑🏻‍❤️‍💋‍🧑🏽|🧑🏻‍❤️‍💋‍🧑🏾|🧑🏻‍❤️‍💋‍🧑🏿|🧑🏼‍❤️‍💋‍🧑🏻|🧑🏼‍❤️‍💋‍🧑🏽|🧑🏼‍❤️‍💋‍🧑🏾|🧑🏼‍❤️‍💋‍🧑🏿|🧑🏽‍❤️‍💋‍🧑🏻|🧑🏽‍❤️‍💋‍🧑🏼|🧑🏽‍❤️‍💋‍🧑🏾|🧑🏽‍❤️‍💋‍🧑🏿|🧑🏾‍❤️‍💋‍🧑🏻|🧑🏾‍❤️‍💋‍🧑🏼|🧑🏾‍❤️‍💋‍🧑🏽|🧑🏾‍❤️‍💋‍🧑🏿|🧑🏿‍❤️‍💋‍🧑🏻|🧑🏿‍❤️‍💋‍🧑🏼|🧑🏿‍❤️‍💋‍🧑🏽|🧑🏿‍❤️‍💋‍🧑🏾|🏴󠁧󠁢󠁥󠁮󠁧󠁿|🏴󠁧󠁢󠁳󠁣󠁴󠁿|🏴󠁧󠁢󠁷󠁬󠁳󠁿|👨🏻‍❤️‍👨🏻|👨🏻‍❤️‍👨🏼|👨🏻‍❤️‍👨🏽|👨🏻‍❤️‍👨🏾|👨🏻‍❤️‍👨🏿|👨🏻‍🐰‍👨🏼|👨🏻‍🐰‍👨🏽|👨🏻‍🐰‍👨🏾|👨🏻‍🐰‍👨🏿|👨🏻‍🤝‍👨🏼|👨🏻‍🤝‍👨🏽|👨🏻‍🤝‍👨🏾|👨🏻‍🤝‍👨🏿|👨🏻‍🫯‍👨🏼|👨🏻‍🫯‍👨🏽|👨🏻‍🫯‍👨🏾|👨🏻‍🫯‍👨🏿|👨🏼‍❤️‍👨🏻|👨🏼‍❤️‍👨🏼|👨🏼‍❤️‍👨🏽|👨🏼‍❤️‍👨🏾|👨🏼‍❤️‍👨🏿|👨🏼‍🐰‍👨🏻|👨🏼‍🐰‍👨🏽|👨🏼‍🐰‍👨🏾|👨🏼‍🐰‍👨🏿|👨🏼‍🤝‍👨🏻|👨🏼‍🤝‍👨🏽|👨🏼‍🤝‍👨🏾|👨🏼‍🤝‍👨🏿|👨🏼‍🫯‍👨🏻|👨🏼‍🫯‍👨🏽|👨🏼‍🫯‍👨🏾|👨🏼‍🫯‍👨🏿|👨🏽‍❤️‍👨🏻|👨🏽‍❤️‍👨🏼|👨🏽‍❤️‍👨🏽|👨🏽‍❤️‍👨🏾|👨🏽‍❤️‍👨🏿|👨🏽‍🐰‍👨🏻|👨🏽‍🐰‍👨🏼|👨🏽‍🐰‍👨🏾|👨🏽‍🐰‍👨🏿|👨🏽‍🤝‍👨🏻|👨🏽‍🤝‍👨🏼|👨🏽‍🤝‍👨🏾|👨🏽‍🤝‍👨🏿|👨🏽‍🫯‍👨🏻|👨🏽‍🫯‍👨🏼|👨🏽‍🫯‍👨🏾|👨🏽‍🫯‍👨🏿|👨🏾‍❤️‍👨🏻|👨🏾‍❤️‍👨🏼|👨🏾‍❤️‍👨🏽|👨🏾‍❤️‍👨🏾|👨🏾‍❤️‍👨🏿|👨🏾‍🐰‍👨🏻|👨🏾‍🐰‍👨🏼|👨🏾‍🐰‍👨🏽|👨🏾‍🐰‍👨🏿|👨🏾‍🤝‍👨🏻|👨🏾‍🤝‍👨🏼|👨🏾‍🤝‍👨🏽|👨🏾‍🤝‍👨🏿|👨🏾‍🫯‍👨🏻|👨🏾‍🫯‍👨🏼|👨🏾‍🫯‍👨🏽|👨🏾‍🫯‍👨🏿|👨🏿‍❤️‍👨🏻|👨🏿‍❤️‍👨🏼|👨🏿‍❤️‍👨🏽|👨🏿‍❤️‍👨🏾|👨🏿‍❤️‍👨🏿|👨🏿‍🐰‍👨🏻|👨🏿‍🐰‍👨🏼|👨🏿‍🐰‍👨🏽|👨🏿‍🐰‍👨🏾|👨🏿‍🤝‍👨🏻|👨🏿‍🤝‍👨🏼|👨🏿‍🤝‍👨🏽|👨🏿‍🤝‍👨🏾|👨🏿‍🫯‍👨🏻|👨🏿‍🫯‍👨🏼|👨🏿‍🫯‍👨🏽|👨🏿‍🫯‍👨🏾|👩🏻‍❤️‍👨🏻|👩🏻‍❤️‍👨🏼|👩🏻‍❤️‍👨🏽|👩🏻‍❤️‍👨🏾|👩🏻‍❤️‍👨🏿|👩🏻‍❤️‍👩🏻|👩🏻‍❤️‍👩🏼|👩🏻‍❤️‍👩🏽|👩🏻‍❤️‍👩🏾|👩🏻‍❤️‍👩🏿|👩🏻‍🐰‍👩🏼|👩🏻‍🐰‍👩🏽|👩🏻‍🐰‍👩🏾|👩🏻‍🐰‍👩🏿|👩🏻‍🤝‍👨🏼|👩🏻‍🤝‍👨🏽|👩🏻‍🤝‍👨🏾|👩🏻‍🤝‍👨🏿|👩🏻‍🤝‍👩🏼|👩🏻‍🤝‍👩🏽|👩🏻‍🤝‍👩🏾|👩🏻‍🤝‍👩🏿|👩🏻‍🫯‍👩🏼|👩🏻‍🫯‍👩🏽|👩🏻‍🫯‍👩🏾|👩🏻‍🫯‍👩🏿|👩🏼‍❤️‍👨🏻|👩🏼‍❤️‍👨🏼|👩🏼‍❤️‍👨🏽|👩🏼‍❤️‍👨🏾|👩🏼‍❤️‍👨🏿|👩🏼‍❤️‍👩🏻|👩🏼‍❤️‍👩🏼|👩🏼‍❤️‍👩🏽|👩🏼‍❤️‍👩🏾|👩🏼‍❤️‍👩🏿|👩🏼‍🐰‍👩🏻|👩🏼‍🐰‍👩🏽|👩🏼‍🐰‍👩🏾|👩🏼‍🐰‍👩🏿|👩🏼‍🤝‍👨🏻|👩🏼‍🤝‍👨🏽|👩🏼‍🤝‍👨🏾|👩🏼‍🤝‍👨🏿|👩🏼‍🤝‍👩🏻|👩🏼‍🤝‍👩🏽|👩🏼‍🤝‍👩🏾|👩🏼‍🤝‍👩🏿|👩🏼‍🫯‍👩🏻|👩🏼‍🫯‍👩🏽|👩🏼‍🫯‍👩🏾|👩🏼‍🫯‍👩🏿|👩🏽‍❤️‍👨🏻|👩🏽‍❤️‍👨🏼|👩🏽‍❤️‍👨🏽|👩🏽‍❤️‍👨🏾|👩🏽‍❤️‍👨🏿|👩🏽‍❤️‍👩🏻|👩🏽‍❤️‍👩🏼|👩🏽‍❤️‍👩🏽|👩🏽‍❤️‍👩🏾|👩🏽‍❤️‍👩🏿|👩🏽‍🐰‍👩🏻|👩🏽‍🐰‍👩🏼|👩🏽‍🐰‍👩🏾|👩🏽‍🐰‍👩🏿|👩🏽‍🤝‍👨🏻|👩🏽‍🤝‍👨🏼|👩🏽‍🤝‍👨🏾|👩🏽‍🤝‍👨🏿|👩🏽‍🤝‍👩🏻|👩🏽‍🤝‍👩🏼|👩🏽‍🤝‍👩🏾|👩🏽‍🤝‍👩🏿|👩🏽‍🫯‍👩🏻|👩🏽‍🫯‍👩🏼|👩🏽‍🫯‍👩🏾|👩🏽‍🫯‍👩🏿|👩🏾‍❤️‍👨🏻|👩🏾‍❤️‍👨🏼|👩🏾‍❤️‍👨🏽|👩🏾‍❤️‍👨🏾|👩🏾‍❤️‍👨🏿|👩🏾‍❤️‍👩🏻|👩🏾‍❤️‍👩🏼|👩🏾‍❤️‍👩🏽|👩🏾‍❤️‍👩🏾|👩🏾‍❤️‍👩🏿|👩🏾‍🐰‍👩🏻|👩🏾‍🐰‍👩🏼|👩🏾‍🐰‍👩🏽|👩🏾‍🐰‍👩🏿|👩🏾‍🤝‍👨🏻|👩🏾‍🤝‍👨🏼|👩🏾‍🤝‍👨🏽|👩🏾‍🤝‍👨🏿|👩🏾‍🤝‍👩🏻|👩🏾‍🤝‍👩🏼|👩🏾‍🤝‍👩🏽|👩🏾‍🤝‍👩🏿|👩🏾‍🫯‍👩🏻|👩🏾‍🫯‍👩🏼|👩🏾‍🫯‍👩🏽|👩🏾‍🫯‍👩🏿|👩🏿‍❤️‍👨🏻|👩🏿‍❤️‍👨🏼|👩🏿‍❤️‍👨🏽|👩🏿‍❤️‍👨🏾|👩🏿‍❤️‍👨🏿|👩🏿‍❤️‍👩🏻|👩🏿‍❤️‍👩🏼|👩🏿‍❤️‍👩🏽|👩🏿‍❤️‍👩🏾|👩🏿‍❤️‍👩🏿|👩🏿‍🐰‍👩🏻|👩🏿‍🐰‍👩🏼|👩🏿‍🐰‍👩🏽|👩🏿‍🐰‍👩🏾|👩🏿‍🤝‍👨🏻|👩🏿‍🤝‍👨🏼|👩🏿‍🤝‍👨🏽|👩🏿‍🤝‍👨🏾|👩🏿‍🤝‍👩🏻|👩🏿‍🤝‍👩🏼|👩🏿‍🤝‍👩🏽|👩🏿‍🤝‍👩🏾|👩🏿‍🫯‍👩🏻|👩🏿‍🫯‍👩🏼|👩🏿‍🫯‍👩🏽|👩🏿‍🫯‍👩🏾|🧑🏻‍❤️‍🧑🏼|🧑🏻‍❤️‍🧑🏽|🧑🏻‍❤️‍🧑🏾|🧑🏻‍❤️‍🧑🏿|🧑🏻‍🐰‍🧑🏼|🧑🏻‍🐰‍🧑🏽|🧑🏻‍🐰‍🧑🏾|🧑🏻‍🐰‍🧑🏿|🧑🏻‍🤝‍🧑🏻|🧑🏻‍🤝‍🧑🏼|🧑🏻‍🤝‍🧑🏽|🧑🏻‍🤝‍🧑🏾|🧑🏻‍🤝‍🧑🏿|🧑🏻‍🫯‍🧑🏼|🧑🏻‍🫯‍🧑🏽|🧑🏻‍🫯‍🧑🏾|🧑🏻‍🫯‍🧑🏿|🧑🏼‍❤️‍🧑🏻|🧑🏼‍❤️‍🧑🏽|🧑🏼‍❤️‍🧑🏾|🧑🏼‍❤️‍🧑🏿|🧑🏼‍🐰‍🧑🏻|🧑🏼‍🐰‍🧑🏽|🧑🏼‍🐰‍🧑🏾|🧑🏼‍🐰‍🧑🏿|🧑🏼‍🤝‍🧑🏻|🧑🏼‍🤝‍🧑🏼|🧑🏼‍🤝‍🧑🏽|🧑🏼‍🤝‍🧑🏾|🧑🏼‍🤝‍🧑🏿|🧑🏼‍🫯‍🧑🏻|🧑🏼‍🫯‍🧑🏽|🧑🏼‍🫯‍🧑🏾|🧑🏼‍🫯‍🧑🏿|🧑🏽‍❤️‍🧑🏻|🧑🏽‍❤️‍🧑🏼|🧑🏽‍❤️‍🧑🏾|🧑🏽‍❤️‍🧑🏿|🧑🏽‍🐰‍🧑🏻|🧑🏽‍🐰‍🧑🏼|🧑🏽‍🐰‍🧑🏾|🧑🏽‍🐰‍🧑🏿|🧑🏽‍🤝‍🧑🏻|🧑🏽‍🤝‍🧑🏼|🧑🏽‍🤝‍🧑🏽|🧑🏽‍🤝‍🧑🏾|🧑🏽‍🤝‍🧑🏿|🧑🏽‍🫯‍🧑🏻|🧑🏽‍🫯‍🧑🏼|🧑🏽‍🫯‍🧑🏾|🧑🏽‍🫯‍🧑🏿|🧑🏾‍❤️‍🧑🏻|🧑🏾‍❤️‍🧑🏼|🧑🏾‍❤️‍🧑🏽|🧑🏾‍❤️‍🧑🏿|🧑🏾‍🐰‍🧑🏻|🧑🏾‍🐰‍🧑🏼|🧑🏾‍🐰‍🧑🏽|🧑🏾‍🐰‍🧑🏿|🧑🏾‍🤝‍🧑🏻|🧑🏾‍🤝‍🧑🏼|🧑🏾‍🤝‍🧑🏽|🧑🏾‍🤝‍🧑🏾|🧑🏾‍🤝‍🧑🏿|🧑🏾‍🫯‍🧑🏻|🧑🏾‍🫯‍🧑🏼|🧑🏾‍🫯‍🧑🏽|🧑🏾‍🫯‍🧑🏿|🧑🏿‍❤️‍🧑🏻|🧑🏿‍❤️‍🧑🏼|🧑🏿‍❤️‍🧑🏽|🧑🏿‍❤️‍🧑🏾|🧑🏿‍🐰‍🧑🏻|🧑🏿‍🐰‍🧑🏼|🧑🏿‍🐰‍🧑🏽|🧑🏿‍🐰‍🧑🏾|🧑🏿‍🤝‍🧑🏻|🧑🏿‍🤝‍🧑🏼|🧑🏿‍🤝‍🧑🏽|🧑🏿‍🤝‍🧑🏾|🧑🏿‍🤝‍🧑🏿|🧑🏿‍🫯‍🧑🏻|🧑🏿‍🫯‍🧑🏼|🧑🏿‍🫯‍🧑🏽|🧑🏿‍🫯‍🧑🏾|👨‍❤️‍💋‍👨|👨‍👨‍👦‍👦|👨‍👨‍👧‍👦|👨‍👨‍👧‍👧|👨‍👩‍👦‍👦|👨‍👩‍👧‍👦|👨‍👩‍👧‍👧|👩‍❤️‍💋‍👨|👩‍❤️‍💋‍👩|👩‍👩‍👦‍👦|👩‍👩‍👧‍👦|👩‍👩‍👧‍👧|🧑‍🧑‍🧒‍🧒|🏃🏻‍♀️‍➡️|🏃🏻‍♂️‍➡️|🏃🏼‍♀️‍➡️|🏃🏼‍♂️‍➡️|🏃🏽‍♀️‍➡️|🏃🏽‍♂️‍➡️|🏃🏾‍♀️‍➡️|🏃🏾‍♂️‍➡️|🏃🏿‍♀️‍➡️|🏃🏿‍♂️‍➡️|👨🏻‍🦯‍➡️|👨🏻‍🦼‍➡️|👨🏻‍🦽‍➡️|👨🏼‍🦯‍➡️|👨🏼‍🦼‍➡️|👨🏼‍🦽‍➡️|👨🏽‍🦯‍➡️|👨🏽‍🦼‍➡️|👨🏽‍🦽‍➡️|👨🏾‍🦯‍➡️|👨🏾‍🦼‍➡️|👨🏾‍🦽‍➡️|👨🏿‍🦯‍➡️|👨🏿‍🦼‍➡️|👨🏿‍🦽‍➡️|👩🏻‍🦯‍➡️|👩🏻‍🦼‍➡️|👩🏻‍🦽‍➡️|👩🏼‍🦯‍➡️|👩🏼‍🦼‍➡️|👩🏼‍🦽‍➡️|👩🏽‍🦯‍➡️|👩🏽‍🦼‍➡️|👩🏽‍🦽‍➡️|👩🏾‍🦯‍➡️|👩🏾‍🦼‍➡️|👩🏾‍🦽‍➡️|👩🏿‍🦯‍➡️|👩🏿‍🦼‍➡️|👩🏿‍🦽‍➡️|🚶🏻‍♀️‍➡️|🚶🏻‍♂️‍➡️|🚶🏼‍♀️‍➡️|🚶🏼‍♂️‍➡️|🚶🏽‍♀️‍➡️|🚶🏽‍♂️‍➡️|🚶🏾‍♀️‍➡️|🚶🏾‍♂️‍➡️|🚶🏿‍♀️‍➡️|🚶🏿‍♂️‍➡️|🧎🏻‍♀️‍➡️|🧎🏻‍♂️‍➡️|🧎🏼‍♀️‍➡️|🧎🏼‍♂️‍➡️|🧎🏽‍♀️‍➡️|🧎🏽‍♂️‍➡️|🧎🏾‍♀️‍➡️|🧎🏾‍♂️‍➡️|🧎🏿‍♀️‍➡️|🧎🏿‍♂️‍➡️|🧑🏻‍🦯‍➡️|🧑🏻‍🦼‍➡️|🧑🏻‍🦽‍➡️|🧑🏼‍🦯‍➡️|🧑🏼‍🦼‍➡️|🧑🏼‍🦽‍➡️|🧑🏽‍🦯‍➡️|🧑🏽‍🦼‍➡️|🧑🏽‍🦽‍➡️|🧑🏾‍🦯‍➡️|🧑🏾‍🦼‍➡️|🧑🏾‍🦽‍➡️|🧑🏿‍🦯‍➡️|🧑🏿‍🦼‍➡️|🧑🏿‍🦽‍➡️|🫱🏻‍🫲🏼|🫱🏻‍🫲🏽|🫱🏻‍🫲🏾|🫱🏻‍🫲🏿|🫱🏼‍🫲🏻|🫱🏼‍🫲🏽|🫱🏼‍🫲🏾|🫱🏼‍🫲🏿|🫱🏽‍🫲🏻|🫱🏽‍🫲🏼|🫱🏽‍🫲🏾|🫱🏽‍🫲🏿|🫱🏾‍🫲🏻|🫱🏾‍🫲🏼|🫱🏾‍🫲🏽|🫱🏾‍🫲🏿|🫱🏿‍🫲🏻|🫱🏿‍🫲🏼|🫱🏿‍🫲🏽|🫱🏿‍🫲🏾|🏃‍♀️‍➡️|🏃‍♂️‍➡️|👨‍❤️‍👨|👨‍👦‍👦|👨‍👧‍👦|👨‍👧‍👧|👨‍👨‍👦|👨‍👨‍👧|👨‍👩‍👦|👨‍👩‍👧|👨‍🦯‍➡️|👨‍🦼‍➡️|👨‍🦽‍➡️|👩‍❤️‍👨|👩‍❤️‍👩|👩‍👦‍👦|👩‍👧‍👦|👩‍👧‍👧|👩‍👩‍👦|👩‍👩‍👧|👩‍🦯‍➡️|👩‍🦼‍➡️|👩‍🦽‍➡️|🚶‍♀️‍➡️|🚶‍♂️‍➡️|🧎‍♀️‍➡️|🧎‍♂️‍➡️|🧑‍🤝‍🧑|🧑‍🦯‍➡️|🧑‍🦼‍➡️|🧑‍🦽‍➡️|🧑‍🧑‍🧒|🧑‍🧒‍🧒|🏃🏻‍♀️|🏃🏻‍♂️|🏃🏻‍➡️|🏃🏼‍♀️|🏃🏼‍♂️|🏃🏼‍➡️|🏃🏽‍♀️|🏃🏽‍♂️|🏃🏽‍➡️|🏃🏾‍♀️|🏃🏾‍♂️|🏃🏾‍➡️|🏃🏿‍♀️|🏃🏿‍♂️|🏃🏿‍➡️|🏄🏻‍♀️|🏄🏻‍♂️|🏄🏼‍♀️|🏄🏼‍♂️|🏄🏽‍♀️|🏄🏽‍♂️|🏄🏾‍♀️|🏄🏾‍♂️|🏄🏿‍♀️|🏄🏿‍♂️|🏊🏻‍♀️|🏊🏻‍♂️|🏊🏼‍♀️|🏊🏼‍♂️|🏊🏽‍♀️|🏊🏽‍♂️|🏊🏾‍♀️|🏊🏾‍♂️|🏊🏿‍♀️|🏊🏿‍♂️|🏋🏻‍♀️|🏋🏻‍♂️|🏋🏼‍♀️|🏋🏼‍♂️|🏋🏽‍♀️|🏋🏽‍♂️|🏋🏾‍♀️|🏋🏾‍♂️|🏋🏿‍♀️|🏋🏿‍♂️|🏌🏻‍♀️|🏌🏻‍♂️|🏌🏼‍♀️|🏌🏼‍♂️|🏌🏽‍♀️|🏌🏽‍♂️|🏌🏾‍♀️|🏌🏾‍♂️|🏌🏿‍♀️|🏌🏿‍♂️|👁️‍🗨️|👨🏻‍⚕️|👨🏻‍⚖️|👨🏻‍✈️|👨🏻‍🌾|👨🏻‍🍳|👨🏻‍🍼|👨🏻‍🎓|👨🏻‍🎤|👨🏻‍🎨|👨🏻‍🏫|👨🏻‍🏭|👨🏻‍💻|👨🏻‍💼|👨🏻‍🔧|👨🏻‍🔬|👨🏻‍🚀|👨🏻‍🚒|👨🏻‍🦯|👨🏻‍🦰|👨🏻‍🦱|👨🏻‍🦲|👨🏻‍🦳|👨🏻‍🦼|👨🏻‍🦽|👨🏼‍⚕️|👨🏼‍⚖️|👨🏼‍✈️|👨🏼‍🌾|👨🏼‍🍳|👨🏼‍🍼|👨🏼‍🎓|👨🏼‍🎤|👨🏼‍🎨|👨🏼‍🏫|👨🏼‍🏭|👨🏼‍💻|👨🏼‍💼|👨🏼‍🔧|👨🏼‍🔬|👨🏼‍🚀|👨🏼‍🚒|👨🏼‍🦯|👨🏼‍🦰|👨🏼‍🦱|👨🏼‍🦲|👨🏼‍🦳|👨🏼‍🦼|👨🏼‍🦽|👨🏽‍⚕️|👨🏽‍⚖️|👨🏽‍✈️|👨🏽‍🌾|👨🏽‍🍳|👨🏽‍🍼|👨🏽‍🎓|👨🏽‍🎤|👨🏽‍🎨|👨🏽‍🏫|👨🏽‍🏭|👨🏽‍💻|👨🏽‍💼|👨🏽‍🔧|👨🏽‍🔬|👨🏽‍🚀|👨🏽‍🚒|👨🏽‍🦯|👨🏽‍🦰|👨🏽‍🦱|👨🏽‍🦲|👨🏽‍🦳|👨🏽‍🦼|👨🏽‍🦽|👨🏾‍⚕️|👨🏾‍⚖️|👨🏾‍✈️|👨🏾‍🌾|👨🏾‍🍳|👨🏾‍🍼|👨🏾‍🎓|👨🏾‍🎤|👨🏾‍🎨|👨🏾‍🏫|👨🏾‍🏭|👨🏾‍💻|👨🏾‍💼|👨🏾‍🔧|👨🏾‍🔬|👨🏾‍🚀|👨🏾‍🚒|👨🏾‍🦯|👨🏾‍🦰|👨🏾‍🦱|👨🏾‍🦲|👨🏾‍🦳|👨🏾‍🦼|👨🏾‍🦽|👨🏿‍⚕️|👨🏿‍⚖️|👨🏿‍✈️|👨🏿‍🌾|👨🏿‍🍳|👨🏿‍🍼|👨🏿‍🎓|👨🏿‍🎤|👨🏿‍🎨|👨🏿‍🏫|👨🏿‍🏭|👨🏿‍💻|👨🏿‍💼|👨🏿‍🔧|👨🏿‍🔬|👨🏿‍🚀|👨🏿‍🚒|👨🏿‍🦯|👨🏿‍🦰|👨🏿‍🦱|👨🏿‍🦲|👨🏿‍🦳|👨🏿‍🦼|👨🏿‍🦽|👩🏻‍⚕️|👩🏻‍⚖️|👩🏻‍✈️|👩🏻‍🌾|👩🏻‍🍳|👩🏻‍🍼|👩🏻‍🎓|👩🏻‍🎤|👩🏻‍🎨|👩🏻‍🏫|👩🏻‍🏭|👩🏻‍💻|👩🏻‍💼|👩🏻‍🔧|👩🏻‍🔬|👩🏻‍🚀|👩🏻‍🚒|👩🏻‍🦯|👩🏻‍🦰|👩🏻‍🦱|👩🏻‍🦲|👩🏻‍🦳|👩🏻‍🦼|👩🏻‍🦽|👩🏼‍⚕️|👩🏼‍⚖️|👩🏼‍✈️|👩🏼‍🌾|👩🏼‍🍳|👩🏼‍🍼|👩🏼‍🎓|👩🏼‍🎤|👩🏼‍🎨|👩🏼‍🏫|👩🏼‍🏭|👩🏼‍💻|👩🏼‍💼|👩🏼‍🔧|👩🏼‍🔬|👩🏼‍🚀|👩🏼‍🚒|👩🏼‍🦯|👩🏼‍🦰|👩🏼‍🦱|👩🏼‍🦲|👩🏼‍🦳|👩🏼‍🦼|👩🏼‍🦽|👩🏽‍⚕️|👩🏽‍⚖️|👩🏽‍✈️|👩🏽‍🌾|👩🏽‍🍳|👩🏽‍🍼|👩🏽‍🎓|👩🏽‍🎤|👩🏽‍🎨|👩🏽‍🏫|👩🏽‍🏭|👩🏽‍💻|👩🏽‍💼|👩🏽‍🔧|👩🏽‍🔬|👩🏽‍🚀|👩🏽‍🚒|👩🏽‍🦯|👩🏽‍🦰|👩🏽‍🦱|👩🏽‍🦲|👩🏽‍🦳|👩🏽‍🦼|👩🏽‍🦽|👩🏾‍⚕️|👩🏾‍⚖️|👩🏾‍✈️|👩🏾‍🌾|👩🏾‍🍳|👩🏾‍🍼|👩🏾‍🎓|👩🏾‍🎤|👩🏾‍🎨|👩🏾‍🏫|👩🏾‍🏭|👩🏾‍💻|👩🏾‍💼|👩🏾‍🔧|👩🏾‍🔬|👩🏾‍🚀|👩🏾‍🚒|👩🏾‍🦯|👩🏾‍🦰|👩🏾‍🦱|👩🏾‍🦲|👩🏾‍🦳|👩🏾‍🦼|👩🏾‍🦽|👩🏿‍⚕️|👩🏿‍⚖️|👩🏿‍✈️|👩🏿‍🌾|👩🏿‍🍳|👩🏿‍🍼|👩🏿‍🎓|👩🏿‍🎤|👩🏿‍🎨|👩🏿‍🏫|👩🏿‍🏭|👩🏿‍💻|👩🏿‍💼|👩🏿‍🔧|👩🏿‍🔬|👩🏿‍🚀|👩🏿‍🚒|👩🏿‍🦯|👩🏿‍🦰|👩🏿‍🦱|👩🏿‍🦲|👩🏿‍🦳|👩🏿‍🦼|👩🏿‍🦽|👮🏻‍♀️|👮🏻‍♂️|👮🏼‍♀️|👮🏼‍♂️|👮🏽‍♀️|👮🏽‍♂️|👮🏾‍♀️|👮🏾‍♂️|👮🏿‍♀️|👮🏿‍♂️|👯🏻‍♀️|👯🏻‍♂️|👯🏼‍♀️|👯🏼‍♂️|👯🏽‍♀️|👯🏽‍♂️|👯🏾‍♀️|👯🏾‍♂️|👯🏿‍♀️|👯🏿‍♂️|👰🏻‍♀️|👰🏻‍♂️|👰🏼‍♀️|👰🏼‍♂️|👰🏽‍♀️|👰🏽‍♂️|👰🏾‍♀️|👰🏾‍♂️|👰🏿‍♀️|👰🏿‍♂️|👱🏻‍♀️|👱🏻‍♂️|👱🏼‍♀️|👱🏼‍♂️|👱🏽‍♀️|👱🏽‍♂️|👱🏾‍♀️|👱🏾‍♂️|👱🏿‍♀️|👱🏿‍♂️|👳🏻‍♀️|👳🏻‍♂️|👳🏼‍♀️|👳🏼‍♂️|👳🏽‍♀️|👳🏽‍♂️|👳🏾‍♀️|👳🏾‍♂️|👳🏿‍♀️|👳🏿‍♂️|👷🏻‍♀️|👷🏻‍♂️|👷🏼‍♀️|👷🏼‍♂️|👷🏽‍♀️|👷🏽‍♂️|👷🏾‍♀️|👷🏾‍♂️|👷🏿‍♀️|👷🏿‍♂️|💁🏻‍♀️|💁🏻‍♂️|💁🏼‍♀️|💁🏼‍♂️|💁🏽‍♀️|💁🏽‍♂️|💁🏾‍♀️|💁🏾‍♂️|💁🏿‍♀️|💁🏿‍♂️|💂🏻‍♀️|💂🏻‍♂️|💂🏼‍♀️|💂🏼‍♂️|💂🏽‍♀️|💂🏽‍♂️|💂🏾‍♀️|💂🏾‍♂️|💂🏿‍♀️|💂🏿‍♂️|💆🏻‍♀️|💆🏻‍♂️|💆🏼‍♀️|💆🏼‍♂️|💆🏽‍♀️|💆🏽‍♂️|💆🏾‍♀️|💆🏾‍♂️|💆🏿‍♀️|💆🏿‍♂️|💇🏻‍♀️|💇🏻‍♂️|💇🏼‍♀️|💇🏼‍♂️|💇🏽‍♀️|💇🏽‍♂️|💇🏾‍♀️|💇🏾‍♂️|💇🏿‍♀️|💇🏿‍♂️|🕵🏻‍♀️|🕵🏻‍♂️|🕵🏼‍♀️|🕵🏼‍♂️|🕵🏽‍♀️|🕵🏽‍♂️|🕵🏾‍♀️|🕵🏾‍♂️|🕵🏿‍♀️|🕵🏿‍♂️|🙅🏻‍♀️|🙅🏻‍♂️|🙅🏼‍♀️|🙅🏼‍♂️|🙅🏽‍♀️|🙅🏽‍♂️|🙅🏾‍♀️|🙅🏾‍♂️|🙅🏿‍♀️|🙅🏿‍♂️|🙆🏻‍♀️|🙆🏻‍♂️|🙆🏼‍♀️|🙆🏼‍♂️|🙆🏽‍♀️|🙆🏽‍♂️|🙆🏾‍♀️|🙆🏾‍♂️|🙆🏿‍♀️|🙆🏿‍♂️|🙇🏻‍♀️|🙇🏻‍♂️|🙇🏼‍♀️|🙇🏼‍♂️|🙇🏽‍♀️|🙇🏽‍♂️|🙇🏾‍♀️|🙇🏾‍♂️|🙇🏿‍♀️|🙇🏿‍♂️|🙋🏻‍♀️|🙋🏻‍♂️|🙋🏼‍♀️|🙋🏼‍♂️|🙋🏽‍♀️|🙋🏽‍♂️|🙋🏾‍♀️|🙋🏾‍♂️|🙋🏿‍♀️|🙋🏿‍♂️|🙍🏻‍♀️|🙍🏻‍♂️|🙍🏼‍♀️|🙍🏼‍♂️|🙍🏽‍♀️|🙍🏽‍♂️|🙍🏾‍♀️|🙍🏾‍♂️|🙍🏿‍♀️|🙍🏿‍♂️|🙎🏻‍♀️|🙎🏻‍♂️|🙎🏼‍♀️|🙎🏼‍♂️|🙎🏽‍♀️|🙎🏽‍♂️|🙎🏾‍♀️|🙎🏾‍♂️|🙎🏿‍♀️|🙎🏿‍♂️|🚣🏻‍♀️|🚣🏻‍♂️|🚣🏼‍♀️|🚣🏼‍♂️|🚣🏽‍♀️|🚣🏽‍♂️|🚣🏾‍♀️|🚣🏾‍♂️|🚣🏿‍♀️|🚣🏿‍♂️|🚴🏻‍♀️|🚴🏻‍♂️|🚴🏼‍♀️|🚴🏼‍♂️|🚴🏽‍♀️|🚴🏽‍♂️|🚴🏾‍♀️|🚴🏾‍♂️|🚴🏿‍♀️|🚴🏿‍♂️|🚵🏻‍♀️|🚵🏻‍♂️|🚵🏼‍♀️|🚵🏼‍♂️|🚵🏽‍♀️|🚵🏽‍♂️|🚵🏾‍♀️|🚵🏾‍♂️|🚵🏿‍♀️|🚵🏿‍♂️|🚶🏻‍♀️|🚶🏻‍♂️|🚶🏻‍➡️|🚶🏼‍♀️|🚶🏼‍♂️|🚶🏼‍➡️|🚶🏽‍♀️|🚶🏽‍♂️|🚶🏽‍➡️|🚶🏾‍♀️|🚶🏾‍♂️|🚶🏾‍➡️|🚶🏿‍♀️|🚶🏿‍♂️|🚶🏿‍➡️|🤦🏻‍♀️|🤦🏻‍♂️|🤦🏼‍♀️|🤦🏼‍♂️|🤦🏽‍♀️|🤦🏽‍♂️|🤦🏾‍♀️|🤦🏾‍♂️|🤦🏿‍♀️|🤦🏿‍♂️|🤵🏻‍♀️|🤵🏻‍♂️|🤵🏼‍♀️|🤵🏼‍♂️|🤵🏽‍♀️|🤵🏽‍♂️|🤵🏾‍♀️|🤵🏾‍♂️|🤵🏿‍♀️|🤵🏿‍♂️|🤷🏻‍♀️|🤷🏻‍♂️|🤷🏼‍♀️|🤷🏼‍♂️|🤷🏽‍♀️|🤷🏽‍♂️|🤷🏾‍♀️|🤷🏾‍♂️|🤷🏿‍♀️|🤷🏿‍♂️|🤸🏻‍♀️|🤸🏻‍♂️|🤸🏼‍♀️|🤸🏼‍♂️|🤸🏽‍♀️|🤸🏽‍♂️|🤸🏾‍♀️|🤸🏾‍♂️|🤸🏿‍♀️|🤸🏿‍♂️|🤹🏻‍♀️|🤹🏻‍♂️|🤹🏼‍♀️|🤹🏼‍♂️|🤹🏽‍♀️|🤹🏽‍♂️|🤹🏾‍♀️|🤹🏾‍♂️|🤹🏿‍♀️|🤹🏿‍♂️|🤼🏻‍♀️|🤼🏻‍♂️|🤼🏼‍♀️|🤼🏼‍♂️|🤼🏽‍♀️|🤼🏽‍♂️|🤼🏾‍♀️|🤼🏾‍♂️|🤼🏿‍♀️|🤼🏿‍♂️|🤽🏻‍♀️|🤽🏻‍♂️|🤽🏼‍♀️|🤽🏼‍♂️|🤽🏽‍♀️|🤽🏽‍♂️|🤽🏾‍♀️|🤽🏾‍♂️|🤽🏿‍♀️|🤽🏿‍♂️|🤾🏻‍♀️|🤾🏻‍♂️|🤾🏼‍♀️|🤾🏼‍♂️|🤾🏽‍♀️|🤾🏽‍♂️|🤾🏾‍♀️|🤾🏾‍♂️|🤾🏿‍♀️|🤾🏿‍♂️|🦸🏻‍♀️|🦸🏻‍♂️|🦸🏼‍♀️|🦸🏼‍♂️|🦸🏽‍♀️|🦸🏽‍♂️|🦸🏾‍♀️|🦸🏾‍♂️|🦸🏿‍♀️|🦸🏿‍♂️|🦹🏻‍♀️|🦹🏻‍♂️|🦹🏼‍♀️|🦹🏼‍♂️|🦹🏽‍♀️|🦹🏽‍♂️|🦹🏾‍♀️|🦹🏾‍♂️|🦹🏿‍♀️|🦹🏿‍♂️|🧍🏻‍♀️|🧍🏻‍♂️|🧍🏼‍♀️|🧍🏼‍♂️|🧍🏽‍♀️|🧍🏽‍♂️|🧍🏾‍♀️|🧍🏾‍♂️|🧍🏿‍♀️|🧍🏿‍♂️|🧎🏻‍♀️|🧎🏻‍♂️|🧎🏻‍➡️|🧎🏼‍♀️|🧎🏼‍♂️|🧎🏼‍➡️|🧎🏽‍♀️|🧎🏽‍♂️|🧎🏽‍➡️|🧎🏾‍♀️|🧎🏾‍♂️|🧎🏾‍➡️|🧎🏿‍♀️|🧎🏿‍♂️|🧎🏿‍➡️|🧏🏻‍♀️|🧏🏻‍♂️|🧏🏼‍♀️|🧏🏼‍♂️|🧏🏽‍♀️|🧏🏽‍♂️|🧏🏾‍♀️|🧏🏾‍♂️|🧏🏿‍♀️|🧏🏿‍♂️|🧑🏻‍⚕️|🧑🏻‍⚖️|🧑🏻‍✈️|🧑🏻‍🌾|🧑🏻‍🍳|🧑🏻‍🍼|🧑🏻‍🎄|🧑🏻‍🎓|🧑🏻‍🎤|🧑🏻‍🎨|🧑🏻‍🏫|🧑🏻‍🏭|🧑🏻‍💻|🧑🏻‍💼|🧑🏻‍🔧|🧑🏻‍🔬|🧑🏻‍🚀|🧑🏻‍🚒|🧑🏻‍🦯|🧑🏻‍🦰|🧑🏻‍🦱|🧑🏻‍🦲|🧑🏻‍🦳|🧑🏻‍🦼|🧑🏻‍🦽|🧑🏻‍🩰|🧑🏼‍⚕️|🧑🏼‍⚖️|🧑🏼‍✈️|🧑🏼‍🌾|🧑🏼‍🍳|🧑🏼‍🍼|🧑🏼‍🎄|🧑🏼‍🎓|🧑🏼‍🎤|🧑🏼‍🎨|🧑🏼‍🏫|🧑🏼‍🏭|🧑🏼‍💻|🧑🏼‍💼|🧑🏼‍🔧|🧑🏼‍🔬|🧑🏼‍🚀|🧑🏼‍🚒|🧑🏼‍🦯|🧑🏼‍🦰|🧑🏼‍🦱|🧑🏼‍🦲|🧑🏼‍🦳|🧑🏼‍🦼|🧑🏼‍🦽|🧑🏼‍🩰|🧑🏽‍⚕️|🧑🏽‍⚖️|🧑🏽‍✈️|🧑🏽‍🌾|🧑🏽‍🍳|🧑🏽‍🍼|🧑🏽‍🎄|🧑🏽‍🎓|🧑🏽‍🎤|🧑🏽‍🎨|🧑🏽‍🏫|🧑🏽‍🏭|🧑🏽‍💻|🧑🏽‍💼|🧑🏽‍🔧|🧑🏽‍🔬|🧑🏽‍🚀|🧑🏽‍🚒|🧑🏽‍🦯|🧑🏽‍🦰|🧑🏽‍🦱|🧑🏽‍🦲|🧑🏽‍🦳|🧑🏽‍🦼|🧑🏽‍🦽|🧑🏽‍🩰|🧑🏾‍⚕️|🧑🏾‍⚖️|🧑🏾‍✈️|🧑🏾‍🌾|🧑🏾‍🍳|🧑🏾‍🍼|🧑🏾‍🎄|🧑🏾‍🎓|🧑🏾‍🎤|🧑🏾‍🎨|🧑🏾‍🏫|🧑🏾‍🏭|🧑🏾‍💻|🧑🏾‍💼|🧑🏾‍🔧|🧑🏾‍🔬|🧑🏾‍🚀|🧑🏾‍🚒|🧑🏾‍🦯|🧑🏾‍🦰|🧑🏾‍🦱|🧑🏾‍🦲|🧑🏾‍🦳|🧑🏾‍🦼|🧑🏾‍🦽|🧑🏾‍🩰|🧑🏿‍⚕️|🧑🏿‍⚖️|🧑🏿‍✈️|🧑🏿‍🌾|🧑🏿‍🍳|🧑🏿‍🍼|🧑🏿‍🎄|🧑🏿‍🎓|🧑🏿‍🎤|🧑🏿‍🎨|🧑🏿‍🏫|🧑🏿‍🏭|🧑🏿‍💻|🧑🏿‍💼|🧑🏿‍🔧|🧑🏿‍🔬|🧑🏿‍🚀|🧑🏿‍🚒|🧑🏿‍🦯|🧑🏿‍🦰|🧑🏿‍🦱|🧑🏿‍🦲|🧑🏿‍🦳|🧑🏿‍🦼|🧑🏿‍🦽|🧑🏿‍🩰|🧔🏻‍♀️|🧔🏻‍♂️|🧔🏼‍♀️|🧔🏼‍♂️|🧔🏽‍♀️|🧔🏽‍♂️|🧔🏾‍♀️|🧔🏾‍♂️|🧔🏿‍♀️|🧔🏿‍♂️|🧖🏻‍♀️|🧖🏻‍♂️|🧖🏼‍♀️|🧖🏼‍♂️|🧖🏽‍♀️|🧖🏽‍♂️|🧖🏾‍♀️|🧖🏾‍♂️|🧖🏿‍♀️|🧖🏿‍♂️|🧗🏻‍♀️|🧗🏻‍♂️|🧗🏼‍♀️|🧗🏼‍♂️|🧗🏽‍♀️|🧗🏽‍♂️|🧗🏾‍♀️|🧗🏾‍♂️|🧗🏿‍♀️|🧗🏿‍♂️|🧘🏻‍♀️|🧘🏻‍♂️|🧘🏼‍♀️|🧘🏼‍♂️|🧘🏽‍♀️|🧘🏽‍♂️|🧘🏾‍♀️|🧘🏾‍♂️|🧘🏿‍♀️|🧘🏿‍♂️|🧙🏻‍♀️|🧙🏻‍♂️|🧙🏼‍♀️|🧙🏼‍♂️|🧙🏽‍♀️|🧙🏽‍♂️|🧙🏾‍♀️|🧙🏾‍♂️|🧙🏿‍♀️|🧙🏿‍♂️|🧚🏻‍♀️|🧚🏻‍♂️|🧚🏼‍♀️|🧚🏼‍♂️|🧚🏽‍♀️|🧚🏽‍♂️|🧚🏾‍♀️|🧚🏾‍♂️|🧚🏿‍♀️|🧚🏿‍♂️|🧛🏻‍♀️|🧛🏻‍♂️|🧛🏼‍♀️|🧛🏼‍♂️|🧛🏽‍♀️|🧛🏽‍♂️|🧛🏾‍♀️|🧛🏾‍♂️|🧛🏿‍♀️|🧛🏿‍♂️|🧜🏻‍♀️|🧜🏻‍♂️|🧜🏼‍♀️|🧜🏼‍♂️|🧜🏽‍♀️|🧜🏽‍♂️|🧜🏾‍♀️|🧜🏾‍♂️|🧜🏿‍♀️|🧜🏿‍♂️|🧝🏻‍♀️|🧝🏻‍♂️|🧝🏼‍♀️|🧝🏼‍♂️|🧝🏽‍♀️|🧝🏽‍♂️|🧝🏾‍♀️|🧝🏾‍♂️|🧝🏿‍♀️|🧝🏿‍♂️|⛹🏻‍♀️|⛹🏻‍♂️|⛹🏼‍♀️|⛹🏼‍♂️|⛹🏽‍♀️|⛹🏽‍♂️|⛹🏾‍♀️|⛹🏾‍♂️|⛹🏿‍♀️|⛹🏿‍♂️|🏋️‍♀️|🏋️‍♂️|🏌️‍♀️|🏌️‍♂️|🏳️‍⚧️|🏳️‍🌈|🕵️‍♀️|🕵️‍♂️|😶‍🌫️|⛓️‍💥|⛹️‍♀️|⛹️‍♂️|❤️‍🔥|❤️‍🩹|🍄‍🟫|🍋‍🟩|🏃‍♀️|🏃‍♂️|🏃‍➡️|🏄‍♀️|🏄‍♂️|🏊‍♀️|🏊‍♂️|🏴‍☠️|🐕‍🦺|🐦‍🔥|🐻‍❄️|👨‍⚕️|👨‍⚖️|👨‍✈️|👨‍🌾|👨‍🍳|👨‍🍼|👨‍🎓|👨‍🎤|👨‍🎨|👨‍🏫|👨‍🏭|👨‍👦|👨‍👧|👨‍💻|👨‍💼|👨‍🔧|👨‍🔬|👨‍🚀|👨‍🚒|👨‍🦯|👨‍🦰|👨‍🦱|👨‍🦲|👨‍🦳|👨‍🦼|👨‍🦽|👩‍⚕️|👩‍⚖️|👩‍✈️|👩‍🌾|👩‍🍳|👩‍🍼|👩‍🎓|👩‍🎤|👩‍🎨|👩‍🏫|👩‍🏭|👩‍👦|👩‍👧|👩‍💻|👩‍💼|👩‍🔧|👩‍🔬|👩‍🚀|👩‍🚒|👩‍🦯|👩‍🦰|👩‍🦱|👩‍🦲|👩‍🦳|👩‍🦼|👩‍🦽|👮‍♀️|👮‍♂️|👯‍♀️|👯‍♂️|👰‍♀️|👰‍♂️|👱‍♀️|👱‍♂️|👳‍♀️|👳‍♂️|👷‍♀️|👷‍♂️|💁‍♀️|💁‍♂️|💂‍♀️|💂‍♂️|💆‍♀️|💆‍♂️|💇‍♀️|💇‍♂️|😮‍💨|😵‍💫|🙂‍↔️|🙂‍↕️|🙅‍♀️|🙅‍♂️|🙆‍♀️|🙆‍♂️|🙇‍♀️|🙇‍♂️|🙋‍♀️|🙋‍♂️|🙍‍♀️|🙍‍♂️|🙎‍♀️|🙎‍♂️|🚣‍♀️|🚣‍♂️|🚴‍♀️|🚴‍♂️|🚵‍♀️|🚵‍♂️|🚶‍♀️|🚶‍♂️|🚶‍➡️|🤦‍♀️|🤦‍♂️|🤵‍♀️|🤵‍♂️|🤷‍♀️|🤷‍♂️|🤸‍♀️|🤸‍♂️|🤹‍♀️|🤹‍♂️|🤼‍♀️|🤼‍♂️|🤽‍♀️|🤽‍♂️|🤾‍♀️|🤾‍♂️|🦸‍♀️|🦸‍♂️|🦹‍♀️|🦹‍♂️|🧍‍♀️|🧍‍♂️|🧎‍♀️|🧎‍♂️|🧎‍➡️|🧏‍♀️|🧏‍♂️|🧑‍⚕️|🧑‍⚖️|🧑‍✈️|🧑‍🌾|🧑‍🍳|🧑‍🍼|🧑‍🎄|🧑‍🎓|🧑‍🎤|🧑‍🎨|🧑‍🏫|🧑‍🏭|🧑‍💻|🧑‍💼|🧑‍🔧|🧑‍🔬|🧑‍🚀|🧑‍🚒|🧑‍🦯|🧑‍🦰|🧑‍🦱|🧑‍🦲|🧑‍🦳|🧑‍🦼|🧑‍🦽|🧑‍🧒|🧑‍🩰|🧔‍♀️|🧔‍♂️|🧖‍♀️|🧖‍♂️|🧗‍♀️|🧗‍♂️|🧘‍♀️|🧘‍♂️|🧙‍♀️|🧙‍♂️|🧚‍♀️|🧚‍♂️|🧛‍♀️|🧛‍♂️|🧜‍♀️|🧜‍♂️|🧝‍♀️|🧝‍♂️|🧞‍♀️|🧞‍♂️|🧟‍♀️|🧟‍♂️|\*️⃣|🇦🇨|🇦🇩|🇦🇪|🇦🇫|🇦🇬|🇦🇮|🇦🇱|🇦🇲|🇦🇴|🇦🇶|🇦🇷|🇦🇸|🇦🇹|🇦🇺|🇦🇼|🇦🇽|🇦🇿|🇧🇦|🇧🇧|🇧🇩|🇧🇪|🇧🇫|🇧🇬|🇧🇭|🇧🇮|🇧🇯|🇧🇱|🇧🇲|🇧🇳|🇧🇴|🇧🇶|🇧🇷|🇧🇸|🇧🇹|🇧🇻|🇧🇼|🇧🇾|🇧🇿|🇨🇦|🇨🇨|🇨🇩|🇨🇫|🇨🇬|🇨🇭|🇨🇮|🇨🇰|🇨🇱|🇨🇲|🇨🇳|🇨🇴|🇨🇵|🇨🇶|🇨🇷|🇨🇺|🇨🇻|🇨🇼|🇨🇽|🇨🇾|🇨🇿|🇩🇪|🇩🇬|🇩🇯|🇩🇰|🇩🇲|🇩🇴|🇩🇿|🇪🇦|🇪🇨|🇪🇪|🇪🇬|🇪🇭|🇪🇷|🇪🇸|🇪🇹|🇪🇺|🇫🇮|🇫🇯|🇫🇰|🇫🇲|🇫🇴|🇫🇷|🇬🇦|🇬🇧|🇬🇩|🇬🇪|🇬🇫|🇬🇬|🇬🇭|🇬🇮|🇬🇱|🇬🇲|🇬🇳|🇬🇵|🇬🇶|🇬🇷|🇬🇸|🇬🇹|🇬🇺|🇬🇼|🇬🇾|🇭🇰|🇭🇲|🇭🇳|🇭🇷|🇭🇹|🇭🇺|🇮🇨|🇮🇩|🇮🇪|🇮🇱|🇮🇲|🇮🇳|🇮🇴|🇮🇶|🇮🇷|🇮🇸|🇮🇹|🇯🇪|🇯🇲|🇯🇴|🇯🇵|🇰🇪|🇰🇬|🇰🇭|🇰🇮|🇰🇲|🇰🇳|🇰🇵|🇰🇷|🇰🇼|🇰🇾|🇰🇿|🇱🇦|🇱🇧|🇱🇨|🇱🇮|🇱🇰|🇱🇷|🇱🇸|🇱🇹|🇱🇺|🇱🇻|🇱🇾|🇲🇦|🇲🇨|🇲🇩|🇲🇪|🇲🇫|🇲🇬|🇲🇭|🇲🇰|🇲🇱|🇲🇲|🇲🇳|🇲🇴|🇲🇵|🇲🇶|🇲🇷|🇲🇸|🇲🇹|🇲🇺|🇲🇻|🇲🇼|🇲🇽|🇲🇾|🇲🇿|🇳🇦|🇳🇨|🇳🇪|🇳🇫|🇳🇬|🇳🇮|🇳🇱|🇳🇴|🇳🇵|🇳🇷|🇳🇺|🇳🇿|🇴🇲|🇵🇦|🇵🇪|🇵🇫|🇵🇬|🇵🇭|🇵🇰|🇵🇱|🇵🇲|🇵🇳|🇵🇷|🇵🇸|🇵🇹|🇵🇼|🇵🇾|🇶🇦|🇷🇪|🇷🇴|🇷🇸|🇷🇺|🇷🇼|🇸🇦|🇸🇧|🇸🇨|🇸🇩|🇸🇪|🇸🇬|🇸🇭|🇸🇮|🇸🇯|🇸🇰|🇸🇱|🇸🇲|🇸🇳|🇸🇴|🇸🇷|🇸🇸|🇸🇹|🇸🇻|🇸🇽|🇸🇾|🇸🇿|🇹🇦|🇹🇨|🇹🇩|🇹🇫|🇹🇬|🇹🇭|🇹🇯|🇹🇰|🇹🇱|🇹🇲|🇹🇳|🇹🇴|🇹🇷|🇹🇹|🇹🇻|🇹🇼|🇹🇿|🇺🇦|🇺🇬|🇺🇲|🇺🇳|🇺🇸|🇺🇾|🇺🇿|🇻🇦|🇻🇨|🇻🇪|🇻🇬|🇻🇮|🇻🇳|🇻🇺|🇼🇫|🇼🇸|🇽🇰|🇾🇪|🇾🇹|🇿🇦|🇿🇲|🇿🇼|🎅🏻|🎅🏼|🎅🏽|🎅🏾|🎅🏿|🏂🏻|🏂🏼|🏂🏽|🏂🏾|🏂🏿|🏃🏻|🏃🏼|🏃🏽|🏃🏾|🏃🏿|🏄🏻|🏄🏼|🏄🏽|🏄🏾|🏄🏿|🏇🏻|🏇🏼|🏇🏽|🏇🏾|🏇🏿|🏊🏻|🏊🏼|🏊🏽|🏊🏾|🏊🏿|🏋🏻|🏋🏼|🏋🏽|🏋🏾|🏋🏿|🏌🏻|🏌🏼|🏌🏽|🏌🏾|🏌🏿|🐈‍⬛|🐦‍⬛|👂🏻|👂🏼|👂🏽|👂🏾|👂🏿|👃🏻|👃🏼|👃🏽|👃🏾|👃🏿|👆🏻|👆🏼|👆🏽|👆🏾|👆🏿|👇🏻|👇🏼|👇🏽|👇🏾|👇🏿|👈🏻|👈🏼|👈🏽|👈🏾|👈🏿|👉🏻|👉🏼|👉🏽|👉🏾|👉🏿|👊🏻|👊🏼|👊🏽|👊🏾|👊🏿|👋🏻|👋🏼|👋🏽|👋🏾|👋🏿|👌🏻|👌🏼|👌🏽|👌🏾|👌🏿|👍🏻|👍🏼|👍🏽|👍🏾|👍🏿|👎🏻|👎🏼|👎🏽|👎🏾|👎🏿|👏🏻|👏🏼|👏🏽|👏🏾|👏🏿|👐🏻|👐🏼|👐🏽|👐🏾|👐🏿|👦🏻|👦🏼|👦🏽|👦🏾|👦🏿|👧🏻|👧🏼|👧🏽|👧🏾|👧🏿|👨🏻|👨🏼|👨🏽|👨🏾|👨🏿|👩🏻|👩🏼|👩🏽|👩🏾|👩🏿|👫🏻|👫🏼|👫🏽|👫🏾|👫🏿|👬🏻|👬🏼|👬🏽|👬🏾|👬🏿|👭🏻|👭🏼|👭🏽|👭🏾|👭🏿|👮🏻|👮🏼|👮🏽|👮🏾|👮🏿|👯🏻|👯🏼|👯🏽|👯🏾|👯🏿|👰🏻|👰🏼|👰🏽|👰🏾|👰🏿|👱🏻|👱🏼|👱🏽|👱🏾|👱🏿|👲🏻|👲🏼|👲🏽|👲🏾|👲🏿|👳🏻|👳🏼|👳🏽|👳🏾|👳🏿|👴🏻|👴🏼|👴🏽|👴🏾|👴🏿|👵🏻|👵🏼|👵🏽|👵🏾|👵🏿|👶🏻|👶🏼|👶🏽|👶🏾|👶🏿|👷🏻|👷🏼|👷🏽|👷🏾|👷🏿|👸🏻|👸🏼|👸🏽|👸🏾|👸🏿|👼🏻|👼🏼|👼🏽|👼🏾|👼🏿|💁🏻|💁🏼|💁🏽|💁🏾|💁🏿|💂🏻|💂🏼|💂🏽|💂🏾|💂🏿|💃🏻|💃🏼|💃🏽|💃🏾|💃🏿|💅🏻|💅🏼|💅🏽|💅🏾|💅🏿|💆🏻|💆🏼|💆🏽|💆🏾|💆🏿|💇🏻|💇🏼|💇🏽|💇🏾|💇🏿|💏🏻|💏🏼|💏🏽|💏🏾|💏🏿|💑🏻|💑🏼|💑🏽|💑🏾|💑🏿|💪🏻|💪🏼|💪🏽|💪🏾|💪🏿|🕴🏻|🕴🏼|🕴🏽|🕴🏾|🕴🏿|🕵🏻|🕵🏼|🕵🏽|🕵🏾|🕵🏿|🕺🏻|🕺🏼|🕺🏽|🕺🏾|🕺🏿|🖐🏻|🖐🏼|🖐🏽|🖐🏾|🖐🏿|🖕🏻|🖕🏼|🖕🏽|🖕🏾|🖕🏿|🖖🏻|🖖🏼|🖖🏽|🖖🏾|🖖🏿|🙅🏻|🙅🏼|🙅🏽|🙅🏾|🙅🏿|🙆🏻|🙆🏼|🙆🏽|🙆🏾|🙆🏿|🙇🏻|🙇🏼|🙇🏽|🙇🏾|🙇🏿|🙋🏻|🙋🏼|🙋🏽|🙋🏾|🙋🏿|🙌🏻|🙌🏼|🙌🏽|🙌🏾|🙌🏿|🙍🏻|🙍🏼|🙍🏽|🙍🏾|🙍🏿|🙎🏻|🙎🏼|🙎🏽|🙎🏾|🙎🏿|🙏🏻|🙏🏼|🙏🏽|🙏🏾|🙏🏿|🚣🏻|🚣🏼|🚣🏽|🚣🏾|🚣🏿|🚴🏻|🚴🏼|🚴🏽|🚴🏾|🚴🏿|🚵🏻|🚵🏼|🚵🏽|🚵🏾|🚵🏿|🚶🏻|🚶🏼|🚶🏽|🚶🏾|🚶🏿|🛀🏻|🛀🏼|🛀🏽|🛀🏾|🛀🏿|🛌🏻|🛌🏼|🛌🏽|🛌🏾|🛌🏿|🤌🏻|🤌🏼|🤌🏽|🤌🏾|🤌🏿|🤏🏻|🤏🏼|🤏🏽|🤏🏾|🤏🏿|🤘🏻|🤘🏼|🤘🏽|🤘🏾|🤘🏿|🤙🏻|🤙🏼|🤙🏽|🤙🏾|🤙🏿|🤚🏻|🤚🏼|🤚🏽|🤚🏾|🤚🏿|🤛🏻|🤛🏼|🤛🏽|🤛🏾|🤛🏿|🤜🏻|🤜🏼|🤜🏽|🤜🏾|🤜🏿|🤝🏻|🤝🏼|🤝🏽|🤝🏾|🤝🏿|🤞🏻|🤞🏼|🤞🏽|🤞🏾|🤞🏿|🤟🏻|🤟🏼|🤟🏽|🤟🏾|🤟🏿|🤦🏻|🤦🏼|🤦🏽|🤦🏾|🤦🏿|🤰🏻|🤰🏼|🤰🏽|🤰🏾|🤰🏿|🤱🏻|🤱🏼|🤱🏽|🤱🏾|🤱🏿|🤲🏻|🤲🏼|🤲🏽|🤲🏾|🤲🏿|🤳🏻|🤳🏼|🤳🏽|🤳🏾|🤳🏿|🤴🏻|🤴🏼|🤴🏽|🤴🏾|🤴🏿|🤵🏻|🤵🏼|🤵🏽|🤵🏾|🤵🏿|🤶🏻|🤶🏼|🤶🏽|🤶🏾|🤶🏿|🤷🏻|🤷🏼|🤷🏽|🤷🏾|🤷🏿|🤸🏻|🤸🏼|🤸🏽|🤸🏾|🤸🏿|🤹🏻|🤹🏼|🤹🏽|🤹🏾|🤹🏿|🤼🏻|🤼🏼|🤼🏽|🤼🏾|🤼🏿|🤽🏻|🤽🏼|🤽🏽|🤽🏾|🤽🏿|🤾🏻|🤾🏼|🤾🏽|🤾🏾|🤾🏿|🥷🏻|🥷🏼|🥷🏽|🥷🏾|🥷🏿|🦵🏻|🦵🏼|🦵🏽|🦵🏾|🦵🏿|🦶🏻|🦶🏼|🦶🏽|🦶🏾|🦶🏿|🦸🏻|🦸🏼|🦸🏽|🦸🏾|🦸🏿|🦹🏻|🦹🏼|🦹🏽|🦹🏾|🦹🏿|🦻🏻|🦻🏼|🦻🏽|🦻🏾|🦻🏿|🧍🏻|🧍🏼|🧍🏽|🧍🏾|🧍🏿|🧎🏻|🧎🏼|🧎🏽|🧎🏾|🧎🏿|🧏🏻|🧏🏼|🧏🏽|🧏🏾|🧏🏿|🧑🏻|🧑🏼|🧑🏽|🧑🏾|🧑🏿|🧒🏻|🧒🏼|🧒🏽|🧒🏾|🧒🏿|🧓🏻|🧓🏼|🧓🏽|🧓🏾|🧓🏿|🧔🏻|🧔🏼|🧔🏽|🧔🏾|🧔🏿|🧕🏻|🧕🏼|🧕🏽|🧕🏾|🧕🏿|🧖🏻|🧖🏼|🧖🏽|🧖🏾|🧖🏿|🧗🏻|🧗🏼|🧗🏽|🧗🏾|🧗🏿|🧘🏻|🧘🏼|🧘🏽|🧘🏾|🧘🏿|🧙🏻|🧙🏼|🧙🏽|🧙🏾|🧙🏿|🧚🏻|🧚🏼|🧚🏽|🧚🏾|🧚🏿|🧛🏻|🧛🏼|🧛🏽|🧛🏾|🧛🏿|🧜🏻|🧜🏼|🧜🏽|🧜🏾|🧜🏿|🧝🏻|🧝🏼|🧝🏽|🧝🏾|🧝🏿|🫃🏻|🫃🏼|🫃🏽|🫃🏾|🫃🏿|🫄🏻|🫄🏼|🫄🏽|🫄🏾|🫄🏿|🫅🏻|🫅🏼|🫅🏽|🫅🏾|🫅🏿|🫰🏻|🫰🏼|🫰🏽|🫰🏾|🫰🏿|🫱🏻|🫱🏼|🫱🏽|🫱🏾|🫱🏿|🫲🏻|🫲🏼|🫲🏽|🫲🏾|🫲🏿|🫳🏻|🫳🏼|🫳🏽|🫳🏾|🫳🏿|🫴🏻|🫴🏼|🫴🏽|🫴🏾|🫴🏿|🫵🏻|🫵🏼|🫵🏽|🫵🏾|🫵🏿|🫶🏻|🫶🏼|🫶🏽|🫶🏾|🫶🏿|🫷🏻|🫷🏼|🫷🏽|🫷🏾|🫷🏿|🫸🏻|🫸🏼|🫸🏽|🫸🏾|🫸🏿|#️⃣|0️⃣|1️⃣|2️⃣|3️⃣|4️⃣|5️⃣|6️⃣|7️⃣|8️⃣|9️⃣|☝🏻|☝🏼|☝🏽|☝🏾|☝🏿|⛹🏻|⛹🏼|⛹🏽|⛹🏾|⛹🏿|✊🏻|✊🏼|✊🏽|✊🏾|✊🏿|✋🏻|✋🏼|✋🏽|✋🏾|✋🏿|✌🏻|✌🏼|✌🏽|✌🏾|✌🏿|✍🏻|✍🏼|✍🏽|✍🏾|✍🏿|🅰️|🅱️|🅾️|🅿️|🈂️|🈷️|🌡️|🌤️|🌥️|🌦️|🌧️|🌨️|🌩️|🌪️|🌫️|🌬️|🌶️|🍽️|🎖️|🎗️|🎙️|🎚️|🎛️|🎞️|🎟️|🏋️|🏌️|🏍️|🏎️|🏔️|🏕️|🏖️|🏗️|🏘️|🏙️|🏚️|🏛️|🏜️|🏝️|🏞️|🏟️|🏳️|🏵️|🏷️|🐿️|👁️|📽️|🕉️|🕊️|🕯️|🕰️|🕳️|🕴️|🕵️|🕶️|🕷️|🕸️|🕹️|🖇️|🖊️|🖋️|🖌️|🖍️|🖐️|🖥️|🖨️|🖱️|🖲️|🖼️|🗂️|🗃️|🗄️|🗑️|🗒️|🗓️|🗜️|🗝️|🗞️|🗡️|🗣️|🗨️|🗯️|🗳️|🗺️|🛋️|🛍️|🛎️|🛏️|🛠️|🛡️|🛢️|🛣️|🛤️|🛥️|🛩️|🛰️|🛳️|©️|®️|‼️|⁉️|™️|ℹ️|↔️|↕️|↖️|↗️|↘️|↙️|↩️|↪️|⌨️|⏏️|⏭️|⏮️|⏯️|⏱️|⏲️|⏸️|⏹️|⏺️|Ⓜ️|▪️|▫️|▶️|◀️|◻️|◼️|☀️|☁️|☂️|☃️|☄️|☎️|☑️|☘️|☝️|☠️|☢️|☣️|☦️|☪️|☮️|☯️|☸️|☹️|☺️|♀️|♂️|♟️|♠️|♣️|♥️|♦️|♨️|♻️|♾️|⚒️|⚔️|⚕️|⚖️|⚗️|⚙️|⚛️|⚜️|⚠️|⚧️|⚰️|⚱️|⛈️|⛏️|⛑️|⛓️|⛩️|⛰️|⛱️|⛴️|⛷️|⛸️|⛹️|✂️|✈️|✉️|✌️|✍️|✏️|✒️|✔️|✖️|✝️|✡️|✳️|✴️|❄️|❇️|❣️|❤️|➡️|⤴️|⤵️|⬅️|⬆️|⬇️|〰️|〽️|㊗️|㊙️|[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55\u{1F004}\u{1F0CF}\u{1F18E}\u{1F191}-\u{1F19A}\u{1F201}\u{1F21A}\u{1F22F}\u{1F232}-\u{1F236}\u{1F238}-\u{1F23A}\u{1F250}\u{1F251}\u{1F300}-\u{1F320}\u{1F32D}-\u{1F335}\u{1F337}-\u{1F37C}\u{1F37E}-\u{1F393}\u{1F3A0}-\u{1F3CA}\u{1F3CF}-\u{1F3D3}\u{1F3E0}-\u{1F3F0}\u{1F3F4}\u{1F3F8}-\u{1F43E}\u{1F440}\u{1F442}-\u{1F4FC}\u{1F4FF}-\u{1F53D}\u{1F54B}-\u{1F54E}\u{1F550}-\u{1F567}\u{1F57A}\u{1F595}\u{1F596}\u{1F5A4}\u{1F5FB}-\u{1F64F}\u{1F680}-\u{1F6C5}\u{1F6CC}\u{1F6D0}-\u{1F6D2}\u{1F6D5}-\u{1F6D8}\u{1F6DC}-\u{1F6DF}\u{1F6EB}\u{1F6EC}\u{1F6F4}-\u{1F6FC}\u{1F7E0}-\u{1F7EB}\u{1F7F0}\u{1F90C}-\u{1F93A}\u{1F93C}-\u{1F945}\u{1F947}-\u{1F9FF}\u{1FA70}-\u{1FA7C}\u{1FA80}-\u{1FA8A}\u{1FA8E}-\u{1FAC6}\u{1FAC8}\u{1FACD}-\u{1FADC}\u{1FADF}-\u{1FAEA}\u{1FAEF}-\u{1FAF8}])/gu).length):m=(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)("i",{className:"material-icons gray",children:"warning_amber"})," ",(0,c.jsx)("i",{className:"gray",children:(0,c.jsx)(a.FormattedMessage,{id:"invalid_content",defaultMessage:"invalid content",description:"Shown when the message is unreadable"})})]});return(0,c.jsxs)("li",{ref:this.props.innerRef,className:e,children:[this.props.selectMode?(0,c.jsx)("i",{className:"material-icons select-checkbox"+(this.props.selected?" blue":""),onClick:()=>this.props.onToggleSelect(this.props.seq),children:this.props.selected?"check_circle":"radio_button_unchecked"}):null,this.props.isGroup&&this.props.response?(0,c.jsx)("div",{className:"avatar-box",children:p?(0,c.jsx)(v.A,{authorizeURL:this.props.tinode.authorizeURL,topic:this.props.userFrom,title:this.props.userName,avatar:s}):null}):null,i&&r?(0,c.jsx)("i",{className:"material-icons red message-fail-icon",children:"error"}):null,(0,c.jsxs)("div",{children:[(0,c.jsxs)("div",{className:t,children:[h?(0,c.jsx)("i",{className:"voice-unread-dot"}):null,(0,c.jsxs)("div",{className:"content-meta",children:[(0,c.jsxs)("div",{className:d,children:[g||m,b]}),this.props.timestamp?(0,c.jsx)(y,{edited:this.props.edited,timestamp:this.props.timestamp,received:this.props.received}):null]}),this.props.showContextMenu&&!this.props.selectMode?(0,c.jsx)("span",{className:"menuTrigger",children:(0,c.jsx)("a",{href:"#",onClick:this.handleContextClick,children:(0,c.jsx)("i",{className:"material-icons",children:"expand_more"})})}):null]}),r,p?(0,c.jsxs)("div",{className:"author",children:[this.props.userName||(0,c.jsx)("i",{children:(0,c.jsx)(a.FormattedMessage,{id:"user_not_found",defaultMessage:"Not found",description:"In place of a user's full name when the user is not found."})}),"owner"==this.props.senderRole?(0,c.jsx)("em",{className:"role-badge owner",children:"群主"}):"admin"==this.props.senderRole?(0,c.jsx)("em",{className:"role-badge admin",children:"管理员"}):null]}):null]})]})}}const _=(0,a.injectIntl)(j);var A=n().forwardRef((e,t)=>(0,c.jsx)(_,{innerRef:t,...e})),P=s(6565),T=s(3405),D=s(3272),E=s(7981);class k extends n().Component{constructor(e){super(e)}render(){const e=[],t=(this.props.subscribers||[]).length,s=Math.min(4,t);return(this.props.subscribers||[]).some(t=>(e.push((0,c.jsx)("div",{className:"avatar-box",children:(0,c.jsx)(v.A,{authorizeURL:this.props.tinode.authorizeURL,topic:t.user,avatar:(0,E.to)(t.public?t.public.photo:null)||!0,title:t.public?t.public.fn:null})},t.user)),e.length==s)),0==e.length?null:(0,c.jsxs)("div",{id:"topic-users",children:[e," ",t>s?(0,c.jsx)("span",{children:(0,c.jsx)(a.FormattedMessage,{id:"more_online_members",defaultMessage:"+{overflow} more",description:"Shown in MessagesView title bar when the number of online subscribers exceeds MAX_ONLINE_IN_TOPIC",values:{overflow:t-s}})}):null]})}}class F extends n().PureComponent{constructor(e){super(e),this.handleButtonAction=this.handleButtonAction.bind(this)}handleButtonAction(e,t){e.preventDefault(),this.props.onAction(t)}render(){return(0,c.jsxs)("div",{className:"accept-invite-panel",children:[(0,c.jsx)("div",{className:"title",children:(0,c.jsx)(a.FormattedMessage,{id:"chat_invitation",defaultMessage:"You are invited to start a new chat. What would you like to do?",description:"New chat invitation message: [Accept] [Ignore] [Block]."})}),(0,c.jsxs)("div",{className:"footer",children:[(0,c.jsx)("button",{className:"primary",onClick:e=>{this.handleButtonAction(e,"accept")},children:(0,c.jsx)(a.FormattedMessage,{id:"chat_invitation_accept",defaultMessage:"Accept",description:"Action [Accept] for chat invitation."})}),(0,c.jsx)("button",{className:"secondary",onClick:e=>{this.handleButtonAction(e,"delete")},children:(0,c.jsx)(a.FormattedMessage,{id:"chat_invitation_ignore",defaultMessage:"Ignore",description:"Action [Ignore] for chat invitation."})}),(0,c.jsx)("button",{className:"secondary",onClick:e=>{this.handleButtonAction(e,"block")},children:(0,c.jsx)(a.FormattedMessage,{id:"chat_invitation_block",defaultMessage:"Block",description:"Action [Block] for chat invitation."})})]})]})}}var R=s(9304);function N({children:e}){return(0,c.jsx)("i",{className:"material-icons","aria-hidden":"true",children:e})}class I extends n().PureComponent{render(){return(0,c.jsx)("div",{id:"dummy-view",children:(0,c.jsxs)("div",{children:[(0,c.jsx)("span",{id:"dummy-view-icon",children:(0,c.jsx)(N,{children:"forum"})}),(0,c.jsx)("h2",{children:D.iv}),(0,c.jsx)("p",{children:"选择一个会话开始聊天"})]})})}}class U extends n().PureComponent{constructor(e){super(e)}render(){let e=null,t="bubble";return this.props.date?(e=(0,c.jsx)(c.Fragment,{children:this.props.date}),t+=" date"):this.props.deleted&&(e=(0,c.jsx)("i",{className:"gray",children:this.props.deletedText||"消息已删除"}),t+=" deleted"),e?(0,c.jsx)("li",{className:"meta",children:(0,c.jsx)("div",{className:t,children:(0,c.jsx)("div",{className:"message-content",children:e})})}):(0,c.jsx)(c.Fragment,{children:null})}}const L=(0,a.defineMessages)({message_not_found:{id:"message_not_found",defaultMessage:"message not found",description:"Pinned message is not found"},message_deleted:{id:"message_deleted",defaultMessage:"message deleted",description:"Pinned message is deleted"}});class q extends n().PureComponent{constructor(e){super(e),this.touchX=null,this.touchY=null,this.touchSurface=n().createRef(),this.getSelectedIndex=this.getSelectedIndex.bind(this),this.handleCancel=this.handleCancel.bind(this),this.handleSelected=this.handleSelected.bind(this),this.handleMoveNext=this.handleMoveNext.bind(this),this.handleMovePrev=this.handleMovePrev.bind(this),this.handleTouchEventStart=this.handleTouchEventStart.bind(this),this.handleTouchEventEnd=this.handleTouchEventEnd.bind(this),this.handleTouchCancel=this.handleTouchCancel.bind(this)}componentDidMount(){this.touchSurface.current.addEventListener("touchstart",this.handleTouchEventStart,{passive:!0}),this.touchSurface.current.addEventListener("touchend",this.handleTouchEventEnd,{passive:!0}),this.touchSurface.current.addEventListener("touchcancel",this.handleTouchCancel,{passive:!0})}componentWillUnmount(){this.touchSurface.current.removeEventListener("touchstart",this.handleTouchEventStart),this.touchSurface.current.removeEventListener("touchend",this.handleTouchEventEnd),this.touchSurface.current.removeEventListener("touchcancel",this.handleTouchCancel)}getSelectedIndex(){return(this.props.pins||[]).length-this.props.selected-1}handleCancel(e){e.preventDefault(),this.props.onCancel(this.props.pins[this.getSelectedIndex()])}handleSelected(e){e.preventDefault(),this.props.onSelected(this.props.pins[this.getSelectedIndex()])}handleMoveNext(e,t){t||e.preventDefault(),e.stopPropagation();const s=Math.max(this.props.selected-1,0);s!=this.props.selected&&this.props.setSelected(s)}handleMovePrev(e,t){t||e.preventDefault(),e.stopPropagation();const s=Math.min(this.props.selected+1,(this.props.pins||[]).length-1);s!=this.props.selected&&this.props.setSelected(s)}handleTouchEventStart(e){1==e.touches.length&&(this.touchX=e.touches[0].clientX,this.touchY=e.touches[0].clientY)}handleTouchEventEnd(e){if(null===this.touchX||1!=e.changedTouches.length)return void(this.touchX=null);const t=this.touchX-e.changedTouches[0].clientX,s=this.touchY-e.changedTouches[0].clientY;this.touchX=null,Math.abs(t)>Math.abs(s)||Math.abs(s)<39||(s>0?this.handleMovePrev(e,!0):this.handleMoveNext(e,!0))}handleTouchCancel(){this.touchX=null}render(){const e=this.getSelectedIndex();let t=(this.props.messages||[])[e];t=t?t._deleted?(0,c.jsx)("i",{className:"gray",children:this.props.intl.formatMessage(L.message_deleted)}):o.Drafty.format(t.content,x.TU,{formatMessage:this.props.intl.formatMessage.bind(this.props.intl),authorizeURL:this.props.tinode.authorizeURL.bind(this.props.tinode)}):(0,c.jsx)("i",{className:"gray",children:this.props.intl.formatMessage(L.message_not_found)});const s=[];return this.props.pins.forEach(t=>{const i=s.length==e?"adot":"dot";s.push((0,c.jsx)("div",{className:i},t))}),(0,c.jsxs)("div",{id:"pinned-wrapper",ref:this.touchSurface,children:[this.props.isAdmin?(0,c.jsx)("div",{className:"cancel",children:(0,c.jsx)("a",{href:"#",onClick:this.handleCancel,children:(0,c.jsx)("i",{className:"material-icons gray",children:"close"})})}):(0,c.jsx)("div",{children:(0,c.jsx)("i",{className:"material-icons gray",children:"push_pin"})}),(0,c.jsx)("div",{className:"pinned-scroll",children:s}),(0,c.jsx)("div",{className:"pinned",onClick:this.handleSelected,children:(0,c.jsx)("p",{children:t})}),(0,c.jsxs)("div",{className:"pinned-menu",children:[(0,c.jsx)("span",{className:"menuTrigger upper",children:e>0?(0,c.jsx)("a",{href:"#",onClick:this.handleMovePrev,children:(0,c.jsx)("i",{className:"material-icons",children:"expand_less"})}):null}),(0,c.jsx)("span",{className:"menuTrigger lower",children:this.props.selected>0?(0,c.jsx)("a",{href:"#",onClick:this.handleMoveNext,children:(0,c.jsx)("i",{className:"material-icons",children:"expand_more"})}):null})]})]})}}var z=(0,a.injectIntl)(q),O=s(781),V=s(5372);const H=n().lazy(e=>s.e(821).then(s.bind(s,7821))),B=n().lazy(e=>s.e(623).then(s.bind(s,1623))),Q=n().lazy(e=>s.e(534).then(s.bind(s,8534))),G=n().lazy(e=>Promise.all([s.e(892),s.e(803)]).then(s.bind(s,4803))),W=n().lazy(e=>s.e(592).then(s.bind(s,4592))),J=(0,a.defineMessages)({message_deleted:{id:"message_deleted",defaultMessage:"message deleted",description:"Placeholder shown in the timeline where a message was recalled or deleted"},online_now:{id:"online_now",defaultMessage:"online now",description:"Indicator that the user or topic is currently online"},last_seen:{id:"last_seen_timestamp",defaultMessage:"Last seen: {timestamp}",description:"Label for the timestamp of when the user or topic was last online"},not_found:{id:"title_not_found",defaultMessage:"Not found",description:"Title shown when topic is not found"},channel:{id:"channel",defaultMessage:"channel",description:"Subtitle shown for channels in MessagesView instead of last seen"},file_attachment_too_large:{id:"file_attachment_too_large",defaultMessage:"The file size {size} exceeds the {limit} limit.",description:"Error message when attachment is too large"},invalid_content:{id:"invalid_content",defaultMessage:"invalid content",description:"Shown when the message is unreadable"},editing_message:{id:"editing_message",defaultMessage:"Editing",description:"Title over message editing preview"},drag_file:{id:"drag_file",defaultMessage:"Drag file here",description:"Prompt on the file drag-n-drop overlay banner"},self_topic_name:{id:"self_topic_name",defaultMessage:"Saved messages",description:"Name of self topic for UI"},subscriber_count:{id:"subscriber_count",defaultMessage:"{count, plural, one {{count, number} subscriber} two {{count, number} subscribers} three {{count, number} subscribers} few {{count, number} subscribers} many {{count, number} subscribers} other {{count, number} subscribers}}",description:"Count of channel subscribers"},member_count:{id:"member_count",defaultMessage:"{count, plural, one {{count, number} member} two {{count, number} members} three {{count, number} members} few {{count, number} members} many {{count, number} members} other {{count, number} members}}",description:"Count of group topic members"},cannot_parse_vcard:{id:"cannot_parse_vcard",defaultMessage:"Cannot parse vCard file.",description:"Error message when vCard file cannot be parsed"}});function K(e){if(e){const t=e.getExcessive()||"";return e.isJoiner("given")&&(t.includes("R")||t.includes("W"))}return!1}function Y(e){if(e){const t=e.getMissing()||"";return e.isJoiner("want")&&(t.includes("R")||t.includes("W"))}return!1}const X="__mention_all__";function $(e){return 1==e||3==e}class Z extends n().Component{constructor(e){super(e),this.state=Z.getDerivedStateFromProps(e,{}),this.state.messagePolicy=null,this.state.toast=null,this.state.riskDialog=null,this.mentionedUsers=[],this.mentionAllPending=!1,this.componentSetup=this.componentSetup.bind(this),this.leave=this.leave.bind(this),this.sendMessage=this.sendMessage.bind(this),this.handleRiskConfirm=this.handleRiskConfirm.bind(this),this.handleRiskCancel=this.handleRiskCancel.bind(this),this.retrySend=this.retrySend.bind(this),this.sendImageAttachment=this.sendImageAttachment.bind(this),this.sendVideoAttachment=this.sendVideoAttachment.bind(this),this.sendFileAttachment=this.sendFileAttachment.bind(this),this.sendAudioAttachment=this.sendAudioAttachment.bind(this),this.sendTheCardAttachment=this.sendTheCardAttachment.bind(this),this.sendKeyPress=this.sendKeyPress.bind(this),this.subscribe=this.subscribe.bind(this),this.handleScrollReference=this.handleScrollReference.bind(this),this.mountDnDEvents=this.mountDnDEvents.bind(this),this.handleScrollEvent=this.handleScrollEvent.bind(this),this.handleDescChange=this.handleDescChange.bind(this),this.handleSubsUpdated=this.handleSubsUpdated.bind(this),this.handleMessageUpdate=this.handleMessageUpdate.bind(this),this.handleAuxUpdate=this.handleAuxUpdate.bind(this),this.handleAllMessagesReceived=this.handleAllMessagesReceived.bind(this),this.handleInfoReceipt=this.handleInfoReceipt.bind(this),this.handleExpandMedia=this.handleExpandMedia.bind(this),this.handleClosePreview=this.handleClosePreview.bind(this),this.handleCallPanelToggle=this.handleCallPanelToggle.bind(this),this.handleFormResponse=this.handleFormResponse.bind(this),this.handleContextClick=this.handleContextClick.bind(this),this.handleShowMessageContextMenu=this.handleShowMessageContextMenu.bind(this),this.handleNewChatAcceptance=this.handleNewChatAcceptance.bind(this),this.handleEnablePeer=this.handleEnablePeer.bind(this),this.loadRelationshipContext=this.loadRelationshipContext.bind(this),this.loadGroupContext=this.loadGroupContext.bind(this),this.loadDraft=this.loadDraft.bind(this),this.handleComposerChange=this.handleComposerChange.bind(this),this.clearDraft=this.clearDraft.bind(this),this.mentionSearch=this.mentionSearch.bind(this),this.mentionSelected=this.mentionSelected.bind(this),this.handleShowAnnouncement=this.handleShowAnnouncement.bind(this),this.handleShowJoinRequests=this.handleShowJoinRequests.bind(this),this.handleSendFriendVerification=this.handleSendFriendVerification.bind(this),this.handleBatchDelete=this.handleBatchDelete.bind(this),this.handleBatchFavorite=this.handleBatchFavorite.bind(this),this.handleAttachFile=this.handleAttachFile.bind(this),this.handleAttachImageOrVideo=this.handleAttachImageOrVideo.bind(this),this.handleCancelUpload=this.handleCancelUpload.bind(this),this.postReadNotification=this.postReadNotification.bind(this),this.clearNotificationQueue=this.clearNotificationQueue.bind(this),this.goToLatestMessage=this.goToLatestMessage.bind(this),this.handleFileDrop=this.handleFileDrop.bind(this),this.handlePickReply=this.handlePickReply.bind(this),this.handleEditMessage=this.handleEditMessage.bind(this),this.handleCancelReply=this.handleCancelReply.bind(this),this.handleQuoteClick=this.handleQuoteClick.bind(this),this.jumpToMessage=this.jumpToMessage.bind(this),this.handleUnpinMessage=this.handleUnpinMessage.bind(this),this.handleCallHangup=this.handleCallHangup.bind(this),this.isDragEnabled=this.isDragEnabled.bind(this),this.handleDragStart=this.handleDragStart.bind(this),this.handleDragIn=this.handleDragIn.bind(this),this.handleDragOut=this.handleDragOut.bind(this),this.handleDrag=this.handleDrag.bind(this),this.handleDrop=this.handleDrop.bind(this),this.chatMessageRefs=[],this.getOrCreateMessageRef=this.getOrCreateMessageRef.bind(this),this.getVisibleMessageRange=this.getVisibleMessageRange.bind(this),this.dragCounter=0,this.dndRef=null,this.readNotificationQueue=[],this.readNotificationTimer=null,this.keyPressTimer=null}getOrCreateMessageRef(e){if(this.chatMessageRefs[e])return this.chatMessageRefs[e];const t=n().createRef();return this.chatMessageRefs[e]=t,t}getVisibleMessageRange(e){let t=Number.MAX_SAFE_INTEGER,s=-1,i=!1;return this.chatMessageRefs.every((n,a)=>{if(n.current){const{top:o,bottom:r,height:l}=n.current.getBoundingClientRect();if(o<=e.top?e.top-o<=l:r-e.bottom<=l)i=!0,t=Math.min(t,a),s=Math.max(s,a);else if(i)return!1}return!0}),s>=t?{min:t,max:s}:{min:0,max:0}}componentDidMount(){this.messagesScroller&&this.messagesScroller.addEventListener("scroll",this.handleScrollEvent),this.mountDnDEvents(this.dndRef),this.componentSetup({},{}),(0,l.Jv)().then(e=>{this.setState({messagePolicy:e.message_policy||null})}).catch(e=>{})}componentWillUnmount(){this.state.rtcPanel&&this.handleCallHangup(this.state.topic,this.props.callSeq),this.messagesScroller&&this.messagesScroller.removeEventListener("scroll",this.handleScrollEvent),window.clearTimeout(this.toastTimer),this.clearNotificationQueue(),this.dndRef&&(this.dndRef.removeEventListener("dragstart",this.handleDragStart),this.dndRef.removeEventListener("dragenter",this.handleDragIn),this.dndRef.removeEventListener("dragleave",this.handleDragOut),this.dndRef.removeEventListener("dragover",this.handleDrag),this.dndRef.removeEventListener("drop",this.handleDrop))}componentDidUpdate(e,t){!this.messagesScroller||t.topic==this.state.topic&&t.maxSeqId==this.state.maxSeqId&&t.minSeqId==this.state.minSeqId||this.state.scrollPosition<100&&(this.messagesScroller.scrollTop=this.messagesScroller.scrollHeight-this.state.scrollPosition-this.messagesScroller.offsetHeight),this.props.applicationVisible?this.postReadNotification(0):this.clearNotificationQueue(),this.props.jumpToSeq&&this.props.jumpToSeq!=e.jumpToSeq&&this.jumpToMessage(parseInt(this.props.jumpToSeq,10)),this.componentSetup(e,t)}componentSetup(e,t){const s=this.props.tinode?this.props.tinode.getTopic(this.state.topic):void 0;if(this.state.topic!=t.topic&&(t.topic&&!o.Tinode.isNewGroupTopicName(t.topic)&&(this.leave(t.topic),t.rtcPanel&&this.handleCallHangup(t.topic,e.callSeq)),s&&(s.onData=this.handleMessageUpdate,s.onAllMessagesReceived=this.handleAllMessagesReceived,s.onInfo=this.handleInfoReceipt,s.onMetaDesc=this.handleDescChange,s.onSubsUpdated=this.handleSubsUpdated,s.onPres=this.handleSubsUpdated,s.onAuxUpdated=this.handleAuxUpdate),this.mentionedUsers=[],this.mentionAllPending=!1,this.loadRelationshipContext(s),this.loadGroupContext(s),this.loadDraft(s)),s)if(this.state.topic!=t.topic||this.props.myUserId&&!e.myUserId){const e=this.props.newTopicParams&&this.props.newTopicParams._topicName==this.props.topic;s.isP2PType()&&e?s.getMeta(s.startMetaQuery().withDesc().build()):this.props.myUserId&&this.subscribe(s)}else s.isSubscribed()&&this.state.isReader&&!t.isReader?s.getMeta(s.startMetaQuery().withLaterData().build()):s.isSubscribed()||!this.props.ready||e.ready||this.subscribe(s)}static getDerivedStateFromProps(e,t){let s={};if(e.topic)if(e.topic!=t.topic){const i=e.tinode.getTopic(e.topic);if(s={topic:e.topic,deleted:i._deleted,docPreview:null,imagePreview:null,imagePostview:null,videoPreview:null,videoPostview:null,rtcPanel:null,minimizedCallPanel:!1,typingIndicator:!1,scrollPosition:0,fetchingMessages:!1,showGoToLastButton:!1,contentToEdit:null,dragging:!1,selectedPin:0,relationshipContext:null,groupRoles:null,myGroupRole:null,groupAnnouncement:null,pendingJoinRequests:0,draftText:null,draftVersion:0,riskDialog:null},e.forwardMessage)if(e.forwardMessage.content){const t=e.forwardMessage.content,i=t?.length||t?.size||0;s.docPreview={object:t,type:e.forwardMessage.type,size:i}}else s.reply={content:e.forwardMessage.preview,seq:null};else s.reply=null;if(i){const n=[];e.connected&&i.subscribers(t=>{t.online&&t.user!=e.myUserId&&n.push(t)}),Object.assign(s,{onlineSubs:n}),i.isSelfType()?Object.assign(s,{title:e.intl.formatMessage(J.self_topic_name),avatar:!0}):i.public?Object.assign(s,{title:(0,d.TP)(i.name,i.public,""),avatar:(0,E.to)(i.public.photo)}):Object.assign(s,{title:"",avatar:null});const a=i.p2pPeerDesc();a?Object.assign(s,{peerMessagingDisabled:Y(a.acs)}):t.peerMessagingDisabled&&Object.assign(s,{peerMessagingDisabled:!1}),Object.assign(s,{minSeqId:i.minMsgSeq(),maxSeqId:i.maxMsgSeq(),latestClearId:i.maxClearId(),channel:i.isChannelType(),pins:(i.aux("pins")||[]).slice(),pinsLoaded:!1}),e.callTopic==i.name&&$(e.callState)&&(s.rtcPanel=e.callTopic)}else Object.assign(s,{minSeqId:-1,maxSeqId:-1,latestClearId:-1,onlineSubs:[],title:"",avatar:null,peerMessagingDisabled:!1,channel:!1,pins:[],pinsLoaded:!1})}else e.callTopic==t.topic&&!t.rtcPanel&&$(e.callState)&&(s.rtcPanel=e.callTopic);else s={minSeqId:-1,maxSeqId:-1,latestClearId:-1,onlineSubs:[],topic:null,title:"",avatar:null,isVerified:!1,isStaff:!1,isDangerous:!1,deleted:!1,docPreview:null,imagePreview:null,imagePostview:null,videoPreview:null,videoPostview:null,rtcPanel:null,minimizedCallPanel:!1,typingIndicator:!1,scrollPosition:0,fetchingMessages:!1,peerMessagingDisabled:!1,channel:!1,reply:null,contentToEdit:null,showGoToLastButton:!1,dragging:!1,pins:[],pinsLoaded:!1,selectedPin:0,subsVersion:0,relationshipContext:null,groupRoles:null,myGroupRole:null,groupAnnouncement:null,pendingJoinRequests:0,draftText:null,draftVersion:0};return e.acs?(e.acs.isWriter()!=t.isWriter&&(s.isWriter=!t.isWriter),e.acs.isReader()!=t.isReader&&(s.isReader=!t.isReader),e.acs.isAdmin()!=t.isAdmin&&(s.isAdmin=!t.isAdmin),!e.acs.isReader("given")!=t.readingBlocked&&(s.readingBlocked=!t.readingBlocked),e.acs.isSharer()!=t.isSharer&&(s.isSharer=!t.isSharer)):(t.isWriter&&(s.isWriter=!1),t.isReader&&(s.isReader=!1),t.isAdmin&&(s.isAdmin=!1),t.readingBlocked||(s.readingBlocked=!0),t.isSharer&&(s.isSharer=!1)),K(e.acs)==!t.unconformed&&(s.unconfirmed=!t.unconformed),!e.connected&&t.onlineSubs&&t.onlineSubs.length>0&&(s.onlineSubs=[]),s}subscribe(e){if(e.isSubscribed()||!this.props.ready)return;const t=this.props.newTopicParams&&this.props.newTopicParams._topicName==this.props.topic;let s=e.startMetaQuery().withLaterDesc().withLaterSub().withAux();(this.state.isReader||t)&&(s=s.withLaterData(24),this.state.isReader&&(s=s.withLaterDel()),this.setState({fetchingMessages:!0}));const i=t?this.props.newTopicParams:void 0;e.subscribe(s.build(),i).then(t=>{if(303==t.code)return void C.A.navigateTo(C.A.setUrlTopic("",t.params.topic));this.state.topic!=t.topic&&this.setState({topic:t.topic}),this.state.deleted&&this.setState({deleted:!1}),this.props.onNewTopicCreated(this.props.topic,t.topic);let s=[];e.queuedMessages(t=>{t._sending||(t._fatal||t.head&&t.head.webrtc?s.push(t.seq):e.isSubscribed()&&this.retrySend(t))}),s.length>0&&e.delMessagesList(s,!0)}).catch(e=>{console.error("Failed subscription to",this.state.topic,e),this.props.onError(e.message,"err");const t=Z.getDerivedStateFromProps({},{});t.title=this.props.intl.formatMessage(J.not_found),this.setState(t)})}leave(e){if(!e||!this.props.tinode.isTopicCached(e))return;const t=this.props.tinode.getTopic(e);t&&t.isSubscribed()&&t.leave(!1).catch(e=>{}).finally(e=>{this.setState({fetchingMessages:!1}),t.onData=void 0,t.onAllMessagesReceived=void 0,t.onInfo=void 0,t.onMetaDesc=void 0,t.onSubsUpdated=void 0,t.onPres=void 0,t.onAuxUpdated=void 0})}handleScrollReference(e){e&&(e.addEventListener("scroll",this.handleScrollEvent),this.messagesScroller=e,this.messagesScroller.scrollTop=this.messagesScroller.scrollHeight-this.state.scrollPosition-this.messagesScroller.offsetHeight)}handleScrollEvent(e){const t=e.target.scrollHeight-e.target.scrollTop-e.target.offsetHeight;if(this.setState({scrollPosition:t,showGoToLastButton:t>100&&t0&&this.setState({fetchingMessages:!0},e=>{t.getMessagesPage(24,n,s,i).catch(e=>this.props.onError(e.message,"err")).finally(e=>this.setState({fetchingMessages:!1}))})}}this.processingScrollEvent=!1}}mountDnDEvents(e){e&&(e.addEventListener("dragstart",this.handleDragStart),e.addEventListener("dragenter",this.handleDragIn),e.addEventListener("dragleave",this.handleDragOut),e.addEventListener("dragover",this.handleDrag),e.addEventListener("drop",this.handleDrop),this.dndRef=e)}goToLatestMessage(){this.setState({scrollPosition:0}),this.messagesScroller&&(this.messagesScroller.scrollTop=this.messagesScroller.scrollHeight-this.messagesScroller.offsetHeight)}handleDescChange(e){o.Tinode.isSelfTopicName(this.props.topic)?this.setState({title:this.props.intl.formatMessage(J.self_topic_name),avatar:!0}):e.public?this.setState({title:(0,d.TP)(this.props.topic,e.public,""),avatar:(0,E.to)(e.public.photo)}):this.setState({title:"",avatar:null}),e.acs&&this.setState({isWriter:e.acs.isWriter(),isReader:e.acs.isReader(),isAdmin:e.acs.isAdmin(),readingBlocked:!e.acs.isReader("given"),unconfirmed:K(e.acs)})}postReadNotification(e){if(!this.props.applicationVisible||!this.state.topic)return;this.readNotificationTimer||(this.readNotificationTimer=setInterval(e=>{if(0==this.readNotificationQueue.length)return clearInterval(this.readNotificationTimer),void(this.readNotificationTimer=null);let t=-1;for(;this.readNotificationQueue.length>0;){const e=this.readNotificationQueue[0];if(e.topicName!=this.state.topic){this.readNotificationQueue.shift();continue}const s=new Date;if(!(e.sendAt<=s))break;this.readNotificationQueue.shift(),(0==e.seq||o.Tinode.isServerAssignedSeq(e.seq))&&(t=Math.max(t,e.seq))}if(t>=0){const e=this.props.tinode.getTopic(this.state.topic);if(e)try{e.noteRead(t)}catch(e){console.error("Failed to send read notification",e)}}},300));const t=new Date;this.readNotificationQueue.push({topicName:this.state.topic,seq:e,sendAt:t.setMilliseconds(t.getMilliseconds()+1500)})}clearNotificationQueue(){this.readNotificationQueue=[],this.readNotificationTimer&&(clearInterval(this.readNotificationTimer),this.readNotificationTimer=null)}handleSubsUpdated(){if(this.state.topic){const e=[],t=this.props.tinode.getTopic(this.state.topic);t.subscribers(t=>{t.online&&t.user!=this.props.myUserId&&e.push(t)});const s={onlineSubs:e,subsVersion:this.state.subsVersion+1},i=t.p2pPeerDesc();i?Object.assign(s,{peerMessagingDisabled:Y(i.acs)}):this.state.peerMessagingDisabled&&Object.assign(s,{peerMessagingDisabled:!1}),this.setState(s)}}handleMessageUpdate(e){if(!this.state.topic)return;const t=this.props.tinode.getTopic(this.state.topic);e?(clearTimeout(this.keyPressTimer),this.setState({maxSeqId:t.maxMsgSeq(),minSeqId:t.minMsgSeq(),typingIndicator:!1},s=>{t.isNewMessage(e.seq)?this.state.scrollPosition>100?this.setState({showGoToLastButton:!0}):this.goToLatestMessage():this.messagesScroller&&(this.messagesScroller.scrollTop=this.messagesScroller.scrollHeight-this.state.scrollPosition-this.messagesScroller.offsetHeight)}),t.msgStatus(e,!0)>=o.Tinode.MESSAGE_STATUS_SENT&&e.from!=this.props.myUserId&&this.postReadNotification(e.seq)):this.setState({latestClearId:t.maxClearId()})}handleAllMessagesReceived(e){if(this.setState({fetchingMessages:!1}),!e){const e=this.props.tinode.getTopic(this.state.topic);return void(e&&this.postReadNotification(e.seq))}if(this.state.pinsLoaded)this.setState({pinsLoaded:!1});else{const e=this.props.tinode.getTopic(this.state.topic);this.setState({pinsLoaded:!0},t=>{e.getPinnedMessages()})}}handleAuxUpdate(e){const t=(e.pins||[]).slice();let s=this.state.selectedPin;t.length>this.state.pins.length?s=0:s>=t.length&&(s=Math.max(0,t.length-1)),this.setState({pins:t,selectedPin:s})}handleInfoReceipt(e){switch(e.what){case"kp":clearTimeout(this.keyPressTimer),this.keyPressTimer=setTimeout(e=>this.setState({typingIndicator:!1}),4e3),this.state.typingIndicator||this.setState({typingIndicator:!0});break;case"read":case"recv":this.forceUpdate();break;default:console.info("Other change in topic: ",e.what)}}handleExpandMedia(e){e&&(e.video?this.setState({videoPostview:e}):this.setState({imagePostview:e}))}handleClosePreview(){this.state.imagePreview&&this.state.imagePreview.url&&URL.revokeObjectURL(this.state.imagePreview.url),this.state.videoPreview&&this.state.videoPreview.url&&URL.revokeObjectURL(this.state.videoPreview.url),this.setState({imagePostview:null,imagePreview:null,docPreview:null,videoPreview:null,videoPostview:null}),this.props.onCancelForwardMessage()}handleFormResponse(e,t,s){if("pub"==e)this.sendMessage(o.Drafty.attachJSON(o.Drafty.parse(t),s));else if("url"==e){const e=new URL(s.ref),t=e.searchParams;for(let e in s.resp)s.resp.hasOwnProperty(e)&&t.set(e,s.resp[e]);["name","seq"].forEach(e=>{s[e]&&t.set(e,s[e])}),t.set("uid",this.props.myUserId),t.set("topic",this.state.topic),e.search=t,window.open(e,"_blank")}else console.info("Unknown action in form",e)}handleContextClick(e){e.preventDefault(),e.stopPropagation(),this.props.showContextMenu({topicName:this.state.topic,y:e.pageY,x:e.pageX})}handleShowMessageContextMenu(e,t){"chan"==e.userFrom&&(e.userFrom=this.state.topic,e.userName=this.state.title),e.topicName=this.state.topic;let s=t||[];this.state.reply&&this.state.reply.editing&&(s=s.filter(e=>"menu_item_reply"!==e));const i=this.props.tinode.getTopic(e.topicName);if(i){const t=this.state.messagePolicy?this.state.messagePolicy.edit_window_seconds:0;!s.includes("menu_item_edit")||t>0&&e.timestamp&&e.timestamp.getTime()>(new Date).getTime()-1e3*t||(s=s.filter(e=>"menu_item_edit"!==e)),s.push("menu_item_copy","menu_item_favorite");const n=this.state.messagePolicy?this.state.messagePolicy.recall_window_seconds:0,a=i.isGroupType()&&i.getAccessMode()&&i.getAccessMode().isAdmin();if((e.userFrom==this.props.myUserId||a)&&e.seq>0&&n>0&&e.timestamp&&e.timestamp.getTime()>(new Date).getTime()-1e3*n&&s.push("menu_item_recall"),i.isSelfType())s.push("message_delete_generic");else{i.isChannelType()||s.push("message_delete");const t=i.getAccessMode();if(t&&t.isDeleter()){let i=t.isOwner();if(!i){const t=0|this.props.tinode.getServerParam(o.Tinode.MSG_DELETE_AGE,0);i=0==t||!!(t>0&&e.timestamp)&&e.timestamp.getTime()>(new Date).getTime()-1e3*t}i&&s.push("message_delete_hard")}}}s.push("menu_item_select"),this.props.showContextMenu(e,s)}handleNewChatAcceptance(e){this.props.onNewChat(this.state.topic,e)}handleEnablePeer(e){e.preventDefault(),this.props.onChangePermissions(this.state.topic,"JRWPS",this.state.topic)}loadRelationshipContext(e){if(!e||!e.isP2PType())return;const t=e.name;(0,l.pl)(t).then(e=>{this.state.topic==t&&this.setState({relationshipContext:e})}).catch(e=>{})}loadGroupContext(e){if(!e||!e.isGroupType()||e.isChannelType())return;const t=e.name;(0,l.Nk)(t).then(e=>{if(this.state.topic!=t)return;const s={};(e.items||[]).forEach(e=>{s[e.user_id]=e.role}),this.setState({groupRoles:s,myGroupRole:s[this.props.myUserId]||null}),"owner"!=s[this.props.myUserId]&&"admin"!=s[this.props.myUserId]||(0,l.s7)(t,"pending").then(e=>{this.state.topic==t&&this.setState({pendingJoinRequests:(e.items||[]).length})}).catch(e=>{})}).catch(e=>{}),(0,l.Yx)(t).then(e=>{this.state.topic==t&&this.setState({groupAnnouncement:e&&e.content?e:null})}).catch(e=>{})}mentionSearch(e){const t=this.props.tinode?this.props.tinode.getTopic(this.state.topic):null;return t&&t.isGroupType()?(0,l.Nk)(this.state.topic,{mentionable:!0,query:e}).then(t=>{const s=t.items||[];return t.permissions&&t.permissions.can_mention_all&&"所有人".includes((e||"").trim())?[{user_id:X,display_name:"所有人"},...s]:s}):Promise.resolve([])}mentionSelected(e,t){e!==X?(this.mentionedUsers=(this.mentionedUsers||[]).filter(e=>e.name!==t),this.mentionedUsers.push({uid:e,name:t})):this.mentionAllPending=!0}loadDraft(e){if(!e)return;const t=e.name;(0,l.V6)(t).then(e=>{this.state.topic==t&&this.setState({draftText:e.content||"",draftVersion:e.version||0})}).catch(e=>{})}handleComposerChange(e){if(this.state.reply&&this.state.reply.editing)return;if(this.props.forwardMessage)return;const t=this.state.topic;if(!t)return;const s=this.state.draftVersion||0;this.draftSaveTimers=this.draftSaveTimers||{},this.draftSaveTimers[t]&&window.clearTimeout(this.draftSaveTimers[t]),this.draftSaveTimers[t]=window.setTimeout(()=>{delete this.draftSaveTimers[t],(0,l.k8)(t,e,[],s).then(e=>{this.state.topic==t&&this.setState({draftVersion:e.version})}).catch(e=>{})},600)}clearDraft(e,t){this.draftSaveTimers&&this.draftSaveTimers[e]&&(window.clearTimeout(this.draftSaveTimers[e]),delete this.draftSaveTimers[e]);const s=null!=t?t:this.state.topic==e&&this.state.draftVersion||0;(0,l.k8)(e,"",[],s).then(t=>{this.state.topic==e&&this.setState({draftText:"",draftVersion:t.version})}).catch(e=>{})}handleShowAnnouncement(e){e.preventDefault();let t=C.A.addUrlParam(C.A.setUrlSidePanel("","group-announcement-detail"),"topic",this.state.topic);t=C.A.addUrlParam(t,"from","chat"),C.A.navigateTo(t)}handleShowJoinRequests(e){e.preventDefault();let t=C.A.addUrlParam(C.A.setUrlSidePanel("","group-join-requests"),"topic",this.state.topic);t=C.A.addUrlParam(t,"from","chat"),C.A.navigateTo(t)}handleSendFriendVerification(e){e.preventDefault(),C.A.navigateTo(C.A.addUrlParam(C.A.setUrlSidePanel("","friend-verification"),"uid",this.state.topic))}showToast(e){this.setState({toast:e}),window.clearTimeout(this.toastTimer),this.toastTimer=window.setTimeout(()=>this.setState({toast:null}),3500)}handleBatchDelete(){const e=this.props.tinode.getTopic(this.state.topic);if(!e||!this.props.selectedSeqs.length)return;const t=this.props.selectedSeqs.filter(t=>!e.cancelSend(t));t.length?e.delMessagesList(t,!0).then(e=>{this.props.onExitSelectMode()}).catch(e=>{this.props.onError(e.message,"err")}):this.props.onExitSelectMode()}handleBatchFavorite(){if(!this.props.selectedSeqs.length)return;const e=this.state.topic,t=this.props.selectedSeqs.slice();(0,l.Bc)(t.map(t=>({topic:e,seq:t}))).then(()=>(0,l.qM)({type:"all",limit:100}).then(s=>{const i=s&&s.items||[],n=new Set(i.filter(t=>t.source&&t.source.topic==e).map(e=>String(e.source.seq))),a=t.filter(e=>!n.has(String(e)));a.length===t.length?this.props.onError("收藏失败","err"):a.length?this.showToast(`已收藏 ${t.length-a.length}/${t.length} 条`):this.showToast("收藏成功")})).catch(e=>{this.props.onError(e.message,"err")})}sendKeyPress(e){const t=this.props.tinode.getTopic(this.state.topic);t.isSubscribed()&&(e||t.noteKeyPress())}applyMentionResolution(e){e&&Array.isArray(e.ent)&&this.mentionedUsers&&this.mentionedUsers.length&&e.ent.forEach(e=>{if("MN"===e.tp&&e.data&&"string"==typeof e.data.val){const t=this.mentionedUsers.find(t=>t.name===e.data.val);t&&(e.data.val=t.uid)}})}sendMessage(e,t,s,i){const n="string"==typeof e?e:null;let a;if(!e&&this.props.forwardMessage)e=this.props.forwardMessage.msg,a=this.props.forwardMessage.head,this.handleCancelReply();else if(this.state.reply){if(this.state.reply.editing){if(e==this.state.contentToEdit)return void this.handleCancelReply();a={replace:":"+this.state.reply.seq}}else this.state.reply.content&&(a={reply:""+this.state.reply.seq},"string"==typeof e&&(e=o.Drafty.parse(e),this.applyMentionResolution(e)),e=o.Drafty.append(o.Drafty.sanitizeEntities(this.state.reply.content),e));this.handleCancelReply()}else if("string"==typeof e&&this.mentionedUsers&&this.mentionedUsers.length){const t=o.Drafty.parse(e);this.applyMentionResolution(t),e=t}this.mentionedUsers=[],this.mentionAllPending&&(a={...a||{},mention_all:!0},this.mentionAllPending=!1),i&&(a={...a||{},"x-im-type":i});const r=this.state.topic,h=this.state.draftVersion||0,d=()=>{const i=this.props.sendMessage(e,t,s,a);return null!=n&&i&&"function"==typeof i.then&&r&&i.then(()=>this.clearDraft(r,h)),i},c=n&&n.match(/https?:\/\/\S+/g);if(c){const e={block:2,warn:1,allow:0},t=Array.from(new Set(c));return Promise.all(t.map(e=>(0,l.Iv)(e,"message_compose"))).then(t=>{const s=t.reduce((t,s)=>(e[s.decision]||0)>(e[t.decision]||0)?s:t);return"allow"===s.decision?d():new Promise(e=>{this.state.riskDialog&&this.state.riskDialog.resolve(!1),this.setState({riskDialog:{blocked:"block"===s.decision,challengeId:s.risk_challenge_id,send:d,resolve:e}})})}).catch(e=>d())}return d()}handleRiskConfirm(){const e=this.state.riskDialog;if(!e)return;this.setState({riskDialog:null});const t=()=>e.resolve(e.send());e.challengeId?(0,l.rF)(e.challengeId,"continue").then(t).catch(t):t()}handleRiskCancel(){const e=this.state.riskDialog;e&&(this.setState({riskDialog:null}),e.challengeId&&!e.blocked&&(0,l.rF)(e.challengeId,"cancel").catch(e=>{}),e.resolve(!1))}retrySend(e){this.props.sendMessage(e.content,void 0,void 0,e.head).then(t=>{this.props.tinode.getTopic(this.state.topic).delMessagesList([e.seq],!0)})}sendFileAttachment(e){const t=.75*this.props.tinode.getServerParam("maxMessageSize",262144)-1024|0;if((o.TheCard.isFileSupported(e.type,e.name)||e.type==o.TheCard.contentType)&&this.sendTheCardAttachment(e,t))return;const s=e=>e===D.Uv?"application/octet-stream":e;if(e.size>t){const t=(0,l.Lf)(this.props.tinode);if(!t)return void this.props.onError(this.props.intl.formatMessage(J.cannot_initiate_upload));const i=t.upload(e),n=o.Drafty.attachFile(null,{mime:s(e.type),filename:e.name,size:e.size,urlPromise:i});this.sendMessage(n,i,t,"file")}else(0,E.bB)(e).then(t=>this.sendMessage(o.Drafty.attachFile(null,{mime:s(t.mime),data:t.bits,filename:t.name,size:e.size}),void 0,void 0,"file")).catch(e=>this.props.onError(e.message,"err"))}sendTheCardAttachment(e,t){return!(e.size>t||(e.type==o.TheCard.contentType?(this.sendMessage(o.Drafty.appendTheCard(null,e.object)),0):((0,E.QJ)(e).then(e=>{this.sendMessage(o.Drafty.appendTheCard(null,e))}).catch(e=>{this.props.onError(this.props.intl.formatMessage(J.cannot_parse_vcard,{error:e.message}),"err")}),0)))}handleAttachFile(e){const t=this.props.tinode.getServerParam("maxFileUploadSize",D.qy);e.size>t?this.props.onError(this.props.intl.formatMessage(J.file_attachment_too_large,{size:(0,h.lX)(e.size),limit:(0,h.lX)(t)}),"err"):this.setState({docPreview:{file:e,name:e.name,size:e.size,type:e.type}})}handleCallHangup(e,t){this.props.onVideoCallClosed(),this.setState({rtcPanel:null}),this.props.onCallHangup(e,t)}handleCallPanelToggle(){this.setState({minimizedCallPanel:!this.state.minimizedCallPanel})}sendImageAttachment(e,t){const s=this.state.imagePreview.mime,i=this.state.imagePreview.width,n=this.state.imagePreview.height,a=this.state.imagePreview.filename,r=.75*this.props.tinode.getServerParam("maxMessageSize",262144)-1024|0;if(t.size>r){const r=(0,l.Lf)(this.props.tinode);if(!r)return void this.props.onError(this.props.intl.formatMessage(J.cannot_initiate_upload));const h=r.upload(t);return void(0,E.ag)(t,64,64,-1,!1).then(e=>(0,E.Sk)(e.blob)).then(l=>{let d=o.Drafty.insertImage(null,0,{mime:s,_tempPreview:l.bits,bits:l.bits,width:i,height:n,filename:a,size:t.size,urlPromise:h});e&&(d=o.Drafty.appendLineBreak(d),d=o.Drafty.append(d,o.Drafty.parse(e))),this.sendMessage(d,h,r,"image")}).catch(e=>this.props.onError(e,"err"))}(0,E.Sk)(t).then(s=>{let r=o.Drafty.insertImage(null,0,{mime:s.mime,bits:s.bits,width:i,height:n,filename:a,size:t.size});e&&(r=o.Drafty.appendLineBreak(r),r=o.Drafty.append(r,o.Drafty.parse(e))),this.sendMessage(r,void 0,void 0,"image")})}sendVideoAttachment(e,t,s,i){const n=i.width,a=i.height,r=.75*this.props.tinode.getServerParam("maxMessageSize",262144)-1024|0,h=[];let d;if(t.size+s.size>r){if(d=(0,l.Lf)(this.props.tinode),!d)return void this.props.onError(this.props.intl.formatMessage(J.cannot_initiate_upload));h[0]=t.size>.675*r?d.upload(t):null,h[1]=s.size>.275*r?d.upload(s):null}if(0==h.length)return void Promise.all([(0,E.Sk)(t),(0,E.Sk)(s)]).then(s=>{const[r,l]=s;let h=o.Drafty.insertVideo(null,0,{mime:r.mime,bits:r.bits,preview:l.bits,premime:l.mime,width:n,height:a,duration:i.duration,filename:i.name,size:t.size});e&&(h=o.Drafty.appendLineBreak(h),h=o.Drafty.append(h,o.Drafty.parse(e))),this.sendMessage(h,void 0,void 0,"video")});const c=Promise.all(h),p=[];p[0]=h[0]?null:(0,E.Sk)(t),p[1]=h[1]?null:(0,E.ag)(s,1024,1024,-1,!1).then(e=>(0,E.Sk)(e.blob)),p[2]=(0,E.ag)(s,96,96,-1,!1).then(e=>(0,E.Sk)(e.blob)),Promise.all(p).then(s=>{const[r,l,h]=s;let p=o.Drafty.insertVideo(null,0,{mime:i.mime,bits:r?r.bits:null,_tempPreview:h.bits,preview:l?l.bits:h.bits,premime:l?l.mime:h.mime,width:n,height:a,duration:i.duration,filename:i.name,size:t.size,urlPromise:c});e&&(p=o.Drafty.appendLineBreak(p),p=o.Drafty.append(p,o.Drafty.parse(e))),this.sendMessage(p,c,d,"video")}).catch(e=>this.props.onError(e.message,"err"))}handleAttachImageOrVideo(e){const t=this.props.tinode.getServerParam("maxFileUploadSize",D.qy);e.type.startsWith("video/")?this.setState({videoPreview:{url:URL.createObjectURL(e),blob:e,filename:e.name,size:e.size,mime:e.type}}):(0,E.ag)(e,1024,1024,t,!1).then(e=>{this.setState({imagePreview:{url:URL.createObjectURL(e.blob),blob:e.blob,filename:e.name,width:e.width,height:e.height,size:e.blob.size,mime:e.mime}})}).catch(e=>{this.props.onError(e.message,"err")})}handleFileDrop(e){if(!e||0==e.length)return;const t=e[0];t.type&&t.type.startsWith("image/")?this.handleAttachImageOrVideo(t):this.handleAttachFile(t)}sendAudioAttachment(e,t,s){fetch(e).then(e=>e.blob()).then(e=>{const i=.75*this.props.tinode.getServerParam("maxMessageSize",262144)-1024;if(e.size>i){const i=(0,l.Lf)(this.props.tinode);if(!i)return void this.props.onError(this.props.intl.formatMessage(J.cannot_initiate_upload));const n=i.upload(e),a=o.Drafty.appendAudio(null,{mime:e.type,size:e.size,duration:s,preview:t,urlPromise:n});this.sendMessage(a,n,i,"voice")}else(0,E.Sk)(e).then(i=>{this.sendMessage(o.Drafty.appendAudio(null,{mime:i.mime,bits:i.bits,size:e.size,duration:s,preview:t}),void 0,void 0,"voice")})}).catch(e=>{this.props.onError(e.message,"err")})}handleCancelUpload(e,t){const s=this.props.tinode.getTopic(this.state.topic).findMessage(e);s&&(s._cancelled=!0),t.cancel()}handlePickReply(e,t,s,i){e&&t?(t="string"==typeof t?o.Drafty.init(t):t,t=o.Drafty.isValid(t)?o.Drafty.replyContent(t,30):o.Drafty.append(o.Drafty.init("⚠ "),o.Drafty.wrapInto(this.props.intl.formatMessage(J.invalid_content),"EM")),this.setState({reply:{content:o.Drafty.quote(i,s,t),seq:e}}),this.props.onCancelForwardMessage()):this.setState({reply:null})}handleEditMessage(e,t){if(!e||!t)return void this.setState({reply:null});t="string"==typeof t?o.Drafty.init(t):t;const s=o.Drafty.toMarkdown(t);t=o.Drafty.isValid(t)?o.Drafty.replyContent(t,48):o.Drafty.append(o.Drafty.init("⚠ "),o.Drafty.wrapInto(this.props.intl.formatMessage(J.invalid_content),"EM")),this.setState({reply:{content:o.Drafty.quote(this.props.intl.formatMessage(J.editing_message),null,t),seq:e,editing:!0},contentToEdit:s}),this.props.onCancelForwardMessage()}handleCancelReply(){this.setState({reply:null,contentToEdit:null}),this.props.onCancelForwardMessage()}handleQuoteClick(e){const t=this.getOrCreateMessageRef(e);t&&t.current?(t.current.scrollIntoView({block:"center",behavior:"smooth"}),t.current.classList.add("flash"),setTimeout(e=>{t.current.classList.remove("flash")},1e3)):(console.error("Unresolved message ref",e),this.props.onError&&this.props.onError("该消息已被删除或撤回","err"))}jumpToMessage(e){const t=this.props.tinode&&this.props.topic?this.props.tinode.getTopic(this.props.topic):null;if(!t||!e||isNaN(e))return;C.A.navigateTo(C.A.removeUrlParam(window.location.hash,"jumpseq"));const s=()=>window.setTimeout(()=>this.handleQuoteClick(e),150);t.findMessage(e)?s():t.getMeta(t.startMetaQuery().withData(Math.max(1,e-20),e+21,41).build()).then(s).catch(e=>this.props.onError(e.message,"err"))}handleUnpinMessage(e){this.props.tinode.getTopic(this.state.topic).pinMessage(e,!1)}isDragEnabled(){const e=!(!this.state.reply||!this.state.reply.editing);return this.state.isWriter&&!this.state.unconfirmed&&!this.props.forwardMessage&&!this.state.peerMessagingDisabled&&!e}handleDragStart(e){e.preventDefault(),e.stopPropagation(),e.dataTransfer.clearData()}handleDragIn(e){e.preventDefault(),e.stopPropagation(),this.dragCounter++,e.dataTransfer.items&&e.dataTransfer.items.length>0&&this.setState({dragging:!0})}handleDragOut(e){e.preventDefault(),e.stopPropagation(),this.dragCounter--,this.dragCounter<=0&&this.setState({dragging:!1})}handleDrag(e){e.preventDefault(),e.stopPropagation()}handleDrop(e){e.preventDefault(),e.stopPropagation(),this.setState({dragging:!1}),this.isDragEnabled()&&e.dataTransfer.files&&e.dataTransfer.files.length>0&&(this.handleFileDrop(e.dataTransfer.files),this.dragCounter=0)}render(){const{formatMessage:e}=this.props.intl,t=this.state.rtcPanel&&(0,c.jsx)(i.Suspense,{fallback:(0,c.jsx)("div",{children:(0,c.jsx)(a.FormattedMessage,{id:"loading_note",defaultMessage:"Loading...",description:"Message shown when component is loading"})}),children:(0,c.jsx)(H,{topic:this.state.topic,seq:this.props.callSeq,callState:this.props.callState,callAudioOnly:this.props.callAudioOnly,tinode:this.props.tinode,title:this.state.title,avatar:this.state.avatar||!0,minimized:this.state.minimizedCallPanel,onError:this.props.onError,onHangup:this.handleCallHangup,onToggleMinimize:this.handleCallPanelToggle,onInvite:this.props.onCallInvite,onSendOffer:this.props.onCallSendOffer,onIceCandidate:this.props.onCallIceCandidate,onSendAnswer:this.props.onCallSendAnswer})}),s=this.state.riskDialog&&(0,c.jsx)(O.wW,{blocked:this.state.riskDialog.blocked,onConfirm:this.handleRiskConfirm,onCancel:this.handleRiskCancel});let n;if(this.state.topic){let r;if(this.state.imagePreview)r=(0,c.jsx)(i.Suspense,{fallback:(0,c.jsx)("div",{children:(0,c.jsx)(a.FormattedMessage,{id:"loading_note",defaultMessage:"Loading...",description:"Message shown when component is loading"})}),children:(0,c.jsx)(Q,{content:this.state.imagePreview,tinode:this.props.tinode,reply:this.state.reply,onCancelReply:this.handleCancelReply,onClose:this.handleClosePreview,onSendMessage:this.sendImageAttachment})});else if(this.state.videoPreview)r=(0,c.jsx)(i.Suspense,{fallback:(0,c.jsx)("div",{children:(0,c.jsx)(a.FormattedMessage,{id:"loading_note",defaultMessage:"Loading...",description:"Message shown when component is loading"})}),children:(0,c.jsx)(W,{content:this.state.videoPreview,tinode:this.props.tinode,reply:this.state.reply,onError:this.props.onError,onCancelReply:this.handleCancelReply,onClose:this.handleClosePreview,onSendMessage:this.sendVideoAttachment})});else if(this.state.imagePostview)r=(0,c.jsx)(i.Suspense,{fallback:(0,c.jsx)("div",{children:(0,c.jsx)(a.FormattedMessage,{id:"loading_note",defaultMessage:"Loading...",description:"Message shown when component is loading"})}),children:(0,c.jsx)(Q,{content:this.state.imagePostview,onClose:this.handleClosePreview})});else if(this.state.videoPostview)r=(0,c.jsx)(i.Suspense,{fallback:(0,c.jsx)("div",{children:(0,c.jsx)(a.FormattedMessage,{id:"loading_note",defaultMessage:"Loading...",description:"Message shown when component is loading"})}),children:(0,c.jsx)(W,{content:this.state.videoPostview,tinode:this.props.tinode,onError:this.props.onError,onClose:this.handleClosePreview})});else if(this.state.docPreview)r=o.TheCard.isFileSupported(this.state.docPreview.type,this.state.docPreview.name)||this.state.docPreview.type==o.TheCard.contentType?(0,c.jsx)(i.Suspense,{fallback:(0,c.jsx)("div",{children:(0,c.jsx)(a.FormattedMessage,{id:"loading_note",defaultMessage:"Loading...",description:"Message shown when component is loading"})}),children:(0,c.jsx)(G,{content:this.state.docPreview,tinode:this.props.tinode,reply:this.state.reply,onCancelReply:this.handleCancelReply,onClose:this.handleClosePreview,onSendMessage:this.sendFileAttachment})}):(0,c.jsx)(i.Suspense,{fallback:(0,c.jsx)("div",{children:(0,c.jsx)(a.FormattedMessage,{id:"loading_note",defaultMessage:"Loading...",description:"Message shown when component is loading"})}),children:(0,c.jsx)(B,{content:this.state.docPreview,tinode:this.props.tinode,reply:this.state.reply,onCancelReply:this.handleCancelReply,onClose:this.handleClosePreview,onSendMessage:this.sendFileAttachment})});else{const t=this.props.tinode.getTopic(this.state.topic),s=t.isChannelType()||t.chan,i=t.isGroupType()&&!s,n=[];t.trusted&&(t.trusted.verified&&n.push({icon:"verified",color:"badge-inv"}),t.trusted.staff&&n.push({icon:"staff",color:"badge-inv"}),t.trusted.danger&&n.push({icon:"dangerous",color:"badge-inv"}));const l=[];this.state.pins.forEach(e=>l.push(t.latestMsgVersion(e)||t.findMessage(e)));const d=[];let p=null,u=null,m=i?"chat-box group":"chat-box";t.messages((e,s,n,a)=>{let o=n?n.from||"chan":null,r="single",l=e.from||"chan";l==p?r=l==o?"middle":"last":l==o&&(r="first"),p=l;const m=!(l==this.props.myUserId),g=t.msgStatus(e,!0);let f,v,b=l;const S=t.userDesc(l);S&&S.public&&(f=S.public.fn,v=(0,E.to)(S.public.photo));const y=this.getOrCreateMessageRef(e.seq);let x=e.head?parseInt(e.head.reply):null;if(x&&!isNaN(x)||(x=null),e.hi)d.push((0,c.jsx)(U,{deleted:!0,deletedText:this.props.intl.formatMessage(J.message_deleted)},e.seq));else{const t=new Date(e.ts);u&&u.toDateString()==t.toDateString()||(d.push((0,c.jsx)(U,{date:(0,h.mf)(e.ts),locale:this.props.intl.locale},"date-"+e.seq)),u=t),d.push((0,c.jsx)(A,{tinode:this.props.tinode,topic:this.state.topic,content:e.content,mimeType:e.head&&e.head.mime,head:e.head,replyToSeq:x,edited:e.head&&!e.head.webrtc&&e.head.replace,timestamp:e.ts,response:m,seq:e.seq,isGroup:i,isChan:this.state.channel,userFrom:b,userName:f,userAvatar:v,senderRole:i&&this.state.groupRoles?this.state.groupRoles[l]:null,sequence:r,received:g,uploader:e._uploader,userIsWriter:this.state.isWriter,userIsAdmin:this.state.isAdmin,relationship:this.state.relationshipContext?this.state.relationshipContext.relationship:null,onSendFriendVerification:this.handleSendFriendVerification,selectMode:this.props.selectMode,selected:this.props.selectedSeqs&&this.props.selectedSeqs.includes(e.seq),onToggleSelect:this.props.onToggleMessageSelect,pinned:this.state.pins.includes(e.seq),viewportWidth:this.props.viewportWidth,showContextMenu:this.handleShowMessageContextMenu,onExpandMedia:this.handleExpandMedia,onFormResponse:this.handleFormResponse,onCancelUpload:this.handleCancelUpload,pickReply:this.handlePickReply,editMessage:this.handleEditMessage,onQuoteClick:this.handleQuoteClick,onAcceptCall:this.props.onAcceptCall,onError:this.props.onError,ref:y},e.seq))}});let g=null;if(s)t.subcnt&&(g=e(J.subscriber_count,{count:t.subcnt}));else{const s=this.props.tinode.getMeTopic().getContact(this.state.topic);s&&(o.Tinode.isP2PTopicName(s.topic)?s.online?g=e(J.online_now):s.seen&&(g=e(J.last_seen,{timestamp:(0,h.cq)(s.seen.when,this.props.intl.locale)})):o.Tinode.isGroupTopicName(s.topic)&&t.subcnt&&(g=e(J.member_count,{count:t.subcnt})))}const f=this.state.avatar||!0,b=this.state.deleted||t.isSelfType()?null:this.props.online?"online"+(this.state.typingIndicator?" typing":""):"offline",S="panel-title"+(this.state.deleted?" deleted":""),y="dark"==this.props.colorSchema?"dark":"",x=!(!this.state.reply||!this.state.reply.editing);let C=(0,c.jsxs)(c.Fragment,{children:[this.state.groupAnnouncement?(0,c.jsxs)("a",{href:"#",id:"group-announcement-banner",onClick:this.handleShowAnnouncement,children:[(0,c.jsx)("i",{className:"material-icons",children:"campaign"}),(0,c.jsx)("span",{children:this.state.groupAnnouncement.content}),(0,c.jsx)("i",{className:"material-icons",children:"chevron_right"})]}):null,this.state.pendingJoinRequests>0?(0,c.jsxs)("a",{href:"#",id:"group-join-request-banner",onClick:this.handleShowJoinRequests,children:[(0,c.jsx)("i",{className:"material-icons",children:"person_add_alt"}),(0,c.jsxs)("span",{children:["新邀请进群申请(",this.state.pendingJoinRequests,")"]}),(0,c.jsx)("i",{className:"material-icons",children:"chevron_right"})]}):null,(0,c.jsxs)("div",{id:"messages-container",className:y,children:[(0,c.jsx)("button",{id:"go-to-latest",className:"action-button"+(this.state.showGoToLastButton?"":" hidden"),onClick:this.goToLatestMessage,children:(0,c.jsx)("i",{className:"material-icons",children:"arrow_downward"})}),(0,c.jsx)("div",{id:"messages-panel",ref:this.handleScrollReference,children:(0,c.jsx)("ul",{id:"scroller",className:m,children:d})}),this.state.isReader?null:(0,c.jsx)("div",{id:"write-only-background",children:this.state.readingBlocked?(0,c.jsx)("div",{id:"write-only-note",children:(0,c.jsx)(a.FormattedMessage,{id:"messages_not_readable",defaultMessage:"no access to messages",description:"Message shown in topic without the read access"})}):null}),(0,c.jsxs)("div",{className:"toast"+(this.state.toast?" show":""),children:[(0,c.jsx)("i",{className:"material-icons",children:"check"})," ",this.state.toast]})]}),this.state.peerMessagingDisabled&&!this.state.unconfirmed?(0,c.jsxs)("div",{id:"peer-messaging-disabled-note",children:[(0,c.jsx)("i",{className:"material-icons secondary",children:"block"})," ",(0,c.jsx)(a.FormattedMessage,{id:"peers_messaging_disabled",defaultMessage:"Peer's messaging is disabled.",description:"Shown when the p2p peer's messaging is disabled"})," ",(0,c.jsx)("a",{href:"#",onClick:this.handleEnablePeer,children:(0,c.jsx)(a.FormattedMessage,{id:"enable_peers_messaging",defaultMessage:"Enable",description:"Call to action to enable peer's messaging"})}),"."]}):null,!this.state.unconfirmed&&this.state.relationshipContext&&"pending_inbound"==this.state.relationshipContext.relationship?(0,c.jsx)("div",{id:"relationship-status-note",children:"以上是打招呼的消息"}):null,!this.state.unconfirmed&&this.state.relationshipContext&&"pending_outbound"==this.state.relationshipContext.relationship?(0,c.jsx)("div",{id:"relationship-status-note",children:"好友申请正在等待处理"}):null,!this.state.unconfirmed&&this.state.relationshipContext&&"none"==this.state.relationshipContext.relationship?(0,c.jsxs)("div",{id:"relationship-status-note",children:["你们还不是好友,发送消息前需先验证 ",(0,c.jsx)("a",{href:"#",onClick:this.handleSendFriendVerification,children:"发送朋友验证"})]}):null,this.props.selectMode?(0,c.jsxs)("div",{id:"batch-action-bar",children:[(0,c.jsxs)("div",{id:"batch-action-count",children:["已选 ",this.props.selectedSeqs.length," 个"]}),(0,c.jsxs)("div",{id:"batch-action-buttons",children:[(0,c.jsxs)("a",{href:"#",onClick:e=>{e.preventDefault(),this.props.selectedSeqs.length&&this.props.onShowBatchForward()},className:this.props.selectedSeqs.length?"":"disabled",children:[(0,c.jsx)("i",{className:"material-icons",children:"forward"}),"转发"]}),(0,c.jsxs)("a",{href:"#",onClick:e=>{e.preventDefault(),this.handleBatchFavorite()},className:this.props.selectedSeqs.length?"":"disabled",children:[(0,c.jsx)("i",{className:"material-icons",children:"star_border"}),"收藏"]}),(0,c.jsxs)("a",{href:"#",onClick:e=>{e.preventDefault(),this.handleBatchDelete()},className:this.props.selectedSeqs.length?"":"disabled",children:[(0,c.jsx)("i",{className:"material-icons",children:"delete_outline"}),"删除"]})]}),(0,c.jsx)("a",{href:"#",id:"batch-action-cancel",onClick:e=>{e.preventDefault(),this.props.onExitSelectMode()},children:"取消"})]}):this.state.unconfirmed?(0,c.jsx)(F,{onAction:this.handleNewChatAcceptance}):(0,c.jsx)(V.A,{tinode:this.props.tinode,topicName:this.state.topic,noInput:!!this.props.forwardMessage,disabled:!this.state.isWriter||this.state.deleted,reply:this.state.reply,initMessage:null!=this.state.contentToEdit?this.state.contentToEdit:this.state.draftText,sendOnEnter:this.props.sendOnEnter,onKeyPress:this.sendKeyPress,onRecordingProgress:this.sendKeyPress,onMessageChange:this.props.forwardMessage?null:this.handleComposerChange,onMentionSearch:this.props.forwardMessage||!i?null:this.mentionSearch,onMentionSelected:this.mentionSelected,onSendMessage:this.sendMessage,onAttachFile:this.props.forwardMessage||x?null:this.handleAttachFile,onAttachImage:this.props.forwardMessage||x?null:this.handleAttachImageOrVideo,onAttachAudio:this.props.forwardMessage||x?null:this.sendAudioAttachment,canStartCall:!this.props.forwardMessage&&this.props.canStartCall,onStartAudioCall:this.props.onStartAudioCall,onStartVideoCall:this.props.onStartVideoCall,onError:this.props.onError,onQuoteClick:this.handleQuoteClick,onCancelReply:this.handleCancelReply})]});r=(0,c.jsxs)(c.Fragment,{children:[(0,c.jsxs)("div",{id:"topic-caption-panel",className:"caption-panel",children:[this.props.displayMobile?(0,c.jsx)("a",{href:"#",id:"hide-message-view",onClick:e=>{e.preventDefault(),this.leave(this.state.topic),this.props.onHideMessagesView()},children:(0,c.jsx)("i",{className:"material-icons",children:"arrow_back"})}):null,(0,c.jsxs)("div",{className:"avatar-box",children:[(0,c.jsx)(v.A,{authorizeURL:this.props.tinode.authorizeURL,avatar:f,topic:this.state.topic,title:this.state.title,deleted:this.state.deleted}),s?null:(0,c.jsx)("span",{className:b})]}),(0,c.jsxs)("div",{id:"topic-title-group",children:[(0,c.jsxs)("div",{id:"topic-title",className:S,children:[this.state.title||(0,c.jsx)("i",{children:(0,c.jsx)(a.FormattedMessage,{id:"unnamed_topic",defaultMessage:"Unnamed",description:"Title shown when the topic has no name"})}),(0,c.jsx)(P.A,{badges:n})]}),(0,c.jsx)("div",{id:"topic-last-seen",children:g})]}),(0,c.jsx)("div",{style:{marginLeft:"auto"}}),!this.props.displayMobile&&this.state.pins.length>0?(0,c.jsx)(z,{tinode:this.props.tinode,pins:this.state.pins,messages:l,selected:this.state.selectedPin,isAdmin:this.state.isAdmin,setSelected:e=>this.setState({selectedPin:e}),onSelected:this.handleQuoteClick,onCancel:this.handleUnpinMessage}):null,i?(0,c.jsx)(k,{tinode:this.props.tinode,subscribers:this.state.onlineSubs}):null,(0,c.jsx)("div",{children:(0,c.jsx)("a",{href:"#",onClick:this.handleContextClick,children:(0,c.jsx)("i",{className:"material-icons",children:"more_vert"})})})]}),this.props.displayMobile?(0,c.jsxs)(c.Fragment,{children:[this.state.pins.length>0?(0,c.jsx)(z,{tinode:this.props.tinode,pins:this.state.pins,messages:l,selected:this.state.selectedPin,isAdmin:this.state.isAdmin,setSelected:e=>this.setState({selectedPin:e}),onSelected:this.handleQuoteClick,onCancel:this.handleUnpinMessage}):null,(0,c.jsx)(T.A,{level:this.props.errorLevel,text:this.props.errorText,onClearError:this.props.onError})]}):null,(0,c.jsx)(R.A,{show:this.state.fetchingMessages}),C,this.state.dragging&&this.isDragEnabled()?(0,c.jsx)("div",{className:"drag-n-drop",children:e(J.drag_file)}):null]})}n=(0,c.jsxs)("div",{id:"topic-view",ref:this.mountDnDEvents,children:[r,t,s]})}else n=(0,c.jsx)(I,{});return n}}var ee=(0,a.injectIntl)(Z)},5372:function(e,t,s){var i=s(1594),n=s.n(i),a=s(8181),o=s(4532),r=(s(3272),s(7981)),l=s(2067),h=s(8353),d=s(4848);const c=n().lazy(e=>Promise.all([s.e(537),s.e(965)]).then(s.bind(s,965))),p=["😀","😁","😂","🤣","😃","😄","😅","😆","😉","😊","😋","😎","😍","😘","🥰","😗","😙","😚","🙂","🤗","🤩","🤔","🤨","😐","😑","😶","🙄","😏","😣","😥","😮","🤐","😯","😪","😫","🥱","😴","😌","😛","😜","😝","🤤","😒","😓","😔","😕","🙃","🤑","😲","☹️","🙁","😖","😞","😟","😤","😢","😭","😦","😧","😨","😩","🤯","😬","😰","😱","🥵","🥶","😳","🤪","😵","😡","😠","🤬","😷","🤒","🤕","🤢","🤮","🥳","🥴","🥺","🤫","🤭","🧐","🤓","😈","👿","👍","👎","👏","🙌","🤝","🙏","💪","❤️","🧡","💛","💚","💙","💜","🖤","💔","💕","💯","🔥","🎉","🎂","🌹","☀️","🌙","⭐"],u={image:"[图片]",video:"[视频]",voice:"[语音]",file:"[文件]",link:"[链接]",text:"[文本]"};function m(e){if("image"===e.type||"video"===e.type||"voice"===e.type)return u[e.type];const t=e.snapshot&&e.snapshot.content;return"string"==typeof t&&t.trim()?t:t&&"string"==typeof t.txt&&t.txt.trim()?t.txt:u[e.type]||e.type||e.favorite_id}const g="im-recent-emoji";function f(){try{const e=JSON.parse(localStorage.getItem(g)||"[]");return Array.isArray(e)?e:[]}catch(e){return[]}}const v=(0,a.defineMessages)({messaging_disabled:{id:"messaging_disabled_prompt",defaultMessage:"Messaging disabled",description:"Prompt in SendMessage in read-only topic"},type_new_message:{id:"new_message_prompt",defaultMessage:"New message",description:"Prompt in send message field"},add_image_caption:{id:"image_caption_prompt",defaultMessage:"Image caption",description:"Prompt in SendMessage for attached image"},file_attachment_too_large:{id:"file_attachment_too_large",defaultMessage:"The file size {size} exceeds the {limit} limit.",description:"Error message when attachment is too large"},cannot_initiate_upload:{id:"cannot_initiate_file_upload",defaultMessage:"Cannot initiate file upload.",description:"Generic error messagewhen attachment fails"},icon_title_record_voice:{id:"icon_title_record_voice",defaultMessage:"Record voice message",description:"Icon tool tip for recording a voice message"},icon_title_attach_file:{id:"icon_title_attach_file",defaultMessage:"Attach file",description:"Icon tool tip for attaching a file"},icon_title_add_image:{id:"icon_title_add_image",defaultMessage:"Add image",description:"Icon tool tip for attaching an image"},icon_title_send:{id:"icon_title_send",defaultMessage:"Send message",description:"Icon tool tip for sending a message"}});class b extends n().PureComponent{constructor(e){super(e),this.state={quote:null,message:"",audioRec:!1,audioAvailable:!(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia),mentionQuery:null,mentionResults:[],mentionHighlight:0,emojiOpen:!1,emojiTab:"emoji",recentEmoji:f(),attachOpen:!1,cardPicker:null,favPicker:null,audioCancelling:!1},this.keypressTimestamp=0,this.handlePasteEvent=this.handlePasteEvent.bind(this),this.handleAttachImage=this.handleAttachImage.bind(this),this.handleAttachFile=this.handleAttachFile.bind(this),this.handleAttachAudio=this.handleAttachAudio.bind(this),this.handleSend=this.handleSend.bind(this),this.handleKeyPress=this.handleKeyPress.bind(this),this.handleMessageTyping=this.handleMessageTyping.bind(this),this.handleDropAttach=this.handleDropAttach.bind(this),this.handleQuoteClick=this.handleQuoteClick.bind(this),this.selectMention=this.selectMention.bind(this),this.startHoldRecording=this.startHoldRecording.bind(this),this.handleHoldMove=this.handleHoldMove.bind(this),this.endHoldRecording=this.endHoldRecording.bind(this),this.handleHoldVisibilityChange=this.handleHoldVisibilityChange.bind(this),this.toggleEmojiPanel=this.toggleEmojiPanel.bind(this),this.insertEmoji=this.insertEmoji.bind(this),this.deleteLastChar=this.deleteLastChar.bind(this),this.toggleAttachPanel=this.toggleAttachPanel.bind(this),this.openCardPicker=this.openCardPicker.bind(this),this.openFavPicker=this.openFavPicker.bind(this),this.sendCard=this.sendCard.bind(this),this.sendFavorite=this.sendFavorite.bind(this),this.formatReply=this.formatReply.bind(this)}componentDidMount(){this.messageEditArea&&(this.messageEditArea.addEventListener("paste",this.handlePasteEvent,!1),"all"==window.getComputedStyle(this.messageEditArea).getPropertyValue("transition-property")&&this.messageEditArea.focus()),this.setState({quote:this.formatReply()})}componentWillUnmount(){this.messageEditArea&&this.messageEditArea.removeEventListener("paste",this.handlePasteEvent,!1),this.mentionSearchTimer&&window.clearTimeout(this.mentionSearchTimer),window.removeEventListener("mousemove",this.handleHoldMove),window.removeEventListener("mouseup",this.endHoldRecording),window.removeEventListener("touchmove",this.handleHoldMove),window.removeEventListener("touchend",this.endHoldRecording),window.removeEventListener("blur",this.endHoldRecording),document.removeEventListener("visibilitychange",this.handleHoldVisibilityChange)}componentDidUpdate(e){if(this.messageEditArea&&("all"==window.getComputedStyle(this.messageEditArea).getPropertyValue("transition-property")&&this.messageEditArea.focus(),this.messageEditArea.style.height="0px",this.messageEditArea.style.height=this.messageEditArea.scrollHeight+"px"),e.topicName!=this.props.topicName)this.setState({message:this.props.initMessage||"",audioRec:!1,quote:null,mentionQuery:null,mentionResults:[],emojiOpen:!1,attachOpen:!1,cardPicker:null,favPicker:null});else if(!e.disabled&&this.props.disabled&&this.state.audioRec)this.endHoldRecording(),this.setState({audioRec:!1});else if(e.initMessage!=this.props.initMessage){const e=this.props.initMessage||"";this.setState({message:e},t=>{this.messageEditArea.scrollTop=this.messageEditArea.scrollHeight,this.messageEditArea.setSelectionRange(e.length,e.length)})}e.reply!=this.props.reply&&this.setState({quote:this.formatReply()})}formatReply(){return this.props.reply?o.Drafty.format(this.props.reply.content,l.NV,{formatMessage:this.props.intl.formatMessage.bind(this.props.intl),authorizeURL:this.props.tinode.authorizeURL.bind(this.props.tinode)}):null}handlePasteEvent(e){this.props.disabled||(0,r.iJ)(e,e=>{this.props.onAttachImage&&this.props.onAttachImage(e)},e=>{this.props.onAttachFile&&this.props.onAttachFile(e)},this.props.onError)&&e.preventDefault()}handleAttachImage(e){e.target.files&&e.target.files.length>0&&this.props.onAttachImage&&this.props.onAttachImage(e.target.files[0]),e.target.value=""}handleAttachFile(e){e.target.files&&e.target.files.length>0&&this.props.onAttachFile&&this.props.onAttachFile(e.target.files[0]),e.target.value=""}handleDropAttach(e){e&&e.length>0&&this.props.onAttachFile&&this.props.onAttachFile(e[0])}handleAttachAudio(e,t,s){this.setState({audioRec:!1}),this.props.onAttachAudio&&this.props.onAttachAudio(e,t,s)}handleSend(e){e.preventDefault();const t=this.state.message.trim();if(t||this.props.acceptBlank||this.props.noInput){const e=this.props.onSendMessage(t);e&&"function"==typeof e.then?e.then(e=>{!1!==e&&this.setState({message:""})}):this.setState({message:""})}}handleKeyPress(e){if(this.state.audioRec)return e.preventDefault(),void e.stopPropagation();if(null!=this.state.mentionQuery){if("Escape"===e.key)return e.preventDefault(),void this.setState({mentionQuery:null,mentionResults:[]});if(this.state.mentionResults.length>0&&("ArrowDown"===e.key||"ArrowUp"===e.key)){e.preventDefault();const t="ArrowDown"===e.key?1:-1,s=this.state.mentionResults.length;return void this.setState({mentionHighlight:(this.state.mentionHighlight+t+s)%s})}if("Enter"===e.key&&this.state.mentionResults.length>0)return e.preventDefault(),e.stopPropagation(),void this.selectMention(this.state.mentionResults[this.state.mentionHighlight])}"Enter"===e.key&&("plain"==this.props.sendOnEnter?e.shiftKey||(e.preventDefault(),e.stopPropagation(),this.handleSend(e)):(e.ctrlKey||e.metaKey)&&(e.preventDefault(),e.stopPropagation(),this.handleSend(e)))}handleMessageTyping(e){if(this.setState({message:e.target.value}),this.updateMentionState(e.target.value,e.target.selectionStart),this.props.onMessageChange&&this.props.onMessageChange(e.target.value),this.props.onKeyPress){const e=(new Date).getTime();e-this.keypressTimestamp>3e3&&(this.props.onKeyPress(),this.keypressTimestamp=e)}}updateMentionState(e,t){if(!this.props.onMentionSearch||null==t)return;const s=e.slice(0,t),i=/(?:^|\s)@([^\s@]*)$/.exec(s);if(!i)return void(null!=this.state.mentionQuery&&this.setState({mentionQuery:null,mentionResults:[]}));const n=i[1],a=t-n.length-1;this.setState({mentionQuery:n,mentionStart:a,mentionHighlight:0}),this.mentionSearchTimer&&window.clearTimeout(this.mentionSearchTimer),this.mentionSearchTimer=window.setTimeout(()=>{this.props.onMentionSearch(n).then(e=>{null!=this.state.mentionQuery&&this.setState({mentionResults:e||[]})}).catch(()=>{})},200)}selectMention(e){const{message:t,mentionStart:s,mentionQuery:i}=this.state;if(null==s||null==i)return;const n=e.group_nickname||e.display_name||e.user_id,a="@"+n+" ",o=s+1+i.length,r=t.slice(0,s)+a+t.slice(o),l=s+a.length;this.setState({message:r,mentionQuery:null,mentionResults:[]}),this.props.onMentionSelected&&this.props.onMentionSelected(e.user_id,n),this.props.onMessageChange&&this.props.onMessageChange(r),requestAnimationFrame(()=>{this.messageEditArea&&(this.messageEditArea.focus(),this.messageEditArea.setSelectionRange(l,l))})}handleQuoteClick(e){if(e.preventDefault(),e.stopPropagation(),this.props.reply&&this.props.onQuoteClick){const e=this.props.reply.seq;this.props.onQuoteClick(e)}}toggleEmojiPanel(e){e.preventDefault(),this.setState(e=>({emojiOpen:!e.emojiOpen,attachOpen:!1,audioRec:!1}))}insertEmoji(e){const t=this.messageEditArea,s=t?t.selectionStart:this.state.message.length,i=t?t.selectionEnd:this.state.message.length,n=this.state.message.slice(0,s)+e+this.state.message.slice(i);!function(e){try{const t=[e].concat(f().filter(t=>t!==e)).slice(0,30);localStorage.setItem(g,JSON.stringify(t))}catch(e){}}(e),this.setState({message:n,recentEmoji:f()}),this.props.onMessageChange&&this.props.onMessageChange(n);const a=s+e.length;requestAnimationFrame(()=>{this.messageEditArea&&(this.messageEditArea.focus(),this.messageEditArea.setSelectionRange(a,a))})}deleteLastChar(){const e=this.messageEditArea,t=e?e.selectionStart:this.state.message.length,s=e?e.selectionEnd:this.state.message.length;let i,n;if(t!==s)i=this.state.message.slice(0,t)+this.state.message.slice(s),n=t;else{if(!(t>0))return;{const e=Array.from(this.state.message.slice(0,t));e.pop(),i=e.join("")+this.state.message.slice(t),n=e.join("").length}}this.setState({message:i}),this.props.onMessageChange&&this.props.onMessageChange(i),requestAnimationFrame(()=>{this.messageEditArea&&(this.messageEditArea.focus(),this.messageEditArea.setSelectionRange(n,n))})}toggleAttachPanel(e){e.preventDefault(),this.setState(e=>({attachOpen:!e.attachOpen,emojiOpen:!1}))}openCardPicker(e){e.preventDefault(),this.setState({attachOpen:!1,cardPicker:{loading:!0}}),(0,h.M7)().then(e=>{this.setState({cardPicker:{loading:!1,items:e.items||[]}})}).catch(()=>this.setState({cardPicker:{loading:!1,items:[],error:!0}}))}sendCard(e){this.setState({cardPicker:null});const t=t=>{const s=new o.TheCard(e.display_name||e.user_id,t);o.TheCard.setTinodeID(s,e.user_id),this.props.onSendMessage(o.Drafty.appendTheCard(null,s),void 0,void 0,"card")};e.avatar_file_id?(0,h.w8)(e.avatar_file_id).then(t).catch(()=>t(void 0)):t(void 0)}openFavPicker(e){e.preventDefault(),this.setState({attachOpen:!1,favPicker:{loading:!0}}),(0,h.qM)({type:"all"}).then(e=>{this.setState({favPicker:{loading:!1,items:e.items||[]}})}).catch(()=>this.setState({favPicker:{loading:!1,items:[],error:!0}}))}sendFavorite(e){this.setState({favPicker:null}),this.props.topicName&&(0,h.t$)([e.favorite_id],[this.props.topicName]).then(e=>{const t=(e&&e.items||[]).filter(e=>"failed"===e.status);t.length&&this.props.onError&&this.props.onError("发送失败:"+((0,h.pI)(t[0].reason)||t[0].reason||"未知原因"),"err")}).catch(e=>{this.props.onError&&this.props.onError(e&&e.message||"发送失败","err")})}startHoldRecording(e){e.preventDefault(),this.state.audioRec||(this.holdStartY="touches"in e?e.touches[0]&&e.touches[0].clientY:e.clientY,this.setState({audioRec:!0,audioCancelling:!1,emojiOpen:!1,attachOpen:!1}),window.addEventListener("mousemove",this.handleHoldMove),window.addEventListener("mouseup",this.endHoldRecording),window.addEventListener("touchmove",this.handleHoldMove,{passive:!1}),window.addEventListener("touchend",this.endHoldRecording),window.addEventListener("blur",this.endHoldRecording),document.addEventListener("visibilitychange",this.handleHoldVisibilityChange))}handleHoldVisibilityChange(){document.hidden&&this.endHoldRecording()}handleHoldMove(e){const t="touches"in e?e.touches[0]&&e.touches[0].clientY:e.clientY;if(null==t||null==this.holdStartY)return;const s=this.holdStartY-t>80;s!==this.state.audioCancelling&&this.setState({audioCancelling:s})}endHoldRecording(){window.removeEventListener("mousemove",this.handleHoldMove),window.removeEventListener("mouseup",this.endHoldRecording),window.removeEventListener("touchmove",this.handleHoldMove),window.removeEventListener("touchend",this.endHoldRecording),window.removeEventListener("blur",this.endHoldRecording),document.removeEventListener("visibilitychange",this.handleHoldVisibilityChange),this.holdStartY=null;const e={preventDefault:()=>{}};this.audioRecorderInstance&&(this.state.audioCancelling?this.audioRecorderInstance.handleDelete(e):this.audioRecorderInstance.handleDone(e))}render(){const{formatMessage:e}=this.props.intl,t=this.props.disabled?e(v.messaging_disabled):this.props.messagePrompt?e(v[this.props.messagePrompt]):e(v.type_new_message),s=this.props.reply&&this.props.reply.editing?"check_circle":"send",n=this.state.quote?(0,d.jsxs)("div",{id:"reply-quote-preview",children:[(0,d.jsx)("div",{className:"cancel",children:(0,d.jsx)("a",{href:"#",onClick:e=>{e.preventDefault(),this.props.onCancelReply()},children:(0,d.jsx)("i",{className:"material-icons gray",children:"close"})})}),this.state.quote]}):null,o=this.state.audioAvailable&&this.props.onAttachAudio,r=null!=this.state.mentionQuery?(0,d.jsx)("div",{id:"mention-picker",children:0===this.state.mentionResults.length?(0,d.jsx)("div",{className:"mention-picker-empty",children:"无匹配成员"}):this.state.mentionResults.map((e,t)=>(0,d.jsx)("div",{className:"mention-picker-row"+(t===this.state.mentionHighlight?" active":""),onMouseDown:t=>{t.preventDefault(),this.selectMention(e)},onMouseEnter:()=>this.setState({mentionHighlight:t}),children:e.group_nickname||e.display_name||e.user_id},e.user_id))}):null;return(0,d.jsxs)("div",{id:"send-message-wrapper",children:[this.props.noInput?null:n,r,(0,d.jsx)("div",{id:"send-message-panel",children:this.props.disabled?(0,d.jsx)("div",{id:"writing-disabled",children:t}):(0,d.jsxs)(d.Fragment,{children:[this.props.noInput?n||(0,d.jsx)("div",{className:"hr thin"}):this.state.audioRec?(0,d.jsx)(i.Suspense,{fallback:(0,d.jsx)("div",{children:(0,d.jsx)(a.FormattedMessage,{id:"loading_note",defaultMessage:"Loading...",description:"Message shown when component is loading"})}),children:(0,d.jsx)(c,{ref:e=>{this.audioRecorderInstance=e},holdMode:!0,cancelling:this.state.audioCancelling,onRecordingProgress:e=>this.props.onKeyPress(!0),onDeleted:e=>this.setState({audioRec:!1}),onFinished:this.handleAttachAudio})}):(0,d.jsx)("textarea",{id:"send-message-input",placeholder:t,value:this.state.message,onChange:this.handleMessageTyping,onKeyDown:this.handleKeyPress,ref:e=>{this.messageEditArea=e}}),this.props.noInput||this.state.audioRec?null:(0,d.jsx)("a",{href:"#",onClick:this.toggleEmojiPanel,title:"表情",children:(0,d.jsx)("i",{className:"material-icons secondary",children:this.state.emojiOpen?"keyboard":"insert_emoticon"})}),this.props.onAttachFile&&!this.state.audioRec?(0,d.jsx)("a",{href:"#",onClick:this.toggleAttachPanel,title:e(v.icon_title_attach_file),children:(0,d.jsx)("i",{className:"material-icons secondary",children:this.state.attachOpen?"keyboard":"add_circle_outline"})}):null,this.state.message||!o?(0,d.jsx)("a",{href:"#",onClick:this.handleSend,title:e(v.icon_title_send),children:(0,d.jsx)("i",{className:"material-icons",children:s})}):this.state.audioRec?null:(0,d.jsx)("a",{href:"#",onMouseDown:this.startHoldRecording,onTouchStart:this.startHoldRecording,onClick:e=>e.preventDefault(),title:e(v.icon_title_record_voice),children:(0,d.jsx)("i",{className:"material-icons",children:"mic"})}),(0,d.jsx)("input",{type:"file",ref:e=>{this.attachFile=e},onChange:this.handleAttachFile,style:{display:"none"}}),(0,d.jsx)("input",{type:"file",ref:e=>{this.attachImage=e},accept:"image/*, video/*",onChange:this.handleAttachImage,style:{display:"none"}}),(0,d.jsx)("input",{type:"file",ref:e=>{this.attachCamera=e},accept:"image/*",capture:"environment",onChange:this.handleAttachImage,style:{display:"none"}})]})}),this.state.emojiOpen?(0,d.jsxs)("div",{id:"emoji-panel",children:[(0,d.jsxs)("div",{id:"emoji-panel-tabs",children:[(0,d.jsx)("a",{href:"#",className:"emoji"===this.state.emojiTab?"active":"",onClick:e=>{e.preventDefault(),this.setState({emojiTab:"emoji"})},children:"😊"}),(0,d.jsx)("a",{href:"#",className:"recent"===this.state.emojiTab?"active":"",onClick:e=>{e.preventDefault(),this.setState({emojiTab:"recent"})},children:"♡"})]}),(0,d.jsx)("div",{id:"emoji-panel-grid",children:0===("emoji"===this.state.emojiTab?p:this.state.recentEmoji).length?(0,d.jsx)("div",{className:"emoji-panel-empty",children:"还没有常用表情"}):("emoji"===this.state.emojiTab?p:this.state.recentEmoji).map((e,t)=>(0,d.jsx)("a",{href:"#",onClick:t=>{t.preventDefault(),this.insertEmoji(e)},children:e},e+t))}),(0,d.jsxs)("div",{id:"emoji-panel-footer",children:[(0,d.jsx)("a",{href:"#",onClick:e=>{e.preventDefault(),this.deleteLastChar()},title:"删除",children:(0,d.jsx)("i",{className:"material-icons",children:"backspace"})}),(0,d.jsx)("a",{href:"#",className:"emoji-panel-send"+(this.state.message?" active":""),onClick:e=>{e.preventDefault(),this.handleSend(e)},title:e(v.icon_title_send),children:(0,d.jsx)("i",{className:"material-icons",children:s})})]})]}):null,this.state.attachOpen?(0,d.jsxs)("div",{id:"attach-panel",children:[(0,d.jsxs)("a",{href:"#",onClick:e=>{e.preventDefault(),this.setState({attachOpen:!1}),this.attachImage.click()},children:[(0,d.jsx)("i",{className:"material-icons",children:"photo"}),(0,d.jsx)("span",{children:"照片"})]}),(0,d.jsxs)("a",{href:"#",onClick:e=>{e.preventDefault(),this.setState({attachOpen:!1}),this.attachCamera.click()},children:[(0,d.jsx)("i",{className:"material-icons",children:"photo_camera"}),(0,d.jsx)("span",{children:"拍摄"})]}),(0,d.jsxs)("a",{href:"#",className:this.props.canStartCall?"":"disabled",onClick:e=>{e.preventDefault(),this.setState({attachOpen:!1}),this.props.canStartCall&&this.props.onStartAudioCall&&this.props.onStartAudioCall()},children:[(0,d.jsx)("i",{className:"material-icons",children:"call"}),(0,d.jsx)("span",{children:"语音通话"})]}),(0,d.jsxs)("a",{href:"#",onClick:this.openCardPicker,children:[(0,d.jsx)("i",{className:"material-icons",children:"badge"}),(0,d.jsx)("span",{children:"名片"})]}),(0,d.jsxs)("a",{href:"#",onClick:e=>{e.preventDefault(),this.setState({attachOpen:!1}),this.attachFile.click()},children:[(0,d.jsx)("i",{className:"material-icons",children:"attach_file"}),(0,d.jsx)("span",{children:"文件"})]}),(0,d.jsxs)("a",{href:"#",onClick:this.openFavPicker,children:[(0,d.jsx)("i",{className:"material-icons",children:"star_border"}),(0,d.jsx)("span",{children:"收藏"})]}),(0,d.jsxs)("a",{href:"#",className:this.props.canStartCall?"":"disabled",onClick:e=>{e.preventDefault(),this.setState({attachOpen:!1}),this.props.canStartCall&&this.props.onStartVideoCall&&this.props.onStartVideoCall()},children:[(0,d.jsx)("i",{className:"material-icons",children:"videocam"}),(0,d.jsx)("span",{children:"视频通话"})]})]}):null,this.state.cardPicker?(0,d.jsx)("div",{className:"send-message-picker-backdrop",onClick:()=>this.setState({cardPicker:null}),children:(0,d.jsxs)("section",{onClick:e=>e.stopPropagation(),children:[(0,d.jsxs)("header",{children:["选择联系人",(0,d.jsx)("a",{href:"#",onClick:e=>{e.preventDefault(),this.setState({cardPicker:null})},children:(0,d.jsx)("i",{className:"material-icons",children:"close"})})]}),(0,d.jsx)("div",{className:"send-message-picker-list",children:this.state.cardPicker.loading?(0,d.jsx)("p",{className:"send-message-picker-empty",children:"加载中…"}):0===this.state.cardPicker.items.length?(0,d.jsx)("p",{className:"send-message-picker-empty",children:this.state.cardPicker.error?"加载失败":"暂无好友"}):this.state.cardPicker.items.map(e=>(0,d.jsx)("a",{href:"#",onClick:t=>{t.preventDefault(),this.sendCard(e)},children:e.display_name||e.user_id},e.user_id))})]})}):null,this.state.favPicker?(0,d.jsx)("div",{className:"send-message-picker-backdrop",onClick:()=>this.setState({favPicker:null}),children:(0,d.jsxs)("section",{onClick:e=>e.stopPropagation(),children:[(0,d.jsxs)("header",{children:["我的收藏",(0,d.jsx)("a",{href:"#",onClick:e=>{e.preventDefault(),this.setState({favPicker:null})},children:(0,d.jsx)("i",{className:"material-icons",children:"close"})})]}),(0,d.jsx)("div",{className:"send-message-picker-list",children:this.state.favPicker.loading?(0,d.jsx)("p",{className:"send-message-picker-empty",children:"加载中…"}):0===this.state.favPicker.items.length?(0,d.jsx)("p",{className:"send-message-picker-empty",children:this.state.favPicker.error?"加载失败":"暂无收藏"}):this.state.favPicker.items.map(e=>(0,d.jsx)("a",{href:"#",onClick:t=>{t.preventDefault(),this.sendFavorite(e)},children:m(e)},e.favorite_id))})]})}):null]})}}t.A=(0,a.injectIntl)(b)}}]); +//# sourceMappingURL=280.prod.js.map \ No newline at end of file diff --git a/umd/280.prod.js.map b/umd/280.prod.js.map new file mode 100644 index 00000000..9a0449e1 --- /dev/null +++ b/umd/280.prod.js.map @@ -0,0 +1 @@ +{"version":3,"file":"280.prod.js","mappings":"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","sources":["webpack://tinode-webapp/./src/widgets/attachment.jsx","webpack://tinode-webapp/./src/widgets/forward-bundle.jsx","webpack://tinode-webapp/./src/widgets/received-marker.jsx","webpack://tinode-webapp/./src/widgets/chat-message.jsx","webpack://tinode-webapp/./src/widgets/group-subs.jsx","webpack://tinode-webapp/./src/widgets/invitation.jsx","webpack://tinode-webapp/./src/views/logo-view.jsx","webpack://tinode-webapp/./src/widgets/meta-message.jsx","webpack://tinode-webapp/./src/widgets/pinned-messages.jsx","webpack://tinode-webapp/./src/views/messages-view.jsx","webpack://tinode-webapp/./src/widgets/send-message.jsx"],"sourcesContent":["import React from 'react';\nimport { FormattedMessage } from 'react-intl';\n\nimport FileProgress from './file-progress.jsx';\nimport { createFileDownloader } from '../lib/im-api.js';\nimport { bytesToHumanSize } from '../lib/strformat.js';\nimport { isUrlRelative, sanitizeUrl } from '../lib/utils.js';\n\n// Same broad-category icon+color convention already established for file cards elsewhere\n// (content-library-view.jsx / group-management-view.jsx's FILE_TYPE_META) -- this was the one place\n// that never adopted it and instead used the same generic gray icon for every attachment regardless\n// of type. This client-side mime sniff exists only because chat attachments (unlike a group file\n// or a favorite) don't carry a server-computed file_type field to look up directly.\nconst ATTACHMENT_TYPE_META = {image: ['image', '#3ba55c'], video: ['videocam', '#3b82c4'], audio: ['audiotrack', '#8b5cf6'], document: ['description', '#e05d44'], file: ['insert_drive_file', '#8a8f98']};\nfunction attachmentTypeFromMime(mime) {\n const m = (mime || '').toLowerCase();\n if (m.startsWith('image/')) return 'image';\n if (m.startsWith('video/')) return 'video';\n if (m.startsWith('audio/')) return 'audio';\n if (m === 'application/pdf' || m === 'text/plain' || m.includes('msword') || m.includes('wordprocessingml') ||\n m.includes('spreadsheetml') || m.includes('presentationml') || m === 'application/vnd.ms-excel' || m === 'application/vnd.ms-powerpoint') {\n return 'document';\n }\n return 'file';\n}\n\nexport default class Attachment extends React.Component {\n constructor(props) {\n super(props);\n\n this.state = {\n downloader: null,\n progress: 0\n };\n\n this.downloadFile = this.downloadFile.bind(this);\n this.handleCancel = this.handleCancel.bind(this);\n }\n\n downloadFile(url, filename, mimetype) {\n if (!url) {\n this.props.onError(\"Invalid download URL '\" + url + \"'\");\n return;\n }\n\n // Same wrong-header bug as content-library-view.jsx's DownloadPage (X-Tinode-APIKey/\n // X-Tinode-Auth, neither recognized by this backend) -- confirmed live: clicking \"保存\" on any\n // real chat file attachment 403'd with \"valid API key required\". createFileDownloader() is the\n // fixed-headers drop-in with the same download()/cancel() interface.\n const downloader = createFileDownloader(this.props.tinode);\n this.setState({downloader: downloader});\n downloader.download(url, filename, mimetype,\n loaded => this.setState({progress: loaded / this.props.size}),\n err => this.props.onError(err, 'err')\n )\n .then(_ => this.setState({downloader: null, progress: 0}))\n .catch(err => {\n if (err) {\n this.props.onError(\"Error downloading file: \" + err.message, 'err');\n }\n this.setState({downloader: null, progress: 0});\n });\n }\n\n handleCancel() {\n if (this.props.uploading) {\n this.props.onCancelUpload();\n } else if (this.state.downloader) {\n this.state.downloader.cancel();\n }\n }\n\n render() {\n let filename = this.props.filename || 'file_attachment';\n if (filename.length > 36) {\n filename = filename.substr(0, 16) + '...' + filename.substr(-16);\n }\n let size = this.props.size > 0 ?\n ({bytesToHumanSize(this.props.size)}) :\n null;\n\n // Detect if the download URL is relative or absolute.\n // If the URL is relative use LargeFileHelper to attach authentication\n // credentials to the request.\n let url, helperFunc;\n if (!this.props.uploading && !this.state.downloader && isUrlRelative(this.props.downloadUrl)) {\n // Relative URL. Use download helper.\n url = '#';\n helperFunc = (e) => {\n e.preventDefault();\n this.downloadFile(this.props.downloadUrl, this.props.filename, this.props.mimetype);\n };\n } else {\n url = sanitizeUrl(this.props.downloadUrl);\n helperFunc = null;\n }\n const downloadWidget = <>file_download ;\n const [icon, color] = ATTACHMENT_TYPE_META[attachmentTypeFromMime(this.props.mimetype)];\n return (\n
\n
{icon}
\n
\n
{filename} {size}
\n {this.props.uploading || this.state.downloader ?\n \n :\n
{url ?\n {downloadWidget}\n :\n {downloadWidget}\n }
\n }\n
\n
\n );\n }\n};\n","// 合并转发卡片(第4章 4.20)。\n//\n// 服务端在 `POST /v1/im/messages/forward` 的 mode=\"bundle\" 下会生成一条消息,\n// head 带 `x-im-type: \"forward_bundle\"`,content 形如:\n// {bundle_id, title, item_count, preview:[{from,type,summary,ts}], items:[...], source_refs, comment}\n// 这个结构不是 Drafty,所以不加这个渲染的话会落到 chat-message 的 \"invalid content\" 兜底。\n//\n// items[] 里已经带了每条被转发消息的完整快照,所以\"查看完整记录\"是就地展开,不需要额外请求。\nimport React from 'react';\n\n// 快照里的 from 是不带 usr 前缀的裸 uid(与收藏快照一致)。先补前缀再查本地会话缓存拿显示名,\n// 查不到就不显示发送者——宁可少一行,也不要把一串 uid 摆在摘要前面。\nfunction senderName(tinode, from) {\n const raw = (from || '').trim();\n if (!raw) return '';\n const uid = raw.startsWith('usr') ? raw : 'usr' + raw;\n const topic = tinode && tinode.getTopic ? tinode.getTopic(uid) : null;\n const pub = topic && topic.public;\n return (pub && (pub.fn || pub.name)) || '';\n}\n\nconst TYPE_LABEL = {image: '[图片]', video: '[视频]', voice: '[语音]', file: '[文件]', link: '[链接]'};\n\nfunction lineText(entry) {\n if (!entry) return '';\n const summary = (entry.summary || entry.text || '').trim();\n if (summary) return summary;\n return TYPE_LABEL[entry.type] || '';\n}\n\nexport default class ForwardBundle extends React.PureComponent {\n constructor(props) {\n super(props);\n this.state = {expanded: false};\n this.handleToggle = this.handleToggle.bind(this);\n }\n\n handleToggle(e) {\n e.preventDefault();\n e.stopPropagation();\n this.setState(s => ({expanded: !s.expanded}));\n }\n\n render() {\n const c = this.props.content || {};\n const count = Number(c.item_count) || (Array.isArray(c.items) ? c.items.length : 0);\n // 收起时用 preview(服务端已截到最多 3 条);展开时用 items(全量)。\n const rows = this.state.expanded ? (c.items || []) : (c.preview || []);\n const comment = (c.comment || '').trim();\n\n return
\n
{c.title || '聊天记录'}
\n
    \n {rows.map((entry, i) => {\n const who = senderName(this.props.tinode, entry.from);\n return
  • \n {who ? {who}: : null}{lineText(entry)}\n
  • ;\n })}\n
\n {count > rows.length || this.state.expanded ?\n :\n
共 {count} 条消息
}\n {comment ?
{comment}
: null}\n
;\n }\n}\n","// Received/read indicator.\nimport React from 'react';\nimport { defineMessages, injectIntl } from 'react-intl';\n\nimport { Tinode } from 'tinode-sdk';\n\nimport { deliveryMarker } from '../lib/utils.js';\n\nconst messages = defineMessages({\n message_sending: {\n id: 'message_sending',\n defaultMessage: 'sending...',\n description: 'Message being sent, in place of time stamp'\n },\n message_sending_failed: {\n id: 'message_sending_failed',\n defaultMessage: 'failed',\n description: 'Failed to send message, in place of time stamp'\n },\n message_edited_marker: {\n id: 'message_edited_marker',\n defaultMessage: ', edited',\n description: 'Marker indicating that the message was edited'\n }\n});\n\nclass ReceivedMarker extends React.PureComponent {\n render() {\n const {formatMessage} = this.props.intl;\n let timestamp;\n if (this.props.received <= Tinode.MESSAGE_STATUS_SENDING) {\n timestamp = formatMessage(messages.message_sending);\n } else if (this.props.received == Tinode.MESSAGE_STATUS_FAILED ||\n this.props.received == Tinode.MESSAGE_STATUS_FATAL) {\n timestamp = formatMessage(messages.message_sending_failed);\n } else {\n timestamp = this.props.timestamp.toLocaleTimeString(this.props.intl.locale, { timeStyle: 'short' });\n }\n\n const icon = deliveryMarker(this.props.received);\n // icon.color is only set for the failed/read cases (deliveryMarker's other {name} results omit\n // the key entirely) -- string-concatenating it unconditionally put the literal text \"undefined\"\n // into the className for sending/sent/received messages.\n const marker = icon ? {icon.name} : null;\n const edited = this.props.edited ? formatMessage(messages.message_edited_marker) : null;\n\n return (\n \n {timestamp}{edited}{'\\u00a0'}{marker}\n \n );\n }\n};\n\nexport default injectIntl(ReceivedMarker);\n","// Single chat message bubble, sent or received.\n\nimport React from 'react';\nimport { FormattedMessage, injectIntl } from 'react-intl';\nimport { Drafty, Tinode, TheCard } from 'tinode-sdk';\n\nimport Attachment from './attachment.jsx';\nimport ForwardBundle from './forward-bundle.jsx';\nimport LetterTile from './letter-tile.jsx';\nimport ReceivedMarker from './received-marker.jsx'\n\nimport { fullFormatter } from '../lib/formatters.js';\nimport { sanitizeUrl } from '../lib/utils.js';\nimport HashNavigation from '../lib/navigation.js';\n\n// 4.9 语音未读红点:纯客户端概念,没有对应的后端字段——原生 Tinode 的 recv/read 只标记到\n// \"这条消息本身有没有被看到\",跟\"这条语音有没有被真的点开听过\"是两回事(文字消息看一眼就算\n// 读过,语音消息可能只是划过去、根本没点开播放)。按话题分别记一份\"已播放过的 seq 集合\"在\n// localStorage,跟\"最近使用表情\"是同一类不需要后端参与的本地小状态。\n// Key还要按登录账号分——P2P话题名本身就是对方user_id,跟\"我是谁\"无关;这个应用已知同一浏览器\n// origin下多个账号共享localStorage(多标签页各自登录不同账号),不带uid会导致账号A点开播放过\n// 的语音,在账号B自己与同一个人/同一个群的独立会话里也显示成\"已读\"。\nconst VOICE_PLAYED_KEY_PREFIX = 'im-voice-played:';\nfunction isVoicePlayed(myUid, topic, seq) {\n try {\n const list = JSON.parse(localStorage.getItem(VOICE_PLAYED_KEY_PREFIX + myUid + ':' + topic) || '[]');\n return Array.isArray(list) && list.includes(seq);\n } catch (_) {\n return false;\n }\n}\nfunction markVoicePlayed(myUid, topic, seq) {\n try {\n const key = VOICE_PLAYED_KEY_PREFIX + myUid + ':' + topic;\n const list = JSON.parse(localStorage.getItem(key) || '[]');\n const set = Array.isArray(list) ? list : [];\n if (!set.includes(seq)) {\n // Cap so a very long-lived topic doesn't grow this without bound.\n localStorage.setItem(key, JSON.stringify(set.concat(seq).slice(-500)));\n }\n } catch (_) { /* ignore */ }\n}\n\nclass BaseChatMessage extends React.PureComponent {\n constructor(props) {\n super(props);\n\n this.state = {\n progress: 0,\n voicePlayed: isVoicePlayed(props.tinode.getCurrentUserID(), props.topic, props.seq)\n };\n\n if (props.uploader) {\n props.uploader.onProgress = this.handleProgress.bind(this);\n }\n\n this.handleExpandImage = this.handleExpandImage.bind(this);\n this.handlePlayVideo = this.handlePlayVideo.bind(this);\n this.handleFormButtonClick = this.handleFormButtonClick.bind(this);\n this.handleQuoteClick = this.handleQuoteClick.bind(this);\n this.handleContextClick = this.handleContextClick.bind(this);\n this.handleCancelUpload = this.handleCancelUpload.bind(this);\n this.handleDraftyClick = this.handleDraftyClick.bind(this);\n this.handleVoicePlayed = this.handleVoicePlayed.bind(this);\n\n this.formatterContext = {\n formatMessage: props.intl.formatMessage.bind(props.intl),\n viewportWidth: props.viewportWidth,\n authorizeURL: props.tinode.authorizeURL.bind(props.tinode),\n\n onHandleClick: this.handleDraftyClick,\n // formatters.js's 'AU' case wires this to AudioPlayer's onPlay -- see handleVoicePlayed below\n // for why this needs to live on the instance (closes over this specific message's seq/topic)\n // rather than being a static, prop-derived value like the other formatterContext entries.\n onVoicePlayed: this.handleVoicePlayed\n };\n }\n\n handleDraftyClick = (e, action) => {\n switch (action) {\n case 'image':\n this.handleExpandImage(e);\n break;\n case 'video':\n this.handlePlayVideo(e);\n break;\n case 'form_button':\n this.handleFormButtonClick(e);\n break;\n case 'quote':\n this.handleQuoteClick(e);\n break;\n case 'contact_chat':\n e.preventDefault();\n try {\n // tinode:topic/usr123abc -> usr123abc\n const pathname = new URL(e.target.dataset.val)?.pathname;\n const parts = pathname.split('/').filter(Boolean);\n HashNavigation.navigateTo(HashNavigation.setUrlTopic('', parts.pop() || ''));\n } catch (error) {\n console.error(\"Invalid URL:\", error);\n }\n break;\n case 'contact_find':\n e.preventDefault();\n let hashUrl = HashNavigation.setUrlSidePanel(window.location.hash, 'newtpk');\n hashUrl = HashNavigation.addUrlParam(hashUrl, 'q', e.target.dataset.val);\n hashUrl = HashNavigation.addUrlParam(hashUrl, 'tab', 'find');\n HashNavigation.navigateTo(hashUrl);\n break;\n default:\n // No special handling; let the browser deal with it.\n console.info('Unhandled drafty action.', action, e.target.dataset);\n break;\n }\n }\n\n handleExpandImage(e) {\n e.preventDefault();\n this.props.onExpandMedia({\n url: e.target.src,\n filename: e.target.dataset.name,\n width: e.target.dataset.width,\n height: e.target.dataset.height,\n size: e.target.dataset.size,\n type: e.target.dataset.mime\n });\n }\n\n handlePlayVideo(e) {\n e.preventDefault();\n this.props.onExpandMedia({\n video: true,\n url: e.target.dataset.src,\n preview: e.target.src,\n filename: e.target.dataset.name,\n width: e.target.dataset.width,\n height: e.target.dataset.height,\n duration: e.target.dataset.duration,\n size: e.target.dataset.size,\n type: e.target.dataset.mime\n });\n }\n\n handleFormButtonClick(e) {\n e.preventDefault();\n const data = {\n seq: this.props.seq\n };\n data.resp = {};\n if (e.target.dataset.name) {\n data.resp[e.target.dataset.name] = e.target.dataset.val ? e.target.dataset.val :\n e.target.dataset.val === undefined ? 1 : '' + e.target.dataset.val;\n }\n if (e.target.dataset.act == 'url') {\n data.ref = sanitizeUrl(e.target.dataset.ref) || 'about:blank';\n }\n const text = e.target.dataset.title || 'unknown';\n this.props.onFormResponse(e.target.dataset.act, text, data);\n }\n\n handleContextClick(e) {\n e.preventDefault();\n e.stopPropagation();\n const menuItems = [];\n if (this.props.received == Tinode.MESSAGE_STATUS_FAILED) {\n menuItems.push('menu_item_send_retry');\n }\n if (this.props.received > Tinode.MESSAGE_STATUS_FATAL) {\n if (this.props.userIsWriter) {\n menuItems.push('menu_item_reply');\n if (!this.props.response) {\n let immutable = false;\n Drafty.entities(this.props.content, (_0, _1, tp) => {\n immutable = ['AU', 'EX', 'FM', 'IM', 'TC', 'VC', 'VD'].includes(tp);\n return immutable;\n });\n if (!immutable) {\n Drafty.styles(this.props.content, tp => {\n immutable = ['QQ'].includes(tp);\n return immutable;\n });\n }\n if (!immutable) {\n menuItems.push('menu_item_edit');\n }\n }\n }\n if (this.props.userIsAdmin) {\n menuItems.push(this.props.pinned ? 'menu_item_unpin' : 'menu_item_pin');\n }\n }\n menuItems.push('menu_item_forward');\n\n this.props.showContextMenu({\n seq: this.props.seq,\n replace: this.props.edited ? parseInt(this.props.edited.split(':')[1]) : 0,\n content: this.props.content,\n head: this.props.head,\n userFrom: this.props.userFrom,\n userName: this.props.userName,\n y: e.pageY,\n x: e.pageX,\n pickReply: this.props.pickReply,\n editMessage: this.props.editMessage,\n timestamp: this.props.timestamp,\n }, menuItems);\n }\n\n handleProgress(ratio) {\n this.setState({progress: ratio});\n }\n\n handleCancelUpload() {\n this.props.onCancelUpload(this.props.seq, this.props.uploader);\n }\n\n handleVoicePlayed() {\n if (this.state.voicePlayed) {\n return;\n }\n markVoicePlayed(this.props.tinode.getCurrentUserID(), this.props.topic, this.props.seq);\n this.setState({voicePlayed: true});\n }\n\n handleQuoteClick(e) {\n e.preventDefault();\n e.stopPropagation();\n const replyToSeq = this.props.replyToSeq;\n if (replyToSeq) {\n this.props.onQuoteClick(replyToSeq);\n }\n }\n\n // Reason caption shown under a failed outgoing message in a 1:1 chat, based on the real\n // relationship state (see docs/images/个人对话—拉黑状态/已读状态.png and .../个人对话—删除状态.png).\n // Returns null for relationships that don't explain a send failure (friend, pending, unknown) so\n // a plain network failure doesn't get a misleading relationship-based caption.\n renderFailReason() {\n if (this.props.response ||\n (this.props.received != Tinode.MESSAGE_STATUS_FAILED && this.props.received != Tinode.MESSAGE_STATUS_FATAL)) {\n return null;\n }\n if (this.props.relationship == 'blocked_by_peer' || this.props.relationship == 'blocked_by_me') {\n return
消息已发送,但被对方拒收了
;\n }\n if (this.props.relationship == 'none') {\n return
你还不是他(她)朋友。发送朋友验证
;\n }\n return null;\n }\n\n render() {\n const sideClass = this.props.sequence + ' ' + (this.props.response ? 'left' : 'right');\n const bubbleClass = (this.props.sequence == 'single' || this.props.sequence == 'last') ? 'bubble tip' : 'bubble';\n const avatar = this.props.userAvatar || true;\n const isFailed = !this.props.response &&\n (this.props.received == Tinode.MESSAGE_STATUS_FAILED || this.props.received == Tinode.MESSAGE_STATUS_FATAL);\n const failReason = this.renderFailReason();\n // 4.9 语音未读红点:只对收到的(response=true)语音消息生效——自己发的语音不需要提醒自己听。\n let isVoiceMessage = false;\n if (this.props.response && this.props.mimeType == Drafty.getContentType() && Drafty.isValid(this.props.content)) {\n Drafty.entities(this.props.content, (_0, _1, tp) => {\n if (tp === 'AU') { isVoiceMessage = true; }\n return isVoiceMessage;\n });\n }\n const showVoiceUnreadDot = isVoiceMessage && !this.state.voicePlayed;\n let textSizeClass = 'message-content';\n const fullDisplay = (this.props.isGroup && this.props.response &&\n (this.props.sequence == 'single' || this.props.sequence == 'last'));\n\n let content = this.props.content;\n // Server-generated conversation notices (`system_notice`, e.g. `friend_added` sent once when two\n // users become friends -- see server's publishIMConversationSystemNotice) and group system-action\n // events (`system_action`, e.g. group_member_joined/join_request_approved/governance changes --\n // server/im_http.go's group event publishers) both carry a custom JSON shape\n // ({template, text, actors/actions, ...}), not Drafty and not a plain string, so without this\n // they fall through to the generic \"invalid content\" placeholder below -- a real, human-readable\n // message like \"有成员通过审批加入了群聊。\" was rendering as a bare warning icon. Reduce either to\n // its `text` upfront so the existing plain-string path renders it as an ordinary bubble -- these\n // are meant to read like a normal message, not a special banner.\n if (this.props.head && (this.props.head['x-im-type'] === 'system_notice' || this.props.head['x-im-type'] === 'system_action') &&\n content && typeof content == 'object' && typeof content.text == 'string') {\n content = content.text;\n }\n // 合并转发(服务端 mode=\"bundle\" 生成的消息)同样不是 Drafty,content 是\n // {bundle_id, title, item_count, preview, items, source_refs, comment}。不认这个类型的话\n // 一样会落到下面的 \"invalid content\" 兜底。渲染成一张可展开的\"聊天记录\"卡片。\n let bundleCard = null;\n if (this.props.head && this.props.head['x-im-type'] === 'forward_bundle' &&\n content && typeof content == 'object' && (content.items || content.preview)) {\n bundleCard = ;\n }\n const attachments = [];\n if (this.props.mimeType == Drafty.getContentType() && Drafty.isValid(content)) {\n Drafty.attachments(content, (att, i) => {\n if (Drafty.isFormResponseType(att.mime)) {\n // Don't show json drafty form response objects as attachments.\n // They are not meant for users.\n return;\n }\n attachments.push();\n }, this);\n const tree = Drafty.format(content, fullFormatter, this.formatterContext);\n content = React.createElement(React.Fragment, null, tree);\n } else if (typeof content == 'string') {\n // Make font bigger for emoji-only messages.\n // Must use 'new RegExp(...)' because React does not like /{1-5}/.\n if (new RegExp('^\\\\p{RGI_Emoji}{1,5}$', 'v').test(content || '')) {\n // Content consists of 1-5 emoji characters. Count how many and use it to increase the font size.\n textSizeClass += ' emoji-' + (content || '').match(/\\p{RGI_Emoji}/vg).length;\n }\n } else {\n content = <>warning_amber \n \n }\n\n return (\n
  • \n {this.props.selectMode ?\n this.props.onToggleSelect(this.props.seq)}>\n {this.props.selected ? 'check_circle' : 'radio_button_unchecked'}\n : null}\n {this.props.isGroup && this.props.response ?\n
    \n {fullDisplay ?\n :\n null}\n
    :\n null}\n {isFailed && failReason ?\n error : null}\n
    \n
    \n {showVoiceUnreadDot ? : null}\n
    \n
    \n {bundleCard || content}\n {attachments}\n
    \n {this.props.timestamp ?\n \n : null}\n
    \n {this.props.showContextMenu && !this.props.selectMode ?\n \n \n expand_more\n \n : null\n }\n
    \n {failReason}\n {fullDisplay ?\n
    \n {this.props.userName ||\n \n }\n {this.props.senderRole == 'owner' ? 群主 :\n this.props.senderRole == 'admin' ? 管理员 : null}\n
    \n : null\n }\n
    \n
  • \n );\n }\n};\n\nconst IntlChatMessage = injectIntl(BaseChatMessage);\nconst ChatMessage = React.forwardRef((props, ref) => );\n\nexport default ChatMessage;\n","// GroupSubs: a list of group subscribers currently online.\n// Show in the topic title bar\nimport React from 'react';\nimport { FormattedMessage } from 'react-intl';\n\nimport { MAX_ONLINE_IN_TOPIC } from '../config.js'\n\nimport LetterTile from './letter-tile.jsx';\nimport { makeImageUrl } from '../lib/blob-helpers.js';\n\nexport default class GroupSubs extends React.Component {\n constructor(props) {\n super(props);\n }\n\n render() {\n const usersOnline = [];\n const totalCount = (this.props.subscribers || []).length;\n const countToShow = Math.min(MAX_ONLINE_IN_TOPIC, totalCount);\n\n (this.props.subscribers || []).some((sub) => {\n usersOnline.push(\n
    \n \n
    \n );\n return usersOnline.length == countToShow;\n });\n if (usersOnline.length == 0) {\n return null;\n }\n return (\n
    {usersOnline} {totalCount > countToShow ?\n \n \n : null}\n
    \n );\n }\n};\n","// A single topic or user.\nimport React from 'react';\nimport { FormattedMessage } from 'react-intl';\n\nexport default class Invitation extends React.PureComponent {\n constructor(props) {\n super(props);\n\n this.handleButtonAction = this.handleButtonAction.bind(this);\n }\n\n handleButtonAction(evt, data) {\n evt.preventDefault();\n this.props.onAction(data);\n }\n\n render() {\n return (\n
    \n
    \n \n
    \n
    \n \n \n \n
    \n
    \n );\n }\n};\n","/* Static placeholder shown in the message pane when no conversation is selected. */\nimport React from 'react';\n\nimport { BASE_APP_NAME } from '../config.js';\n\nfunction Icon({children}) { return {children}; }\n\nexport default class LogoView extends React.PureComponent {\n render() {\n return (\n
    \n
    \n forum\n

    {BASE_APP_NAME}

    \n

    选择一个会话开始聊天

    \n
    \n
    \n );\n }\n};\n","// Message bubble with non-payload content, such as an indicator of deleted content or a date stamp.\n\nimport React from 'react';\n\nexport default class MetaMessage extends React.PureComponent {\n constructor(props) {\n super(props);\n }\n\n render() {\n let content = null;\n let bubbleClass = 'bubble';\n if (this.props.date) {\n // A date badge.\n content = <>{this.props.date}\n bubbleClass += ' date';\n } else if (this.props.deleted) {\n // 撤回/删除占位。messages-view.jsx 对 msg.hi 的消息一直在传 deleted={true},但这里从来\n // 没有处理过这个分支,于是整个组件走到下面的 `return null` —— 撤回一条消息之后时间线上\n // 什么都不剩,看不出这里曾经有过一条消息。文案复用已有的 message_deleted(\"消息已删除\")。\n content = {this.props.deletedText || '消息已删除'};\n bubbleClass += ' deleted';\n }\n\n if (!content) {\n return <>{null}\n }\n\n return (\n
  • \n
    \n
    \n {content}\n
    \n
    \n
  • \n );\n }\n};\n","// Send message form.\nimport React from 'react';\nimport { defineMessages, injectIntl } from 'react-intl';\nimport { Drafty } from 'tinode-sdk';\n\nimport { previewFormatter } from '../lib/formatters.js';\nimport { MIN_SWIPE_DISTANCE } from '../config.js';\n\nconst messages = defineMessages({\n message_not_found: {\n id: 'message_not_found',\n defaultMessage: 'message not found',\n description: 'Pinned message is not found'\n },\n message_deleted: {\n id: 'message_deleted',\n defaultMessage: 'message deleted',\n description: 'Pinned message is deleted'\n }\n});\n\nclass PinnedMessages extends React.PureComponent {\n constructor(props) {\n super(props);\n\n // Starting location of the touch gesture.\n this.touchX = null;\n this.touchY = null;\n\n this.touchSurface = React.createRef();\n\n this.getSelectedIndex = this.getSelectedIndex.bind(this);\n this.handleCancel = this.handleCancel.bind(this);\n this.handleSelected = this.handleSelected.bind(this);\n this.handleMoveNext = this.handleMoveNext.bind(this);\n this.handleMovePrev = this.handleMovePrev.bind(this);\n this.handleTouchEventStart = this.handleTouchEventStart.bind(this);\n this.handleTouchEventEnd = this.handleTouchEventEnd.bind(this);\n this.handleTouchCancel = this.handleTouchCancel.bind(this);\n }\n\n componentDidMount() {\n this.touchSurface.current.addEventListener('touchstart', this.handleTouchEventStart, {passive: true});\n this.touchSurface.current.addEventListener('touchend', this.handleTouchEventEnd, {passive: true});\n this.touchSurface.current.addEventListener('touchcancel', this.handleTouchCancel, {passive: true});\n }\n\n componentWillUnmount() {\n this.touchSurface.current.removeEventListener('touchstart', this.handleTouchEventStart);\n this.touchSurface.current.removeEventListener('touchend', this.handleTouchEventEnd);\n this.touchSurface.current.removeEventListener('touchcancel', this.handleTouchCancel);\n }\n getSelectedIndex() {\n const list = (this.props.pins || []);\n return list.length - this.props.selected - 1;\n }\n\n handleCancel(e) {\n e.preventDefault();\n this.props.onCancel(this.props.pins[this.getSelectedIndex()]);\n }\n\n handleSelected(e) {\n e.preventDefault();\n this.props.onSelected(this.props.pins[this.getSelectedIndex()]);\n }\n\n handleMoveNext(e, isTouch) {\n // Don't call preventDefault for touch events.\n isTouch || e.preventDefault();\n e.stopPropagation();\n const idx = Math.max(this.props.selected - 1, 0);\n if (idx != this.props.selected) {\n this.props.setSelected(idx);\n }\n }\n\n handleMovePrev(e, isTouch) {\n // Don't call preventDefault for touch events.\n isTouch || e.preventDefault();\n e.stopPropagation();\n const idx = Math.min(this.props.selected + 1, (this.props.pins || []).length - 1);\n if (idx != this.props.selected) {\n this.props.setSelected(idx);\n }\n }\n\n handleTouchEventStart(e) {\n if (e.touches.length == 1) {\n this.touchX = e.touches[0].clientX;\n this.touchY = e.touches[0].clientY;\n }\n }\n\n handleTouchEventEnd(e) {\n if (this.touchX === null || e.changedTouches.length != 1) {\n this.touchX = null;\n return;\n }\n\n const dX = this.touchX - e.changedTouches[0].clientX;\n const dY = this.touchY - e.changedTouches[0].clientY;\n this.touchX = null;\n\n if (Math.abs(dX) > Math.abs(dY) || Math.abs(dY) < MIN_SWIPE_DISTANCE) {\n // Horizontal swipe or too short vertical swipe.\n return;\n }\n\n if (dY > 0) {\n this.handleMovePrev(e, true);\n } else {\n this.handleMoveNext(e, true);\n }\n }\n\n handleTouchCancel() {\n this.touchX = null;\n }\n\n render() {\n const selected = this.getSelectedIndex();\n let messageShown = (this.props.messages || [])[selected];\n messageShown = messageShown ?\n messageShown._deleted ?\n {this.props.intl.formatMessage(messages.message_deleted)}\n :\n Drafty.format(messageShown.content, previewFormatter, {\n formatMessage: this.props.intl.formatMessage.bind(this.props.intl),\n authorizeURL: this.props.tinode.authorizeURL.bind(this.props.tinode)\n })\n :\n {this.props.intl.formatMessage(messages.message_not_found)};\n\n const dots = [];\n this.props.pins.forEach(seq => {\n const cn = dots.length == selected ? 'adot' : 'dot';\n dots.push(
    );\n });\n\n return (\n
    \n {this.props.isAdmin ?\n
    \n close\n
    :\n
    push_pin
    \n }\n
    {dots}
    \n

    {messageShown}

    \n
    \n \n {selected > 0 ?\n \n expand_less\n \n : null\n }\n \n \n {this.props.selected > 0 ?\n \n expand_more\n \n : null\n }\n \n
    \n
    \n );\n }\n}\n\nexport default injectIntl(PinnedMessages);\n","// Panel with a chat.\n\nimport React, { Suspense } from 'react';\nimport { FormattedMessage, defineMessages, injectIntl } from 'react-intl';\n\nimport { Drafty, Tinode, TheCard } from 'tinode-sdk';\n\nconst CallPanel = React.lazy(_ => import('../widgets/call-panel.jsx'));\nimport ChatMessage from '../widgets/chat-message.jsx';\nimport ContactBadges from '../widgets/contact-badges.jsx';\nconst DocPreview = React.lazy(_ => import('../widgets/doc-preview.jsx'));\nimport ErrorPanel from '../widgets/error-panel.jsx';\nimport GroupSubs from '../widgets/group-subs.jsx';\nconst ImagePreview = React.lazy(_ => import('../widgets/image-preview.jsx'));\nimport Invitation from '../widgets/invitation.jsx';\nimport LetterTile from '../widgets/letter-tile.jsx';\nimport LoadSpinner from '../widgets/load-spinner.jsx';\nimport LogoView from './logo-view.jsx';\nimport MetaMessage from '../widgets/meta-message.jsx';\nimport PinnedMessages from '../widgets/pinned-messages.jsx';\nimport { RiskConfirmDialog } from './security-support-view.jsx';\nimport SendMessage from '../widgets/send-message.jsx';\nconst TheCardPreview = React.lazy(_ => import('../widgets/the-card-preview.jsx'));\nconst VideoPreview = React.lazy(_ => import('../widgets/video-preview.jsx'));\n\nimport { DEFAULT_P2P_ACCESS_MODE, EDIT_PREVIEW_LENGTH, IMAGE_PREVIEW_DIM, IMMEDIATE_P2P_SUBSCRIPTION,\n DRAFTY_FR_MIME_TYPE_LEGACY, KEYPRESS_DELAY, MESSAGES_PAGE, MAX_EXTERN_ATTACHMENT_SIZE, MAX_IMAGE_DIM,\n MAX_INBAND_ATTACHMENT_SIZE, READ_DELAY, QUOTED_REPLY_LENGTH, VIDEO_PREVIEW_DIM } from '../config.js';\nimport { CALL_STATE_OUTGOING_INITATED, CALL_STATE_IN_PROGRESS } from '../constants.js';\nimport { blobToBase64, fileToBase64, imageScaled, importVCard, makeImageUrl } from '../lib/blob-helpers.js';\nimport { topicDisplayName } from '../lib/utils.js';\nimport { checkURL, confirmRiskChallenge, createChatUploader, favoriteMessages, getBootstrap, getConversationContext,\n getFavorites, getGroupJoinRequests, getGroupMembers, getLatestGroupAnnouncement, getTopicDraft, recallMessage,\n updateTopicDraft } from '../lib/im-api.js';\nimport HashNavigation from '../lib/navigation.js';\nimport { bytesToHumanSize, relativeDateFormat, shortDateFormat } from '../lib/strformat.js';\n\n// Run timer with this frequency (ms) for checking notification queue.\nconst NOTIFICATION_EXEC_INTERVAL = 300;\n// Scroll distance before [go to latest message] button is shown.\nconst SHOW_GO_TO_LAST_DIST = 100;\n// Sctoll distance from the top when fetching the page of earlier messages is triggered.\nconst FETCH_PAGE_TRIGGER = 40;\n\nconst messages = defineMessages({\n // 已存在于 src/i18n/*.json(zh: \"消息已删除\"),这里只是注册引用,不是新增待翻译串\n message_deleted: {\n id: 'message_deleted',\n defaultMessage: 'message deleted',\n description: 'Placeholder shown in the timeline where a message was recalled or deleted',\n },\n online_now: {\n id: 'online_now',\n defaultMessage: 'online now',\n description: 'Indicator that the user or topic is currently online',\n },\n last_seen: {\n id: 'last_seen_timestamp',\n defaultMessage: 'Last seen: {timestamp}',\n description: 'Label for the timestamp of when the user or topic was last online'\n },\n not_found: {\n id: 'title_not_found',\n defaultMessage: 'Not found',\n description: 'Title shown when topic is not found'\n },\n channel: {\n id: 'channel',\n defaultMessage: 'channel',\n description: 'Subtitle shown for channels in MessagesView instead of last seen'\n },\n file_attachment_too_large: {\n id: 'file_attachment_too_large',\n defaultMessage: 'The file size {size} exceeds the {limit} limit.',\n description: 'Error message when attachment is too large'\n },\n invalid_content: {\n id: 'invalid_content',\n defaultMessage: 'invalid content',\n description: 'Shown when the message is unreadable'\n },\n editing_message: {\n id: 'editing_message',\n defaultMessage: 'Editing',\n description: 'Title over message editing preview'\n },\n drag_file: {\n id: 'drag_file',\n defaultMessage: 'Drag file here',\n description: 'Prompt on the file drag-n-drop overlay banner'\n },\n self_topic_name: {\n id: 'self_topic_name',\n defaultMessage: 'Saved messages',\n description: 'Name of self topic for UI'\n },\n subscriber_count: {\n id: 'subscriber_count',\n defaultMessage: '{count, plural, ' +\n 'one {{count, number} subscriber} ' +\n 'two {{count, number} subscribers} ' +\n 'three {{count, number} subscribers} ' +\n 'few {{count, number} subscribers} ' +\n 'many {{count, number} subscribers} ' +\n 'other {{count, number} subscribers}}',\n description: 'Count of channel subscribers'\n },\n member_count: {\n id: 'member_count',\n defaultMessage: '{count, plural, ' +\n 'one {{count, number} member} ' +\n 'two {{count, number} members} ' +\n 'three {{count, number} members} ' +\n 'few {{count, number} members} ' +\n 'many {{count, number} members} ' +\n 'other {{count, number} members}}',\n description: 'Count of group topic members'\n },\n cannot_parse_vcard: {\n id: 'cannot_parse_vcard',\n defaultMessage: 'Cannot parse vCard file.',\n description: 'Error message when vCard file cannot be parsed'\n }\n});\n\n// Checks if the access permissions are granted but not yet accepted.\nfunction isUnconfirmed(acs) {\n if (acs) {\n const ex = acs.getExcessive() || '';\n return acs.isJoiner('given') && (ex.includes('R') || ex.includes('W'));\n }\n return false;\n}\n\nfunction isPeerRestricted(acs) {\n if (acs) {\n const ms = acs.getMissing() || '';\n return acs.isJoiner('want') && (ms.includes('R') || ms.includes('W'));\n }\n return false;\n}\n\n// Synthetic \"所有人\" entry in the @提醒 picker (mentionSearch below) -- not a real user_id, just a\n// marker mentionSelected/sendMessage recognize to set head.mention_all instead of resolving a\n// Drafty MN entity to it. Never sent to the server as an actual id.\nconst MENTION_ALL_UID = '__mention_all__';\n\nfunction shouldPresentCallPanel(callState) {\n // Show call panel if either:\n // - call is outgoing (and the client is waiting for the other side to pick up) or,\n // - call is already in progress.\n return callState == CALL_STATE_OUTGOING_INITATED || callState == CALL_STATE_IN_PROGRESS;\n}\n\nclass MessagesView extends React.Component {\n constructor(props) {\n super(props);\n\n this.state = MessagesView.getDerivedStateFromProps(props, {});\n // Not topic-specific, fetched once in componentDidMount -- unlike the rest of state this\n // is intentionally not touched by getDerivedStateFromProps on topic change.\n this.state.messagePolicy = null;\n this.state.toast = null;\n this.state.riskDialog = null;\n this.mentionedUsers = [];\n this.mentionAllPending = false;\n\n this.componentSetup = this.componentSetup.bind(this);\n this.leave = this.leave.bind(this);\n this.sendMessage = this.sendMessage.bind(this);\n this.handleRiskConfirm = this.handleRiskConfirm.bind(this);\n this.handleRiskCancel = this.handleRiskCancel.bind(this);\n this.retrySend = this.retrySend.bind(this);\n this.sendImageAttachment = this.sendImageAttachment.bind(this);\n this.sendVideoAttachment = this.sendVideoAttachment.bind(this);\n this.sendFileAttachment = this.sendFileAttachment.bind(this);\n this.sendAudioAttachment = this.sendAudioAttachment.bind(this);\n this.sendTheCardAttachment = this.sendTheCardAttachment.bind(this);\n this.sendKeyPress = this.sendKeyPress.bind(this);\n this.subscribe = this.subscribe.bind(this);\n this.handleScrollReference = this.handleScrollReference.bind(this);\n this.mountDnDEvents = this.mountDnDEvents.bind(this);\n this.handleScrollEvent = this.handleScrollEvent.bind(this);\n this.handleDescChange = this.handleDescChange.bind(this);\n this.handleSubsUpdated = this.handleSubsUpdated.bind(this);\n this.handleMessageUpdate = this.handleMessageUpdate.bind(this);\n this.handleAuxUpdate = this.handleAuxUpdate.bind(this);\n this.handleAllMessagesReceived = this.handleAllMessagesReceived.bind(this);\n this.handleInfoReceipt = this.handleInfoReceipt.bind(this);\n this.handleExpandMedia = this.handleExpandMedia.bind(this);\n this.handleClosePreview = this.handleClosePreview.bind(this);\n this.handleCallPanelToggle = this.handleCallPanelToggle.bind(this);\n this.handleFormResponse = this.handleFormResponse.bind(this);\n this.handleContextClick = this.handleContextClick.bind(this);\n this.handleShowMessageContextMenu = this.handleShowMessageContextMenu.bind(this);\n this.handleNewChatAcceptance = this.handleNewChatAcceptance.bind(this);\n this.handleEnablePeer = this.handleEnablePeer.bind(this);\n this.loadRelationshipContext = this.loadRelationshipContext.bind(this);\n this.loadGroupContext = this.loadGroupContext.bind(this);\n this.loadDraft = this.loadDraft.bind(this);\n this.handleComposerChange = this.handleComposerChange.bind(this);\n this.clearDraft = this.clearDraft.bind(this);\n this.mentionSearch = this.mentionSearch.bind(this);\n this.mentionSelected = this.mentionSelected.bind(this);\n this.handleShowAnnouncement = this.handleShowAnnouncement.bind(this);\n this.handleShowJoinRequests = this.handleShowJoinRequests.bind(this);\n this.handleSendFriendVerification = this.handleSendFriendVerification.bind(this);\n this.handleBatchDelete = this.handleBatchDelete.bind(this);\n this.handleBatchFavorite = this.handleBatchFavorite.bind(this);\n this.handleAttachFile = this.handleAttachFile.bind(this);\n this.handleAttachImageOrVideo = this.handleAttachImageOrVideo.bind(this);\n this.handleCancelUpload = this.handleCancelUpload.bind(this);\n this.postReadNotification = this.postReadNotification.bind(this);\n this.clearNotificationQueue = this.clearNotificationQueue.bind(this);\n this.goToLatestMessage = this.goToLatestMessage.bind(this);\n this.handleFileDrop = this.handleFileDrop.bind(this);\n\n this.handlePickReply = this.handlePickReply.bind(this);\n this.handleEditMessage = this.handleEditMessage.bind(this);\n this.handleCancelReply = this.handleCancelReply.bind(this);\n this.handleQuoteClick = this.handleQuoteClick.bind(this);\n this.jumpToMessage = this.jumpToMessage.bind(this);\n this.handleUnpinMessage = this.handleUnpinMessage.bind(this);\n this.handleCallHangup = this.handleCallHangup.bind(this);\n\n this.isDragEnabled = this.isDragEnabled.bind(this);\n this.handleDragStart = this.handleDragStart.bind(this);\n this.handleDragIn = this.handleDragIn.bind(this);\n this.handleDragOut = this.handleDragOut.bind(this);\n this.handleDrag = this.handleDrag.bind(this);\n this.handleDrop = this.handleDrop.bind(this);\n\n this.chatMessageRefs = [];\n this.getOrCreateMessageRef = this.getOrCreateMessageRef.bind(this);\n this.getVisibleMessageRange = this.getVisibleMessageRange.bind(this);\n\n // Keeps track of the drag event.\n // Need a counter b/c the browser's 'drag' events may fire multiple times\n // when the user takes the mouse pointer over the container:\n // for the component itself and for all nested/child elements.\n this.dragCounter = 0;\n this.dndRef = null;\n\n this.readNotificationQueue = [];\n this.readNotificationTimer = null;\n\n this.keyPressTimer = null;\n }\n\n getOrCreateMessageRef(seqId) {\n if (this.chatMessageRefs[seqId]) {\n return this.chatMessageRefs[seqId];\n }\n const ref = React.createRef();\n this.chatMessageRefs[seqId] = ref;\n return ref;\n }\n\n getVisibleMessageRange(holderRect) {\n let min = Number.MAX_SAFE_INTEGER, max = -1;\n let visibilityStatus = false;\n this.chatMessageRefs.every((ref, seq) => {\n if (ref.current) {\n const { top, bottom, height } = ref.current.getBoundingClientRect();\n const visible = top <= holderRect.top ? holderRect.top - top <= height : bottom - holderRect.bottom <= height;\n if (visible) {\n visibilityStatus = true;\n min = Math.min(min, seq);\n max = Math.max(max, seq);\n } else if (visibilityStatus) {\n // The remaining elements are no longer visible, no need to iterate them.\n return false;\n }\n }\n return true;\n });\n\n return max >= min ? {min: min, max: max} : {min: 0, max: 0};\n }\n\n componentDidMount() {\n if (this.messagesScroller) {\n this.messagesScroller.addEventListener('scroll', this.handleScrollEvent);\n }\n\n // Drag and drop events\n this.mountDnDEvents(this.dndRef);\n\n this.componentSetup({}, {});\n\n getBootstrap().then(data => {\n this.setState({messagePolicy: data.message_policy || null});\n }).catch(_ => {});\n }\n\n componentWillUnmount() {\n // componentSetup below has an identical guard for switching from one topic to another during an\n // active call -- but componentDidUpdate/componentSetup never runs on an actual unmount (leaving\n // the messaging section entirely for another chapter, or on mobile switching to the conversation\n // list while displayMobile). Without this, CallPanel's own componentWillUnmount only tears down\n // local media: it never notifies the peer or resets tinode-web.jsx's top-level callState/\n // callTopic, which then stay stuck at CALL_STATE_IN_PROGRESS. Navigating back to the call's topic\n // later remounts a \"zombie\" CallPanel -- its start() sees that stale CALL_STATE_IN_PROGRESS and\n // takes the \"we just accepted\" branch, which never calls getUserMedia(): no local media, every\n // control disabled, only hang-up works.\n if (this.state.rtcPanel) {\n this.handleCallHangup(this.state.topic, this.props.callSeq);\n }\n if (this.messagesScroller) {\n this.messagesScroller.removeEventListener('scroll', this.handleScrollEvent);\n }\n window.clearTimeout(this.toastTimer);\n\n // Flush all notifications.\n this.clearNotificationQueue();\n\n // Drag and drop events\n if (this.dndRef) {\n this.dndRef.removeEventListener('dragstart', this.handleDragStart);\n this.dndRef.removeEventListener('dragenter', this.handleDragIn);\n this.dndRef.removeEventListener('dragleave', this.handleDragOut);\n this.dndRef.removeEventListener('dragover', this.handleDrag);\n this.dndRef.removeEventListener('drop', this.handleDrop);\n }\n }\n\n componentDidUpdate(prevProps, prevState) {\n // Scroll last message into view on component update e.g. on message received\n // or vertical shrinking.\n if (this.messagesScroller &&\n (prevState.topic != this.state.topic || prevState.maxSeqId != this.state.maxSeqId ||\n prevState.minSeqId != this.state.minSeqId)) {\n // New message.\n if (this.state.scrollPosition < SHOW_GO_TO_LAST_DIST) {\n this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight -\n this.state.scrollPosition - this.messagesScroller.offsetHeight;\n }\n }\n\n if (!this.props.applicationVisible) {\n // If application is not visible, flush all unsent 'read' notifications.\n this.clearNotificationQueue();\n } else {\n // Otherwise assume there are unread messages.\n this.postReadNotification(0);\n }\n\n // Ch.7: jump to a message found via chat-history search (content-library-view.jsx's History),\n // passed in as a ?jumpseq= hash param rather than a normal prop since the navigation that gets us\n // here also has to change the *topic*, which content-library-view.jsx has no direct way to do.\n if (this.props.jumpToSeq && this.props.jumpToSeq != prevProps.jumpToSeq) {\n this.jumpToMessage(parseInt(this.props.jumpToSeq, 10));\n }\n\n this.componentSetup(prevProps, prevState);\n }\n\n componentSetup(prevProps, prevState) {\n const topic = this.props.tinode ? this.props.tinode.getTopic(this.state.topic) : undefined;\n if (this.state.topic != prevState.topic) {\n if (prevState.topic && !Tinode.isNewGroupTopicName(prevState.topic)) {\n this.leave(prevState.topic);\n if (prevState.rtcPanel) {\n this.handleCallHangup(prevState.topic, prevProps.callSeq);\n }\n }\n\n if (topic) {\n topic.onData = this.handleMessageUpdate;\n topic.onAllMessagesReceived = this.handleAllMessagesReceived;\n topic.onInfo = this.handleInfoReceipt;\n topic.onMetaDesc = this.handleDescChange;\n topic.onSubsUpdated = this.handleSubsUpdated;\n topic.onPres = this.handleSubsUpdated;\n topic.onAuxUpdated = this.handleAuxUpdate;\n }\n\n this.mentionedUsers = [];\n this.mentionAllPending = false;\n this.loadRelationshipContext(topic);\n this.loadGroupContext(topic);\n this.loadDraft(topic);\n }\n\n if (topic) {\n if ((this.state.topic != prevState.topic) || (this.props.myUserId && !prevProps.myUserId)) {\n // Don't immediately subscribe to a new p2p topic, wait for the first message.\n const newTopic = (this.props.newTopicParams && this.props.newTopicParams._topicName == this.props.topic);\n if (topic.isP2PType() && newTopic && !IMMEDIATE_P2P_SUBSCRIPTION) {\n topic.getMeta(topic.startMetaQuery().withDesc().build());\n } else if (this.props.myUserId) {\n this.subscribe(topic);\n }\n } else if (topic.isSubscribed() && this.state.isReader && !prevState.isReader) {\n // If reader status has changed and data became available.\n topic.getMeta(topic.startMetaQuery().withLaterData().build());\n } else if (!topic.isSubscribed() && this.props.ready && !prevProps.ready) {\n // Connection restored (e.g. wake from sleep): resubscribe to the currently open topic.\n this.subscribe(topic);\n }\n }\n }\n\n static getDerivedStateFromProps(nextProps, prevState) {\n let nextState = {};\n if (!nextProps.topic) {\n // Default state: no topic.\n nextState = {\n minSeqId: -1,\n maxSeqId: -1,\n latestClearId: -1,\n onlineSubs: [],\n topic: null,\n title: '',\n avatar: null,\n isVerified: false,\n isStaff: false,\n isDangerous: false,\n deleted: false,\n docPreview: null,\n imagePreview: null,\n imagePostview: null,\n videoPreview: null,\n videoPostview: null,\n rtcPanel: null,\n minimizedCallPanel: false,\n typingIndicator: false,\n scrollPosition: 0,\n fetchingMessages: false,\n peerMessagingDisabled: false,\n channel: false,\n reply: null,\n contentToEdit: null,\n showGoToLastButton: false,\n dragging: false,\n pins: [],\n pinsLoaded: false,\n selectedPin: 0,\n subsVersion: 0,\n relationshipContext: null,\n groupRoles: null,\n myGroupRole: null,\n groupAnnouncement: null,\n pendingJoinRequests: 0,\n draftText: null,\n draftVersion: 0\n };\n } else if (nextProps.topic != prevState.topic) {\n const topic = nextProps.tinode.getTopic(nextProps.topic);\n\n nextState = {\n topic: nextProps.topic,\n deleted: topic._deleted,\n docPreview: null,\n imagePreview: null,\n imagePostview: null,\n videoPreview: null,\n videoPostview: null,\n rtcPanel: null,\n minimizedCallPanel: false,\n typingIndicator: false,\n scrollPosition: 0,\n fetchingMessages: false,\n showGoToLastButton: false,\n contentToEdit: null,\n dragging: false,\n selectedPin: 0,\n relationshipContext: null,\n groupRoles: null,\n myGroupRole: null,\n groupAnnouncement: null,\n pendingJoinRequests: 0,\n draftText: null,\n draftVersion: 0,\n // MessagesView isn't remounted on topic switch (no `key={topic}` at the call site in\n // tinode-web.jsx), so a pending risk-check dialog from the conversation just left would\n // otherwise survive the switch -- confirming it would then send the old topic's message\n // into whichever topic is now open, since doSend()'s `this.props.sendMessage` resolves the\n // topic to send to at call time, not at the time the dialog was raised.\n riskDialog: null\n };\n\n if (nextProps.forwardMessage) {\n if (nextProps.forwardMessage.content) {\n const content = nextProps.forwardMessage.content;\n const size = content?.length || (content?.size || 0);\n nextState.docPreview = {\n object: content,\n type: nextProps.forwardMessage.type,\n size: size\n };\n } else {\n // We are forwarding a message. Show preview.\n nextState.reply = {\n content: nextProps.forwardMessage.preview,\n seq: null\n };\n }\n } else {\n nextState.reply = null;\n }\n\n if (topic) {\n // Topic exists.\n const subs = [];\n\n if (nextProps.connected) {\n topic.subscribers((sub) => {\n if (sub.online && sub.user != nextProps.myUserId) {\n subs.push(sub);\n }\n });\n }\n\n Object.assign(nextState, {\n onlineSubs: subs\n });\n\n if (topic.isSelfType()) {\n Object.assign(nextState, {\n title: nextProps.intl.formatMessage(messages.self_topic_name),\n avatar: true\n });\n } else if (topic.public) {\n Object.assign(nextState, {\n title: topicDisplayName(topic.name, topic.public, ''),\n avatar: makeImageUrl(topic.public.photo)\n });\n } else {\n Object.assign(nextState, {\n title: '',\n avatar: null\n });\n }\n\n const peer = topic.p2pPeerDesc();\n if (peer) {\n Object.assign(nextState, {\n peerMessagingDisabled: isPeerRestricted(peer.acs)\n });\n } else if (prevState.peerMessagingDisabled) {\n Object.assign(nextState, {\n peerMessagingDisabled: false\n });\n }\n Object.assign(nextState, {\n minSeqId: topic.minMsgSeq(),\n maxSeqId: topic.maxMsgSeq(),\n latestClearId: topic.maxClearId(),\n channel: topic.isChannelType(),\n pins: (topic.aux('pins') || []).slice(),\n pinsLoaded: false\n });\n\n if (nextProps.callTopic == topic.name && shouldPresentCallPanel(nextProps.callState)) {\n nextState.rtcPanel = nextProps.callTopic;\n }\n } else {\n // Invalid topic.\n Object.assign(nextState, {\n minSeqId: -1,\n maxSeqId: -1,\n latestClearId: -1,\n onlineSubs: [],\n title: '',\n avatar: null,\n peerMessagingDisabled: false,\n channel: false,\n pins: [],\n pinsLoaded: false\n });\n }\n } else {\n // We are still in same topic. Show the call panel if necessary.\n if (nextProps.callTopic == prevState.topic && !prevState.rtcPanel &&\n shouldPresentCallPanel(nextProps.callState)) {\n nextState.rtcPanel = nextProps.callTopic;\n }\n }\n\n if (nextProps.acs) {\n if (nextProps.acs.isWriter() != prevState.isWriter) {\n nextState.isWriter = !prevState.isWriter;\n }\n if (nextProps.acs.isReader() != prevState.isReader) {\n nextState.isReader = !prevState.isReader;\n }\n if (nextProps.acs.isAdmin() != prevState.isAdmin) {\n nextState.isAdmin = !prevState.isAdmin;\n }\n if (!nextProps.acs.isReader('given') != prevState.readingBlocked) {\n nextState.readingBlocked = !prevState.readingBlocked;\n }\n if (nextProps.acs.isSharer() != prevState.isSharer) {\n nextState.isSharer = !prevState.isSharer;\n }\n } else {\n if (prevState.isWriter) {\n nextState.isWriter = false;\n }\n if (prevState.isReader) {\n nextState.isReader = false;\n }\n if (prevState.isAdmin) {\n nextState.isAdmin = false;\n }\n if (!prevState.readingBlocked) {\n nextState.readingBlocked = true;\n }\n if (prevState.isSharer) {\n nextState.isSharer = false;\n }\n }\n\n if (isUnconfirmed(nextProps.acs) == !prevState.unconformed) {\n nextState.unconfirmed = !prevState.unconformed;\n }\n\n // Clear subscribers online when there is no connection.\n if (!nextProps.connected && prevState.onlineSubs && prevState.onlineSubs.length > 0) {\n nextState.onlineSubs = [];\n }\n\n return nextState;\n }\n\n subscribe(topic) {\n if (topic.isSubscribed() || !this.props.ready) {\n return;\n }\n\n // Is this a new topic?\n const newTopic = (this.props.newTopicParams && this.props.newTopicParams._topicName == this.props.topic);\n // Don't request the tags. They are useless unless the user\n // is the owner and is editing the topic.\n let getQuery = topic.startMetaQuery().withLaterDesc().withLaterSub().withAux();\n if (this.state.isReader || newTopic) {\n // Reading is either permitted or we don't know because it's a new topic. Ask for messages.\n getQuery = getQuery.withLaterData(MESSAGES_PAGE);\n if (this.state.isReader) {\n getQuery = getQuery.withLaterDel();\n }\n // And show \"loading\" spinner.\n this.setState({ fetchingMessages: true });\n }\n\n const setQuery = newTopic ? this.props.newTopicParams : undefined;\n topic.subscribe(getQuery.build(), setQuery)\n .then(ctrl => {\n if (ctrl.code == 303) {\n // Redirect to another topic requested.\n HashNavigation.navigateTo(HashNavigation.setUrlTopic('', ctrl.params.topic));\n return;\n }\n if (this.state.topic != ctrl.topic) {\n this.setState({topic: ctrl.topic});\n }\n if (this.state.deleted) {\n this.setState({deleted: false});\n }\n this.props.onNewTopicCreated(this.props.topic, ctrl.topic);\n // If there are unsent messages (except hard-failed and video call messages),\n // try sending them now. Hard-failed and unsent video call messages will be dropped.\n let discard = [];\n topic.queuedMessages(pub => {\n if (pub._sending) {\n return;\n }\n if (pub._fatal || (pub.head && pub.head.webrtc)) {\n // Filter out unsent failed & video call messages.\n discard.push(pub.seq);\n return;\n }\n if (topic.isSubscribed()) {\n this.retrySend(pub);\n }\n });\n if (discard.length > 0) {\n topic.delMessagesList(discard, true);\n }\n })\n .catch(err => {\n console.error(\"Failed subscription to\", this.state.topic, err);\n this.props.onError(err.message, 'err');\n const blankState = MessagesView.getDerivedStateFromProps({}, {});\n blankState.title = this.props.intl.formatMessage(messages.not_found);\n this.setState(blankState);\n });\n }\n\n leave(oldTopicName) {\n if (!oldTopicName || !this.props.tinode.isTopicCached(oldTopicName)) {\n return;\n }\n\n const oldTopic = this.props.tinode.getTopic(oldTopicName);\n if (oldTopic && oldTopic.isSubscribed()) {\n oldTopic.leave(false)\n .catch(_ => { /* do nothing here */ })\n .finally(_ => {\n // We don't care if the request succeeded or failed.\n // The topic is dead regardless.\n this.setState({fetchingMessages: false});\n oldTopic.onData = undefined;\n oldTopic.onAllMessagesReceived = undefined;\n oldTopic.onInfo = undefined;\n oldTopic.onMetaDesc = undefined;\n oldTopic.onSubsUpdated = undefined;\n oldTopic.onPres = undefined;\n oldTopic.onAuxUpdated = undefined;\n });\n }\n }\n\n // Don't use React.createRef as the ref.current is not available in componentDidMount in this component.\n handleScrollReference(node) {\n if (node) {\n node.addEventListener('scroll', this.handleScrollEvent);\n this.messagesScroller = node;\n this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight -\n this.state.scrollPosition - this.messagesScroller.offsetHeight;\n }\n }\n\n // Get older messages and show/hide [go to latest message] button.\n handleScrollEvent(event) {\n const pos = event.target.scrollHeight - event.target.scrollTop - event.target.offsetHeight;\n this.setState({\n scrollPosition: pos,\n // Show [go to latest message] if far enough from bottom and scrolling down.\n showGoToLastButton: (pos > SHOW_GO_TO_LAST_DIST) && (pos < this.state.scrollPosition),\n });\n\n if (this.state.fetchingMessages || this.processingScrollEvent) {\n return;\n }\n\n if (event.target.scrollTop <= FETCH_PAGE_TRIGGER) {\n const topic = this.props.tinode.getTopic(this.state.topic);\n if (topic && topic.isSubscribed()) {\n this.processingScrollEvent = true;\n const {min, max} = this.getVisibleMessageRange(event.target.getBoundingClientRect());\n const gaps = topic.msgHasMoreMessages(min, max, false);\n if (gaps.length > 0) {\n this.setState({fetchingMessages: true}, _ => {\n topic.getMessagesPage(MESSAGES_PAGE, gaps, min, max)\n .catch(err => this.props.onError(err.message, 'err'))\n .finally(_ => this.setState({fetchingMessages: false}));\n });\n }\n }\n }\n this.processingScrollEvent = false;\n }\n\n /* Mount drag and drop events */\n mountDnDEvents(dnd) {\n if (dnd) {\n dnd.addEventListener('dragstart', this.handleDragStart);\n dnd.addEventListener('dragenter', this.handleDragIn);\n dnd.addEventListener('dragleave', this.handleDragOut);\n dnd.addEventListener('dragover', this.handleDrag);\n dnd.addEventListener('drop', this.handleDrop);\n this.dndRef = dnd;\n }\n }\n\n goToLatestMessage() {\n this.setState({scrollPosition: 0});\n if (this.messagesScroller) {\n this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.messagesScroller.offsetHeight;\n }\n }\n\n handleDescChange(desc) {\n if (Tinode.isSelfTopicName(this.props.topic)) {\n this.setState({\n title: this.props.intl.formatMessage(messages.self_topic_name),\n avatar: true\n });\n } else if (desc.public) {\n this.setState({\n title: topicDisplayName(this.props.topic, desc.public, ''),\n avatar: makeImageUrl(desc.public.photo)\n });\n } else {\n this.setState({\n title: '',\n avatar: null\n });\n }\n\n if (desc.acs) {\n this.setState({\n isWriter: desc.acs.isWriter(),\n isReader: desc.acs.isReader(),\n isAdmin: desc.acs.isAdmin(),\n readingBlocked: !desc.acs.isReader('given'),\n unconfirmed: isUnconfirmed(desc.acs),\n });\n }\n }\n\n postReadNotification(seq) {\n // Ignore notifications if the app is invisible or topic is not yet available.\n if (!this.props.applicationVisible || !this.state.topic) {\n return;\n }\n\n // Set up the timer if it's not running already.\n if (!this.readNotificationTimer) {\n this.readNotificationTimer = setInterval(_ => {\n if (this.readNotificationQueue.length == 0) {\n // Shut down the timer if the queue is empty.\n clearInterval(this.readNotificationTimer);\n this.readNotificationTimer = null;\n return;\n }\n\n let seq = -1;\n while (this.readNotificationQueue.length > 0) {\n const n = this.readNotificationQueue[0];\n if (n.topicName != this.state.topic) {\n // Topic has changed. Drop the notification.\n this.readNotificationQueue.shift();\n continue;\n }\n\n const now = new Date();\n if (n.sendAt <= now) {\n // Remove expired notification from queue.\n this.readNotificationQueue.shift();\n if (n.seq == 0 || Tinode.isServerAssignedSeq(n.seq)) {\n seq = Math.max(seq, n.seq);\n }\n } else {\n break;\n }\n }\n\n // Send only one notification for the whole batch of messages.\n if (seq >= 0) {\n const topic = this.props.tinode.getTopic(this.state.topic);\n if (topic) {\n try {\n topic.noteRead(seq);\n } catch (err) {\n console.error(\"Failed to send read notification\", err);\n }\n }\n }\n }, NOTIFICATION_EXEC_INTERVAL);\n }\n\n const now = new Date();\n this.readNotificationQueue.push({\n topicName: this.state.topic,\n seq: seq,\n sendAt: now.setMilliseconds(now.getMilliseconds() + READ_DELAY)\n });\n }\n\n // Clear notification queue and timer.\n clearNotificationQueue() {\n this.readNotificationQueue = [];\n if (this.readNotificationTimer) {\n clearInterval(this.readNotificationTimer);\n this.readNotificationTimer = null;\n }\n }\n\n handleSubsUpdated() {\n if (this.state.topic) {\n const subs = [];\n const topic = this.props.tinode.getTopic(this.state.topic);\n topic.subscribers(sub => {\n if (sub.online && sub.user != this.props.myUserId) {\n subs.push(sub);\n }\n });\n const newState = {onlineSubs: subs, subsVersion: this.state.subsVersion + 1};\n const peer = topic.p2pPeerDesc();\n if (peer) {\n Object.assign(newState, {\n peerMessagingDisabled: isPeerRestricted(peer.acs)\n });\n } else if (this.state.peerMessagingDisabled) {\n Object.assign(newState, {\n peerMessagingDisabled: false\n });\n }\n this.setState(newState);\n }\n }\n\n // The 'msg' could be false-ish if some message ranges were deleted.\n handleMessageUpdate(msg) {\n if (!this.state.topic) {\n return;\n }\n const topic = this.props.tinode.getTopic(this.state.topic);\n if (!msg) {\n // msg could be null if one or more messages were deleted.\n // Updating state to force redraw.\n this.setState({latestClearId: topic.maxClearId()});\n return;\n }\n\n clearTimeout(this.keyPressTimer)\n this.setState({maxSeqId: topic.maxMsgSeq(), minSeqId: topic.minMsgSeq(), typingIndicator: false}, _ => {\n // Scroll to the bottom if the message is added to the end of the message\n // list if already at the bottom, otherwise show [go to latest] button.\n // Implemented as a callback to be sure the scroll height has been updated.\n if (topic.isNewMessage(msg.seq)) {\n if (this.state.scrollPosition > SHOW_GO_TO_LAST_DIST) {\n this.setState({showGoToLastButton: true});\n } else {\n this.goToLatestMessage();\n }\n } else {\n if (this.messagesScroller) {\n this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.state.scrollPosition -\n this.messagesScroller.offsetHeight;\n }\n }\n });\n\n // Aknowledge messages except own messages. They are\n // automatically assumed to be read and recived.\n const status = topic.msgStatus(msg, true);\n if (status >= Tinode.MESSAGE_STATUS_SENT && msg.from != this.props.myUserId) {\n this.postReadNotification(msg.seq);\n }\n }\n\n handleAllMessagesReceived(count) {\n this.setState({fetchingMessages: false});\n if (!count) {\n // All messages received. Nothing left to receive.\n const topic = this.props.tinode.getTopic(this.state.topic);\n if (topic) {\n // Send read notification for the absolute last message.\n this.postReadNotification(topic.seq);\n }\n return;\n }\n\n // Load pinned message too (if any);\n if (!this.state.pinsLoaded) {\n // This needs to be guarded to avoid an infinite loop.\n // The loop may happen if some pinned messages are deleted.\n const topic = this.props.tinode.getTopic(this.state.topic);\n this.setState({pinsLoaded: true}, _ => {\n topic.getPinnedMessages();\n });\n } else {\n this.setState({pinsLoaded: false});\n }\n }\n\n handleAuxUpdate(aux) {\n const pins = (aux['pins'] || []).slice();\n let selectedPin = this.state.selectedPin;\n if (pins.length > this.state.pins.length) {\n // New pins added, show the latest.\n selectedPin = 0;\n } else if (selectedPin >= pins.length) {\n selectedPin = Math.max(0, pins.length - 1);\n }\n this.setState({pins: pins, selectedPin: selectedPin});\n }\n\n handleInfoReceipt(info) {\n switch (info.what) {\n case 'kp': {\n clearTimeout(this.keyPressTimer);\n this.keyPressTimer = setTimeout(_ => this.setState({typingIndicator: false}), KEYPRESS_DELAY + 1000);\n if (!this.state.typingIndicator) {\n this.setState({typingIndicator: true});\n }\n break;\n }\n case 'read':\n case 'recv':\n // Redraw due to changed recv/read status.\n this.forceUpdate();\n break;\n default:\n console.info(\"Other change in topic: \", info.what);\n }\n }\n\n handleExpandMedia(content) {\n if (!content) {\n return;\n }\n\n if (content.video) {\n this.setState({videoPostview: content});\n } else {\n this.setState({imagePostview: content});\n }\n }\n\n handleClosePreview() {\n if (this.state.imagePreview && this.state.imagePreview.url) {\n URL.revokeObjectURL(this.state.imagePreview.url);\n }\n if (this.state.videoPreview && this.state.videoPreview.url) {\n URL.revokeObjectURL(this.state.videoPreview.url);\n }\n this.setState({\n imagePostview: null,\n imagePreview: null,\n docPreview: null,\n videoPreview: null,\n videoPostview: null,\n });\n this.props.onCancelForwardMessage();\n }\n\n handleFormResponse(action, text, data) {\n if (action == 'pub') {\n this.sendMessage(Drafty.attachJSON(Drafty.parse(text), data));\n } else if (action == 'url') {\n const url = new URL(data.ref);\n const params = url.searchParams;\n for (let key in data.resp) {\n if (data.resp.hasOwnProperty(key)) {\n params.set(key, data.resp[key]);\n }\n }\n ['name', 'seq'].forEach(key => {\n if (data[key]) {\n params.set(key, data[key]);\n }\n });\n params.set('uid', this.props.myUserId);\n params.set('topic', this.state.topic);\n url.search = params;\n window.open(url, '_blank');\n } else {\n console.info(\"Unknown action in form\", action);\n }\n }\n\n handleContextClick(e) {\n e.preventDefault();\n e.stopPropagation();\n this.props.showContextMenu({ topicName: this.state.topic, y: e.pageY, x: e.pageX });\n }\n\n handleShowMessageContextMenu(params, messageSpecificMenuItems) {\n if (params.userFrom == 'chan') {\n params.userFrom = this.state.topic;\n params.userName = this.state.title;\n }\n params.topicName = this.state.topic;\n let menuItems = messageSpecificMenuItems || [];\n // Picking \"回复\" on some other message while already editing one (this.state.reply.editing)\n // silently abandons the edit: handlePickReply overwrites this.state.reply wholesale but never\n // touches contentToEdit, so the composer keeps showing the message being edited while the\n // header/send-icon quietly switch to reply mode -- sending then posts that text as a brand new\n // reply to the other message, and the original edit is lost with no confirmation. Simplest fix\n // is the same one already used for menu_item_edit's window check: just don't offer the option\n // that would cause it, rather than trying to reconcile the two states after the fact.\n if (this.state.reply && this.state.reply.editing) {\n menuItems = menuItems.filter(item => item !== 'menu_item_reply');\n }\n const topic = this.props.tinode.getTopic(params.topicName);\n if (topic) {\n // Edit (Ch.4): chat-message.jsx already gated 'menu_item_edit' on writer + non-attachment\n // content, but has no access to the server-configured edit window (that's session-level state\n // living here, not a per-message prop) -- unlike recall just below, this was never actually\n // filtered by age, so an edit attempt on a message well past the window would only fail at\n // send time instead of never showing the option. Same window-check shape as recall's, just\n // removing the item after the fact instead of adding it, since base eligibility already ran.\n const editWindow = this.state.messagePolicy ? this.state.messagePolicy.edit_window_seconds : 0;\n if (menuItems.includes('menu_item_edit') && !(editWindow > 0 && params.timestamp &&\n params.timestamp.getTime() > (new Date().getTime() - editWindow * 1000))) {\n menuItems = menuItems.filter(item => item !== 'menu_item_edit');\n }\n menuItems.push('menu_item_copy', 'menu_item_favorite');\n // Recall (Ch.4): own message, real seq, and still inside the server-configured window.\n // Distinct from delete -- see context-menu.jsx recallOwnMessage for why both exist.\n // A group admin/owner can also recall *other* members' messages within the same window --\n // server/im_http.go's serveIMMessageRecall calls authorizeIMMessageMutation with\n // allowAdmin=true, so the backend has always accepted this; the reference screenshot\n // (消息页面—长按弹出.png) lists \"群撤回\" as its own, always-shown menu item alongside \"撤回\" --\n // this was previously never offered at all since the only condition checked was authorship.\n const recallWindow = this.state.messagePolicy ? this.state.messagePolicy.recall_window_seconds : 0;\n const canRecallAsAdmin = topic.isGroupType() && topic.getAccessMode() && topic.getAccessMode().isAdmin();\n if ((params.userFrom == this.props.myUserId || canRecallAsAdmin) && params.seq > 0 && recallWindow > 0 &&\n params.timestamp && params.timestamp.getTime() > (new Date().getTime() - recallWindow * 1000)) {\n menuItems.push('menu_item_recall');\n }\n // Self -> (1) always hard-delete with [Delete] title.\n // P2P -> (1) hard-delete if allowed and not too old, (2) always soft-delete.\n // Group -> (1) hard-delete if allowed and not too old or owner, (2) always soft-delete.\n if (topic.isSelfType()) {\n // Hard-delete with plain [Delete] title.\n menuItems.push('message_delete_generic');\n } else {\n if (!topic.isChannelType()) {\n // P2P or normal group: always allow to soft-delete.\n menuItems.push('message_delete');\n }\n\n const acs = topic.getAccessMode();\n if (acs && acs.isDeleter()) {\n // Owner can always hard-delete regardless of age.\n let canDelete = acs.isOwner();\n if (!canDelete) {\n // Not owner: check message age if configured on the server.\n const maxDelAge = this.props.tinode.getServerParam(Tinode.MSG_DELETE_AGE, 0) | 0;\n // Make sure the message is not too old. This check is here just to make the UI\n // more user-friendly. The server will enforce the limit regardless of this.\n canDelete = maxDelAge == 0 || (maxDelAge > 0 && params.timestamp ?\n params.timestamp.getTime() > (new Date().getTime() - maxDelAge * 1000) : false);\n }\n if (canDelete) {\n // [Delete for All] title.\n menuItems.push('message_delete_hard');\n }\n }\n }\n }\n menuItems.push('menu_item_select');\n this.props.showContextMenu(params, menuItems);\n }\n\n handleNewChatAcceptance(action) {\n this.props.onNewChat(this.state.topic, action);\n }\n\n handleEnablePeer(e) {\n e.preventDefault();\n this.props.onChangePermissions(this.state.topic, DEFAULT_P2P_ACCESS_MODE, this.state.topic);\n }\n\n // Fetch the real friend/block/pending relationship state for a 1:1 topic so the UI can explain\n // (instead of silently disabling) why sending is restricted. Best-effort: a failed fetch just\n // leaves relationshipContext null and the existing isWriter-based disable stays in effect.\n loadRelationshipContext(topic) {\n if (!topic || !topic.isP2PType()) {\n return;\n }\n const topicName = topic.name;\n getConversationContext(topicName).then(data => {\n if (this.state.topic == topicName) {\n this.setState({relationshipContext: data});\n }\n }).catch(_ => {});\n }\n\n // Ch.6: role badges (docs/images/群标识.png) and the announcement/join-request banners at the top of a\n // group chat (docs/images/群公告状态.png, 新邀请进群申请.png) all need data no P2P topic has -- fetch it\n // once per group-topic-load, same best-effort pattern as loadRelationshipContext above. Every `topic`\n // field these Ch.6 endpoints return is a real grp-prefixed native Tinode name (verified against the Go\n // source), so there's no Ch.5-style translation needed anywhere here.\n loadGroupContext(topic) {\n if (!topic || !topic.isGroupType() || topic.isChannelType()) {\n return;\n }\n const topicName = topic.name;\n getGroupMembers(topicName).then(data => {\n if (this.state.topic != topicName) {\n return;\n }\n const roles = {};\n (data.items || []).forEach(m => { roles[m.user_id] = m.role; });\n this.setState({groupRoles: roles, myGroupRole: roles[this.props.myUserId] || null});\n // Pending join requests can only be resolved by an admin/owner -- only they can act on the banner,\n // and only they pass requireIMGroupMember's IsAdmin() check on the list endpoint itself.\n if (roles[this.props.myUserId] == 'owner' || roles[this.props.myUserId] == 'admin') {\n getGroupJoinRequests(topicName, 'pending').then(reqData => {\n if (this.state.topic == topicName) {\n this.setState({pendingJoinRequests: (reqData.items || []).length});\n }\n }).catch(_ => {});\n }\n }).catch(_ => {});\n getLatestGroupAnnouncement(topicName).then(data => {\n if (this.state.topic == topicName) {\n this.setState({groupAnnouncement: (data && data.content) ? data : null});\n }\n }).catch(_ => {});\n }\n\n // 4.2-4.3 @提醒:只对群话题开放(私聊提@没有意义,也没有可选的\"其他成员\")。返回给\n // send-message.jsx 的选择器渲染,真正的 uid 解析在 mentionSelected 里记下来,供发送时\n // applyMentionResolution 使用。\n mentionSearch(query) {\n const topic = this.props.tinode ? this.props.tinode.getTopic(this.state.topic) : null;\n if (!topic || !topic.isGroupType()) {\n return Promise.resolve([]);\n }\n return getGroupMembers(this.state.topic, {mentionable: true, query}).then(data => {\n const items = data.items || [];\n // \"所有人\" (参考图 @人员—选择提醒人.png 里排在真实成员最前面的合成选项) -- server/topic.go's\n // validateAndNormalizeMentions rejects head.mention_all from anyone who isn't admin\n // (ErrPermissionDenied), so this is only offered to accounts GET .../members already told us\n // can actually use it -- an ineligible account would otherwise see the option, pick it, and\n // have the server silently reject the send.\n const canMentionAll = !!(data.permissions && data.permissions.can_mention_all);\n if (canMentionAll && '所有人'.includes((query || '').trim())) {\n return [{user_id: MENTION_ALL_UID, display_name: '所有人'}, ...items];\n }\n return items;\n });\n }\n\n mentionSelected(uid, name) {\n if (uid === MENTION_ALL_UID) {\n // Not a real Drafty mention to resolve -- sendMessage below reads this flag directly to set\n // head.mention_all, independent of the this.mentionedUsers/applyMentionResolution machinery\n // single-person @提醒 uses. The \"@所有人\" text itself still gets auto-detected by Drafty.parse\n // into an ordinary (uid-less) MN entity and renders highlighted like any other mention --\n // that's just decorative here since the real \"notify everyone\" effect comes from the head flag.\n this.mentionAllPending = true;\n return;\n }\n this.mentionedUsers = (this.mentionedUsers || []).filter(m => m.name !== name);\n this.mentionedUsers.push({uid, name});\n }\n\n // 4.1 跨话题草稿:话题一切换就去问服务端这个会话有没有存过草稿。原生话题名(P2P 用对方\n // user_id)直接可用,接口内部自己会做订阅存在性校验,不需要额外归一化。\n loadDraft(topic) {\n if (!topic) {\n return;\n }\n const topicName = topic.name;\n getTopicDraft(topicName).then(data => {\n if (this.state.topic != topicName) {\n return;\n }\n this.setState({draftText: data.content || '', draftVersion: data.version || 0});\n }).catch(_ => {});\n }\n\n // 输入框每次变化都会调这个(不在这里节流——防抖延迟统一放这一处,跟日报/月报草稿已有的\n // 600ms 防抖是同一个数值,方便以后统一调整)。编辑已有消息、转发预填内容这两种情况下\n // SendMessage 的文本框也会触发 onChange,但那些不是\"新写的草稿\",不应该覆盖真正的草稿。\n //\n // 定时器按话题分开存(this.draftSaveTimers 是个 map),不能像原来那样用单个共享句柄——\n // 那样话题A打字触发的600ms保存,会在300ms后切到话题B打字时被 clearTimeout 直接取消掉,\n // A刚打的字就再也不会发给服务器了。\n //\n // version 在这里(调用的当下,this.state.topic 必然还是 topicName,因为 onMessageChange\n // 只有当前激活话题的 SendMessage 实例会触发)同步捕获进闭包,不能等定时器触发时才去读\n // this.state.draftVersion——那时用户很可能已经切到别的话题,届时重新读到的要么是无关话题\n // 的版本号,要么在判断不匹配时退化成硬编码的 0。后端 PUT .../draft 对 version=0 是\"无条件\n // 跳过乐观锁校验直接覆盖\"而不是\"仅当草稿真的不存在时才创建\"(见\n // docs/IM-后端问题清单-2026-09-04.md),这个 0 一旦被真的发出去,可能无声覆盖掉这段时间里\n // 别的标签页/设备写入的更新草稿。\n handleComposerChange(text) {\n if (this.state.reply && this.state.reply.editing) {\n return;\n }\n if (this.props.forwardMessage) {\n return;\n }\n const topicName = this.state.topic;\n if (!topicName) {\n return;\n }\n const version = this.state.draftVersion || 0;\n this.draftSaveTimers = this.draftSaveTimers || {};\n if (this.draftSaveTimers[topicName]) {\n window.clearTimeout(this.draftSaveTimers[topicName]);\n }\n this.draftSaveTimers[topicName] = window.setTimeout(() => {\n delete this.draftSaveTimers[topicName];\n updateTopicDraft(topicName, text, [], version).then(d => {\n if (this.state.topic == topicName) {\n this.setState({draftVersion: d.version});\n }\n }).catch(_ => {});\n }, 600);\n }\n\n // 消息真的发出去之后,把服务端存的草稿清空——不然重新打开这个会话会看到已经发送过的旧文字。\n // 单纯等下一次防抖自然把空字符串存上去也能达到同样效果,但那样在\"发送后立刻切走\"这个真实\n // 会发生的场景里会有一个几百毫秒的窗口,草稿还是旧内容,不如发送成功后立刻清。\n // knownVersion 由调用方(sendMessage)在发送发起的那一刻同步捕获传入,原因同上——避免在\n // 发送成功回调触发时(用户很可能已经切换话题)重新派生出不可靠的版本号。\n clearDraft(topicName, knownVersion) {\n if (this.draftSaveTimers && this.draftSaveTimers[topicName]) {\n window.clearTimeout(this.draftSaveTimers[topicName]);\n delete this.draftSaveTimers[topicName];\n }\n const version = knownVersion != null ? knownVersion :\n (this.state.topic == topicName) ? (this.state.draftVersion || 0) : 0;\n updateTopicDraft(topicName, '', [], version).then(d => {\n if (this.state.topic == topicName) {\n this.setState({draftText: '', draftVersion: d.version});\n }\n }).catch(_ => {});\n }\n\n // Note: setUrlSidePanel only overwrites path[0] -- called with window.location.hash while a topic is\n // open (path[1] is the open topic), it leaves that segment in place, producing e.g.\n // \"#group-announcement-detail/grpXXX?topic=grpXXX\". handleHashRoute then re-parses path[1] as a topic\n // selector on every hashchange, fighting with the sidepanel that's trying to open and leaving the\n // whole view blank. Build the target hash from an empty path instead of the current one.\n handleShowAnnouncement(e) {\n e.preventDefault();\n // `from=chat` lets Announcement (group-management-view.jsx) tell this entry point apart from\n // the one via group-settings -- both land on the identical path[0]/topic hash otherwise, so\n // without it the \"back\" button can't know whether to return to group-settings or to this chat.\n let hash = HashNavigation.addUrlParam(HashNavigation.setUrlSidePanel('', 'group-announcement-detail'), 'topic', this.state.topic);\n hash = HashNavigation.addUrlParam(hash, 'from', 'chat');\n HashNavigation.navigateTo(hash);\n }\n\n handleShowJoinRequests(e) {\n e.preventDefault();\n // `from=chat` mirrors handleShowAnnouncement above -- lets JoinRequests (group-management-view.jsx)\n // return to this chat instead of always landing on group-governance.\n let hash = HashNavigation.addUrlParam(HashNavigation.setUrlSidePanel('', 'group-join-requests'), 'topic', this.state.topic);\n hash = HashNavigation.addUrlParam(hash, 'from', 'chat');\n HashNavigation.navigateTo(hash);\n }\n\n handleSendFriendVerification(e) {\n e.preventDefault();\n // Same stray-path[1] hazard as handleShowAnnouncement above (build from an empty base, not the\n // current hash, since a topic is open) -- this one additionally never set `uid`, which the\n // friend-verification page needs (contact-management-view.jsx's Verification reads hashParams.uid)\n // to know who the verification is for; for a P2P topic that's simply the topic name itself.\n HashNavigation.navigateTo(HashNavigation.addUrlParam(\n HashNavigation.setUrlSidePanel('', 'friend-verification'), 'uid', this.state.topic));\n }\n\n showToast(text) {\n this.setState({toast: text});\n window.clearTimeout(this.toastTimer);\n // Matches div.toast.show's own fadein(0.5s) + hold(2.5s) + fadeout(0.5s) animation length,\n // so the class is removed right as the CSS fadeout finishes instead of cutting it short.\n this.toastTimer = window.setTimeout(() => this.setState({toast: null}), 3500);\n }\n\n handleBatchDelete() {\n const topic = this.props.tinode.getTopic(this.state.topic);\n if (!topic || !this.props.selectedSeqs.length) {\n return;\n }\n // A selected message may still be queued/uploading (no server-confirmed seq yet, same case\n // context-menu.jsx's single-message deleteMessages guards with cancelSend before falling\n // back to delMessagesList). delMessagesList's normalizeRanges silently drops local-only\n // seqs instead of cancelling them, so left unfiltered a still-uploading attachment would\n // survive \"delete\" and get sent normally once its upload finishes.\n const remaining = this.props.selectedSeqs.filter(seq => !topic.cancelSend(seq));\n if (!remaining.length) {\n this.props.onExitSelectMode();\n return;\n }\n topic.delMessagesList(remaining, true).then(_ => {\n this.props.onExitSelectMode();\n }).catch(err => {\n this.props.onError(err.message, 'err');\n });\n }\n\n // Per docs/images/多选-选中对话内容-收藏成功.png the selection stays visible behind the toast --\n // unlike delete, favoriting doesn't remove the messages, so there's no reason to exit select mode.\n handleBatchFavorite() {\n if (!this.props.selectedSeqs.length) {\n return;\n }\n const topicName = this.state.topic;\n const seqs = this.props.selectedSeqs.slice();\n favoriteMessages(seqs.map(seq => ({topic: topicName, seq}))).then(() => {\n // `result.failed` can't be trusted here: the batch-create endpoint reuses one request-level\n // Idempotency-Key across every message in the batch (docs/IM-后端问题清单-2026-09-04.md,\n // 新增1), so every item after the first silently no-ops via ON DUPLICATE KEY UPDATE and gets\n // folded into `existing_count` -- indistinguishable, from this response alone, from a message\n // that really was already favorited. Re-reading the actual favorites list and checking which\n // of the messages we just asked for really landed sidesteps that ambiguity entirely.\n return getFavorites({type: 'all', limit: 100}).then(data => {\n const items = (data && data.items) || [];\n const landed = new Set(items\n .filter(it => it.source && it.source.topic == topicName)\n .map(it => String(it.source.seq)));\n const missing = seqs.filter(seq => !landed.has(String(seq)));\n if (missing.length === seqs.length) {\n this.props.onError('收藏失败', 'err');\n } else if (missing.length) {\n this.showToast(`已收藏 ${seqs.length - missing.length}/${seqs.length} 条`);\n } else {\n this.showToast('收藏成功');\n }\n });\n }).catch(err => {\n this.props.onError(err.message, 'err');\n });\n }\n\n sendKeyPress(audio) {\n const topic = this.props.tinode.getTopic(this.state.topic);\n if (!topic.isSubscribed()) {\n return;\n }\n if (audio) {\n // Doc's default for the \"user is recording voice\" indicator is OFF unless product opts in\n // (a non-persisted {note what:\"kpa\"} broadcast to every other group member) -- this was firing\n // unconditionally on every recording, contradicting that documented default. No product signal\n // to turn it on yet, so this is a deliberate no-op rather than a removed feature: re-enable by\n // restoring `topic.noteRecording(true);` here if/when that's confirmed wanted.\n return;\n }\n topic.noteKeyPress();\n }\n\n // sendMessage sends the message with an optional subscription to topic first.\n // typeHint (Ch.7): the backend's imMessageType() classifier -- which drives every type-filtered list\n // in this chapter (favorites tabs, chat-history search/media tabs) -- only recognizes a flat\n // content.file_id/content.url key or an explicit head['x-im-type'] hint; it never walks a real\n // Drafty entity array. Since every attachment this app actually sends uses the standard ent[]\n // format (Drafty.attachFile/insertImage/insertVideo), none of them carry a flat file_id, so without\n // this hint every image/video/file/voice message silently classifies as plain \"text\" server-side.\n // Mutates a parsed Drafty document in place, upgrading any auto-detected \"@name\" MN entity whose\n // raw matched text equals a name the user actually picked from the mention dropdown into a real,\n // uid-bearing mention. Entities that don't match anything tracked (a literal \"@word\" the user just\n // typed, or an edited/mismatched name) are left with their raw text value -- Tinode's own renderer\n // already falls back to displaying that gracefully, this only upgrades the ones it safely can.\n applyMentionResolution(parsed) {\n if (!parsed || !Array.isArray(parsed.ent) || !this.mentionedUsers || !this.mentionedUsers.length) {\n return;\n }\n parsed.ent.forEach(e => {\n if (e.tp === 'MN' && e.data && typeof e.data.val === 'string') {\n const match = this.mentionedUsers.find(m => m.name === e.data.val);\n if (match) {\n e.data.val = match.uid;\n }\n }\n });\n }\n\n sendMessage(msg, uploadCompletionPromise, uploader, typeHint) {\n // Captured before the reply/edit branches below possibly rewrite `msg` into a Drafty object\n // (Drafty.append(...) for a reply-with-quote) -- the URL risk check further down keys off\n // `typeof msg == 'string'`, so without this a plain-text reply containing a link would silently\n // skip the check entirely (a fresh, non-reply message with the same text does get checked).\n const originalText = typeof msg === 'string' ? msg : null;\n let head;\n if (!msg && this.props.forwardMessage) {\n // We are forwarding a message.\n msg = this.props.forwardMessage.msg;\n head = this.props.forwardMessage.head;\n this.handleCancelReply();\n } else if (this.state.reply) {\n if (this.state.reply.editing) {\n if (msg == this.state.contentToEdit) {\n // Message unchanged.\n this.handleCancelReply();\n return;\n }\n // Editing an existing message.\n head = {replace: ':' + this.state.reply.seq};\n } else if (this.state.reply.content) {\n // Replying to a message in this topic.\n // Turn it into Drafty so we can make a quoted Drafty object later.\n head = {reply: '' + this.state.reply.seq};\n if (typeof msg == 'string') {\n msg = Drafty.parse(msg);\n this.applyMentionResolution(msg);\n }\n msg = Drafty.append(Drafty.sanitizeEntities(this.state.reply.content), msg);\n }\n this.handleCancelReply();\n } else if (typeof msg == 'string' && this.mentionedUsers && this.mentionedUsers.length) {\n // 4.2-4.3 @提醒:Drafty.parse 本来就会把纯文本里的\"@word\"自动识别成 MN 实体,但\n // data.val 存的是匹配到的原始文字(tinode.dev.js 的 ENTITY_TYPES 表,pack: val =>\n // ({val: val.slice(1)})),不是 uid——那是纯文本解析器,不可能凭空知道 uid。真正的 uid\n // 只在用户从选择器里点选时才知道,记在 this.mentionedUsers 里;这里按显示名回填,把\n // 自动识别出的占位符换成真的 uid。没有任何选过的提醒时完全不碰 msg,维持字符串原样,\n // 交给 SDK 自己在更底层 parse(跟这次改动之前完全一样的行为,不引入任何差异)。\n const parsed = Drafty.parse(msg);\n this.applyMentionResolution(parsed);\n msg = parsed;\n }\n // Was only cleared on topic switch -- picking someone from the @提醒 picker once left them\n // resolvable for every later message in the same topic too, so literal text \"@张三\" typed by\n // hand, pasted, or quoted from someone else in a LATER, unrelated message would silently turn\n // into a real mention of whoever was last picked under that name. A retry of a failed send\n // (retrySend) reuses the already-resolved Drafty content stored on the failed pub, not this\n // array, so clearing it here doesn't affect retries.\n this.mentionedUsers = [];\n if (this.mentionAllPending) {\n // server/topic.go's validateAndNormalizeMentions reads head.mention_all directly -- it's a\n // separate signal from the Drafty MN entity the \"@所有人\" text itself auto-parses into (that\n // entity has no real uid and is purely decorative here, same as any other unresolved mention).\n // Reset immediately after reading, same lifecycle as this.mentionedUsers just above -- a\n // \"所有人\" pick should only apply to the one message being sent right now, not linger into\n // later ones in the same topic.\n head = {...(head || {}), mention_all: true};\n this.mentionAllPending = false;\n }\n if (typeHint) {\n head = {...(head || {}), 'x-im-type': typeHint};\n }\n\n const topicForDraft = this.state.topic;\n // Captured now, not re-read inside the .then() below -- by the time send actually resolves\n // the user may have switched topics, and clearDraft falling back to a hardcoded 0 runs into\n // the same backend version=0-skips-the-lock issue explained in handleComposerChange above.\n const draftVersionAtSend = this.state.draftVersion || 0;\n const doSend = () => {\n const result = this.props.sendMessage(msg, uploadCompletionPromise, uploader, head);\n // Only a plain-text compose (not a reply/edit/forward, all of which pass a Drafty object or\n // reuse contentToEdit rather than the persisted draft) has a server-side draft worth clearing.\n if (originalText != null && result && typeof result.then == 'function' && topicForDraft) {\n result.then(() => this.clearDraft(topicForDraft, draftVersionAtSend));\n }\n return result;\n };\n\n // Pre-send URL risk check (POST /security/urls/check) -- the only Ch.11 \"anti-fraud\" mechanism\n // with a real backend behind it. Only plain-text composed messages are checked (not forwards,\n // uploads, or already-Drafty content) since that's the one path a URL could plausibly be typed in.\n // Returns a promise resolving to `false` when the message was NOT sent (blocked/cancelled) so\n // send-message.jsx can leave the composer text intact instead of optimistically clearing it --\n // without this, a blocked message's text would just vanish with no failed-message trace to retry.\n // Was missing the `g` flag -- .match() without it only ever returns the FIRST url in the message,\n // so a second url (e.g. the phishing link in \"看这个 https://safe.example.com 但是别信这个\n // https://phish.example.com/login?token=abc\") never got checked at all as long as the first one\n // came back `allow`. Check every distinct url in the message and act on the riskiest verdict.\n const urlMatches = originalText && originalText.match(/https?:\\/\\/\\S+/g);\n if (urlMatches) {\n const RISK_RANK = {block: 2, warn: 1, allow: 0};\n const urls = Array.from(new Set(urlMatches));\n return Promise.all(urls.map(url => checkURL(url, 'message_compose'))).then(results => {\n const result = results.reduce((worst, r) => (RISK_RANK[r.decision] || 0) > (RISK_RANK[worst.decision] || 0) ? r : worst);\n if (result.decision === 'allow') {\n return doSend();\n }\n return new Promise(resolve => {\n // riskDialog is a single slot -- if an earlier risk check is still awaiting the user's\n // decision (two messages sent in quick succession, both flagged), overwriting it here\n // would leave that first promise permanently unresolved and its message silently dropped\n // with send-message.jsx never told to stop holding it as unsent. Resolving it `false` first\n // means it's treated the same as the user cancelling it -- lost, but not hung forever.\n if (this.state.riskDialog) this.state.riskDialog.resolve(false);\n this.setState({riskDialog: {blocked: result.decision === 'block', challengeId: result.risk_challenge_id, send: doSend, resolve}});\n });\n }).catch(_ => doSend()); // Don't let a risk-check failure block sending altogether.\n }\n\n return doSend();\n }\n\n handleRiskConfirm() {\n const dialog = this.state.riskDialog;\n if (!dialog) return;\n this.setState({riskDialog: null});\n const finish = () => dialog.resolve(dialog.send());\n if (dialog.challengeId) {\n confirmRiskChallenge(dialog.challengeId, 'continue').then(finish).catch(finish);\n } else {\n finish();\n }\n }\n\n handleRiskCancel() {\n const dialog = this.state.riskDialog;\n if (!dialog) return;\n this.setState({riskDialog: null});\n if (dialog.challengeId && !dialog.blocked) {\n confirmRiskChallenge(dialog.challengeId, 'cancel').catch(_ => {});\n }\n dialog.resolve(false);\n }\n\n // Retry sending a message.\n retrySend(pub) {\n this.props.sendMessage(pub.content, undefined, undefined, pub.head)\n .then(_ => {\n // All good. Remove the original message draft from the cache.\n const topic = this.props.tinode.getTopic(this.state.topic);\n topic.delMessagesList([pub.seq], true);\n });\n }\n\n // sendFileAttachment sends the file as Drafty message:\n // - if file is too large, upload it and send a s link.\n // - if file is small enough, just send it in-band.\n sendFileAttachment(file) {\n // Server-provided limit reduced for base64 encoding and overhead.\n const maxInbandAttachmentSize = (this.props.tinode.getServerParam('maxMessageSize',\n MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024) | 0;\n\n if (TheCard.isFileSupported(file.type, file.name) || file.type == TheCard.contentType) {\n // This is a vCard file, try to convert and send as TheCard.\n if (this.sendTheCardAttachment(file, maxInbandAttachmentSize)) {\n // Successfully sent as TheCard.\n return;\n }\n // Sending as TheCard failed, fall through to sending as generic file attachment.\n }\n\n // If the attachment is a JSON file, then use 'application/octet-stream' instead of 'application/json'.\n // This is a temporary workaround for the collision with the 'application/json' MIME type of form responses.\n // Remove this code in 2026 or so.\n const jsonMimeConverter = (fileType) => fileType === DRAFTY_FR_MIME_TYPE_LEGACY ? 'application/octet-stream' : fileType;\n\n if (file.size > maxInbandAttachmentSize) {\n // Too large to send inband - uploading out of band and sending as a link.\n const uploader = createChatUploader(this.props.tinode);\n if (!uploader) {\n this.props.onError(this.props.intl.formatMessage(messages.cannot_initiate_upload));\n return;\n }\n const uploadCompletionPromise = uploader.upload(file);\n const msg = Drafty.attachFile(null, {\n mime: jsonMimeConverter(file.type),\n filename: file.name,\n size: file.size,\n urlPromise: uploadCompletionPromise\n });\n // Pass data and the uploader to the TinodeWeb.\n this.sendMessage(msg, uploadCompletionPromise, uploader, 'file');\n } else {\n // Small enough to send inband.\n fileToBase64(file)\n .then(b64 => this.sendMessage(Drafty.attachFile(null, {\n mime: jsonMimeConverter(b64.mime),\n data: b64.bits,\n filename: b64.name,\n size: file.size\n }), undefined, undefined, 'file'))\n .catch(err => this.props.onError(err.message, 'err'));\n }\n }\n\n // Convert attached vCard to TheCard and send.\n sendTheCardAttachment(file, maxInbandAttachmentSize) {\n if (file.size > maxInbandAttachmentSize) {\n // Cannot convert to TheCard, send as a generic file attachment instead.\n return false;\n }\n\n if (file.type == TheCard.contentType) {\n // Already TheCard, no need to convert.\n this.sendMessage(Drafty.appendTheCard(null, file.object));\n return true;\n }\n\n importVCard(file)\n .then(card => {\n this.sendMessage(Drafty.appendTheCard(null, card));\n })\n .catch(err => {\n this.props.onError(this.props.intl.formatMessage(messages.cannot_parse_vcard, {error: err.message}), 'err');\n });\n return true;\n }\n\n // handleAttachFile method is called when [Attach file] button is clicked: launch attachment preview.\n handleAttachFile(file) {\n const maxExternAttachmentSize = this.props.tinode.getServerParam('maxFileUploadSize', MAX_EXTERN_ATTACHMENT_SIZE);\n\n if (file.size > maxExternAttachmentSize) {\n // Too large.\n this.props.onError(this.props.intl.formatMessage(messages.file_attachment_too_large,\n {size: bytesToHumanSize(file.size), limit: bytesToHumanSize(maxExternAttachmentSize)}), 'err');\n } else {\n this.setState({\n docPreview: {\n file: file,\n name: file.name,\n size: file.size,\n type: file.type\n }\n });\n }\n }\n\n handleCallHangup(topic, seq) {\n this.props.onVideoCallClosed();\n this.setState({\n rtcPanel: null\n });\n this.props.onCallHangup(topic, seq);\n }\n\n handleCallPanelToggle() {\n this.setState({minimizedCallPanel: !this.state.minimizedCallPanel});\n }\n\n // sendImageAttachment sends the image bits as Drafty message.\n sendImageAttachment(caption, blob) {\n const mime = this.state.imagePreview.mime;\n const width = this.state.imagePreview.width;\n const height = this.state.imagePreview.height;\n const fname = this.state.imagePreview.filename;\n\n // Server-provided limit reduced for base64 encoding and overhead.\n const maxInbandAttachmentSize = (this.props.tinode.getServerParam('maxMessageSize',\n MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024) | 0;\n\n if (blob.size > maxInbandAttachmentSize) {\n // Too large to send inband - uploading out of band and sending as a link.\n const uploader = createChatUploader(this.props.tinode);\n if (!uploader) {\n this.props.onError(this.props.intl.formatMessage(messages.cannot_initiate_upload));\n return;\n }\n const uploadCompletionPromise = uploader.upload(blob);\n\n // Make small preview to show while uploading.\n imageScaled(blob, IMAGE_PREVIEW_DIM, IMAGE_PREVIEW_DIM, -1, false)\n // Convert tiny image into base64 for serialization and previewing.\n .then(scaled => blobToBase64(scaled.blob))\n .then(b64 => {\n let msg = Drafty.insertImage(null, 0, {\n mime: mime,\n _tempPreview: b64.bits, // This preview will not be serialized.\n bits: b64.bits, // Image thumbnail.\n width: width,\n height: height,\n filename: fname,\n size: blob.size,\n urlPromise: uploadCompletionPromise\n });\n if (caption) {\n msg = Drafty.appendLineBreak(msg);\n msg = Drafty.append(msg, Drafty.parse(caption));\n }\n // Pass data and the uploader to the TinodeWeb.\n this.sendMessage(msg, uploadCompletionPromise, uploader, 'image');\n })\n .catch(err => this.props.onError(err, 'err'));\n return;\n }\n\n // Send the image inband if it's not too big. The image has been scaled already\n // in image preview.\n blobToBase64(blob)\n .then(b64 => {\n let msg = Drafty.insertImage(null, 0, {\n mime: b64.mime,\n bits: b64.bits,\n width: width,\n height: height,\n filename: fname,\n size: blob.size\n });\n if (caption) {\n msg = Drafty.appendLineBreak(msg);\n msg = Drafty.append(msg, Drafty.parse(caption));\n }\n this.sendMessage(msg, undefined, undefined, 'image');\n });\n }\n\n // sendVideoAttachment sends the video bits as Drafty message.\n sendVideoAttachment(caption, videoBlob, previewBlob, params) {\n const width = params.width;\n const height = params.height;\n\n // Server-provided limit reduced for base64 encoding and overhead.\n const maxInbandAttachmentSize = (this.props.tinode.getServerParam('maxMessageSize',\n MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024) | 0;\n\n const uploads = [];\n let uploader;\n if ((videoBlob.size + previewBlob.size) > maxInbandAttachmentSize) {\n // One or both are too large to send inband. Uploading out of band and sending as a link.\n uploader = createChatUploader(this.props.tinode);\n if (!uploader) {\n this.props.onError(this.props.intl.formatMessage(messages.cannot_initiate_upload));\n return;\n }\n\n uploads[0] = videoBlob.size > maxInbandAttachmentSize * 0.675 ? uploader.upload(videoBlob) : null;\n uploads[1] = previewBlob.size > maxInbandAttachmentSize * 0.275 ? uploader.upload(previewBlob) : null;\n }\n\n if (uploads.length == 0) {\n // Both video and preview are small enough to send inband.\n Promise.all([blobToBase64(videoBlob), blobToBase64(previewBlob)])\n .then(b64s => {\n const [v64, i64] = b64s;\n let msg = Drafty.insertVideo(null, 0, {\n mime: v64.mime,\n bits: v64.bits,\n preview: i64.bits,\n premime: i64.mime,\n width: width,\n height: height,\n duration: params.duration,\n filename: params.name,\n size: videoBlob.size\n });\n if (caption) {\n msg = Drafty.appendLineBreak(msg);\n msg = Drafty.append(msg, Drafty.parse(caption));\n }\n this.sendMessage(msg, undefined, undefined, 'video');\n });\n return;\n }\n\n const uploadCompletionPromise = Promise.all(uploads);\n\n const b64conv = [];\n // Small video converted to base64.\n b64conv[0] = uploads[0] ? null : blobToBase64(videoBlob);\n // Full-size preview fits inline.\n b64conv[1] = uploads[1] ? null : imageScaled(previewBlob, MAX_IMAGE_DIM, MAX_IMAGE_DIM, -1, false)\n .then(scaled => blobToBase64(scaled.blob));\n // Small preview to show while uploading.\n b64conv[2] = imageScaled(previewBlob, VIDEO_PREVIEW_DIM, VIDEO_PREVIEW_DIM, -1, false)\n .then(scaled => blobToBase64(scaled.blob));\n // Convert tiny image into base64 for serialization and previewing.\n Promise.all(b64conv)\n .then(b64s => {\n const [video, img, preview] = b64s;\n let msg = Drafty.insertVideo(null, 0, {\n mime: params.mime,\n bits: video ? video.bits : null,\n _tempPreview: preview.bits,\n preview: img ? img.bits : preview.bits,\n premime: img ? img.mime : preview.mime,\n width: width,\n height: height,\n duration: params.duration,\n filename: params.name,\n size: videoBlob.size,\n urlPromise: uploadCompletionPromise\n });\n\n if (caption) {\n msg = Drafty.appendLineBreak(msg);\n msg = Drafty.append(msg, Drafty.parse(caption));\n }\n // Pass data and the uploader to the TinodeWeb.\n this.sendMessage(msg, uploadCompletionPromise, uploader, 'video');\n })\n .catch(err => this.props.onError(err.message, 'err'));\n }\n\n // handleAttachImageOrVideo method is called when [Attach image or video] button is clicked: launch image or video preview.\n handleAttachImageOrVideo(file) {\n const maxExternAttachmentSize = this.props.tinode.getServerParam('maxFileUploadSize', MAX_EXTERN_ATTACHMENT_SIZE);\n\n if (file.type.startsWith('video/')) {\n this.setState({videoPreview: {\n url: URL.createObjectURL(file),\n blob: file,\n filename: file.name,\n size: file.size,\n mime: file.type\n }});\n return;\n }\n\n // Get image dimensions and size, optionally scale it down.\n imageScaled(file, MAX_IMAGE_DIM, MAX_IMAGE_DIM, maxExternAttachmentSize, false)\n .then(scaled => {\n this.setState({imagePreview: {\n url: URL.createObjectURL(scaled.blob),\n blob: scaled.blob,\n filename: scaled.name,\n width: scaled.width,\n height: scaled.height,\n size: scaled.blob.size,\n mime: scaled.mime\n }});\n }).catch(err => {\n this.props.onError(err.message, 'err');\n });\n }\n\n // handleFileDrop is called when the user drags & drops a file upon the message view.\n handleFileDrop(files) {\n if (!files || files.length == 0) {\n return;\n }\n const file = files[0];\n if (file.type && file.type.startsWith('image/')) {\n this.handleAttachImageOrVideo(file);\n } else {\n this.handleAttachFile(file);\n }\n }\n\n // sendAudioAttachment sends audio bits inband as Drafty message (no preview).\n sendAudioAttachment(url, preview, duration) {\n fetch(url)\n .then(result => result.blob())\n .then(blob => {\n // Server-provided limit reduced for base64 encoding and overhead.\n const maxInbandAttachmentSize = this.props.tinode.getServerParam('maxMessageSize', MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024;\n if (blob.size > maxInbandAttachmentSize) {\n // Too large to send inband - uploading out of band and sending as a link.\n const uploader = createChatUploader(this.props.tinode);\n if (!uploader) {\n this.props.onError(this.props.intl.formatMessage(messages.cannot_initiate_upload));\n return;\n }\n const uploadCompletionPromise = uploader.upload(blob);\n const msg = Drafty.appendAudio(null, {\n mime: blob.type,\n size: blob.size,\n duration: duration,\n preview: preview,\n urlPromise: uploadCompletionPromise\n });\n // Pass data and the uploader to the TinodeWeb.\n this.sendMessage(msg, uploadCompletionPromise, uploader, 'voice');\n } else {\n // Small enough to send inband.\n blobToBase64(blob)\n .then(b64 => {\n this.sendMessage(Drafty.appendAudio(null, {\n mime: b64.mime,\n bits: b64.bits,\n size: blob.size,\n duration: duration,\n preview: preview,\n }), undefined, undefined, 'voice')\n })\n }\n })\n .catch(err => {this.props.onError(err.message, 'err')});;\n }\n\n handleCancelUpload(seq, uploader) {\n const topic = this.props.tinode.getTopic(this.state.topic);\n const found = topic.findMessage(seq);\n if (found) {\n found._cancelled = true;\n }\n uploader.cancel();\n }\n\n // seq: seq ID of the source message\n // context: message content.\n // senderId: UID of the sender of the source message.\n // senderName: full name of the sender of the original message.\n handlePickReply(seq, content, senderId, senderName) {\n if (!seq || !content) {\n this.setState({reply: null});\n return;\n }\n\n content = typeof content == 'string' ? Drafty.init(content) : content;\n if (Drafty.isValid(content)) {\n content = Drafty.replyContent(content, QUOTED_REPLY_LENGTH);\n } else {\n // /!\\ invalid content.\n content = Drafty.append(Drafty.init('\\u26A0 '),\n Drafty.wrapInto(this.props.intl.formatMessage(messages.invalid_content), 'EM'));\n }\n\n this.setState({\n reply: {\n content: Drafty.quote(senderName, senderId, content),\n seq: seq\n }\n });\n this.props.onCancelForwardMessage();\n }\n\n // seq: seq ID of the message to edit.\n // context: message content.\n handleEditMessage(seq, content) {\n if (!seq || !content) {\n this.setState({reply: null});\n return;\n }\n\n content = typeof content == 'string' ? Drafty.init(content) : content;\n const editable = Drafty.toMarkdown(content);\n if (Drafty.isValid(content)) {\n content = Drafty.replyContent(content, EDIT_PREVIEW_LENGTH);\n } else {\n // /!\\ invalid content.\n content = Drafty.append(Drafty.init('\\u26A0 '),\n Drafty.wrapInto(this.props.intl.formatMessage(messages.invalid_content), 'EM'));\n }\n\n this.setState({\n reply: {\n content: Drafty.quote(this.props.intl.formatMessage(messages.editing_message), null, content),\n seq: seq,\n editing: true\n },\n contentToEdit: editable\n });\n this.props.onCancelForwardMessage();\n }\n\n\n handleCancelReply() {\n this.setState({reply: null, contentToEdit: null});\n this.props.onCancelForwardMessage();\n }\n\n handleQuoteClick(replyToSeq) {\n const ref = this.getOrCreateMessageRef(replyToSeq);\n if (ref && ref.current) {\n ref.current.scrollIntoView({block: \"center\", behavior: \"smooth\"});\n ref.current.classList.add('flash');\n setTimeout(_ => {ref.current.classList.remove('flash')} , 1000);\n } else {\n // Most commonly hit when the target message was deleted/recalled after being found by\n // Ch.7 chat-history search but before this click -- never gets a ref\n // (see jumpToMessage below), so without this the click did nothing visible at all.\n console.error(\"Unresolved message ref\", replyToSeq);\n if (this.props.onError) {\n this.props.onError('该消息已被删除或撤回', 'err');\n }\n }\n }\n\n // Ch.7 chat-history search result -> jump to the message in the real conversation. handleQuoteClick\n // only scrolls to a message already present in this topic's locally-cached message list (used\n // elsewhere for quoted-reply/pinned-message jumps, where that's always true); a search result can\n // point at a message far outside whatever window happens to be loaded, so fetch a window around it\n // first via the native SDK (not the REST search API -- handleQuoteClick reads refs off the SDK's own\n // local topic cache, so the data has to land there, which only getMeta does).\n jumpToMessage(seq) {\n const topic = this.props.tinode && this.props.topic ? this.props.tinode.getTopic(this.props.topic) : null;\n if (!topic || !seq || isNaN(seq)) {\n return;\n }\n HashNavigation.navigateTo(HashNavigation.removeUrlParam(window.location.hash, 'jumpseq'));\n const jump = () => window.setTimeout(() => this.handleQuoteClick(seq), 150);\n if (topic.findMessage(seq)) {\n jump();\n } else {\n topic.getMeta(topic.startMetaQuery().withData(Math.max(1, seq - 20), seq + 21, 41).build())\n .then(jump).catch(err => this.props.onError(err.message, 'err'));\n }\n }\n\n handleUnpinMessage(seq) {\n const topic = this.props.tinode.getTopic(this.state.topic);\n topic.pinMessage(seq, false);\n }\n\n isDragEnabled() {\n // Same editing-state guard as the attach-panel props in render() (see the `editingMessage`\n // local there) -- drag&drop is a second, independent path into handleFileDrop below, which\n // calls handleAttachImageOrVideo/handleAttachFile directly rather than through those props, so\n // gating only the props left this route as a full bypass of that guard: dropping a file while\n // editing a message (without touching the \"+\" button at all) still replaced the edited\n // message's content via sendMessage's head.replace, with no confirmation.\n const editingMessage = !!(this.state.reply && this.state.reply.editing);\n return this.state.isWriter && !this.state.unconfirmed && !this.props.forwardMessage &&\n !this.state.peerMessagingDisabled && !editingMessage;\n }\n\n handleDragStart(e) {\n e.preventDefault();\n e.stopPropagation();\n e.dataTransfer.clearData();\n }\n\n handleDragIn(e) {\n e.preventDefault();\n e.stopPropagation();\n this.dragCounter++;\n if (e.dataTransfer.items && e.dataTransfer.items.length > 0) {\n this.setState({dragging: true});\n }\n }\n\n handleDragOut(e) {\n e.preventDefault();\n e.stopPropagation();\n this.dragCounter--;\n if (this.dragCounter <= 0) {\n this.setState({dragging: false});\n }\n }\n\n handleDrag(e) {\n e.preventDefault();\n e.stopPropagation();\n }\n\n handleDrop(e) {\n e.preventDefault();\n e.stopPropagation();\n this.setState({dragging: false});\n if (this.isDragEnabled() && e.dataTransfer.files && e.dataTransfer.files.length > 0) {\n this.handleFileDrop(e.dataTransfer.files);\n this.dragCounter = 0;\n }\n }\n\n render() {\n const {formatMessage} = this.props.intl;\n\n // P2P call is an overlay, not a separate component because it cannot be\n // re-mounted between full screen/minimized.\n const overlay = this.state.rtcPanel &&\n
    }>\n \n ;\n\n const riskDialog = this.state.riskDialog &&\n ;\n\n let component;\n if (!this.state.topic) {\n component = ;\n\n } else {\n let component2;\n if (this.state.imagePreview) {\n // Preview image before sending.\n component2 = (\n }>\n \n \n );\n } else if (this.state.videoPreview) {\n // Preview video.\n component2 = }>\n \n ;\n\n } else if (this.state.imagePostview) {\n // Expand received image.\n component2 = }>\n \n ;\n\n } else if (this.state.videoPostview) {\n // Play received video.\n component2 = }>\n \n ;\n\n } else if (this.state.docPreview) {\n // Preview attachment before sending.\n if (TheCard.isFileSupported(this.state.docPreview.type, this.state.docPreview.name) ||\n this.state.docPreview.type == TheCard.contentType) {\n component2 = }>\n \n ;\n } else {\n component2 = }>\n \n ;\n }\n } else {\n const topic = this.props.tinode.getTopic(this.state.topic);\n const isChannel = topic.isChannelType() || topic.chan;\n const groupTopic = topic.isGroupType() && !isChannel;\n const icon_badges = [];\n if (topic.trusted) {\n if (topic.trusted.verified) {\n icon_badges.push({icon: 'verified', color: 'badge-inv'});\n }\n if (topic.trusted.staff) {\n icon_badges.push({icon: 'staff', color: 'badge-inv'});\n }\n if (topic.trusted.danger) {\n icon_badges.push({icon: 'dangerous', color: 'badge-inv'});\n }\n }\n\n const pinnedMessages = [];\n this.state.pins.forEach(seq => pinnedMessages.push(topic.latestMsgVersion(seq) || topic.findMessage(seq)));\n\n const messageNodes = [];\n let previousFrom = null;\n let prevDate = null;\n // Set upfront (not just inside the loop below) so an empty (zero-message) conversation still\n // gets the base .chat-box class instead of leaving
      with no class at all.\n let chatBoxClass = groupTopic ? 'chat-box group' : 'chat-box';\n topic.messages((msg, prev, next, i) => {\n let nextFrom = next ? (next.from || 'chan') : null;\n\n let sequence = 'single';\n let thisFrom = msg.from || 'chan';\n if (thisFrom == previousFrom) {\n if (thisFrom == nextFrom) {\n sequence = 'middle';\n } else {\n sequence = 'last';\n }\n } else if (thisFrom == nextFrom) {\n sequence = 'first';\n }\n previousFrom = thisFrom;\n\n const isReply = !(thisFrom == this.props.myUserId);\n const deliveryStatus = topic.msgStatus(msg, true);\n\n let userFrom = thisFrom, userName, userAvatar;\n const user = topic.userDesc(thisFrom);\n if (user && user.public) {\n userName = user.public.fn;\n userAvatar = makeImageUrl(user.public.photo);\n }\n\n // Ref for this chat message.\n const ref = this.getOrCreateMessageRef(msg.seq);\n let replyToSeq = msg.head ? parseInt(msg.head.reply) : null;\n if (!replyToSeq || isNaN(replyToSeq)) {\n replyToSeq = null;\n }\n\n if (msg.hi) {\n // Deleted message.\n messageNodes.push(\n \n );\n } else {\n const thisDate = new Date(msg.ts);\n // This message was sent on a different date than the previous.\n if (!prevDate || prevDate.toDateString() != thisDate.toDateString()) {\n messageNodes.push(\n \n );\n prevDate = thisDate;\n }\n messageNodes.push(\n \n );\n }\n });\n\n let lastSeen = null;\n if (isChannel) {\n if (topic.subcnt) {\n lastSeen = formatMessage(messages.subscriber_count, {count: topic.subcnt});\n }\n } else {\n const cont = this.props.tinode.getMeTopic().getContact(this.state.topic);\n if (cont) {\n if (Tinode.isP2PTopicName(cont.topic)) {\n if (cont.online) {\n lastSeen = formatMessage(messages.online_now);\n } else if (cont.seen) {\n lastSeen = formatMessage(messages.last_seen,\n {timestamp: shortDateFormat(cont.seen.when, this.props.intl.locale)});\n // TODO: also handle user agent in c.seen.ua\n }\n } else if (Tinode.isGroupTopicName(cont.topic)) {\n if (topic.subcnt) {\n lastSeen = formatMessage(messages.member_count, {count: topic.subcnt});\n }\n }\n }\n }\n const avatar = this.state.avatar || true;\n const online = this.state.deleted || topic.isSelfType() ? null :\n this.props.online ? 'online' + (this.state.typingIndicator ? ' typing' : '') : 'offline';\n\n const titleClass = 'panel-title' + (this.state.deleted ? ' deleted' : '');\n const darkModeClass = this.props.colorSchema == 'dark' ? 'dark' : '';\n // sendMessage() unconditionally sends whatever content it's given with head={replace:...}\n // while this.state.reply.editing is set (see sendMessage above) -- it has no way to tell\n // \"the user is still editing the original text\" apart from \"the user just picked a photo/\n // file/card/favorite from the attachment panel while that edit was still open\". Gating the\n // attach entry points closed here (same mechanism already used for forwardMessage below) is\n // simpler and safer than trying to teach sendMessage to distinguish those cases after the fact.\n const editingMessage = !!(this.state.reply && this.state.reply.editing);\n\n let messagesComponent = (\n <>\n {this.state.groupAnnouncement ?\n \n campaign\n {this.state.groupAnnouncement.content}\n chevron_right\n : null}\n {this.state.pendingJoinRequests > 0 ?\n \n person_add_alt\n 新邀请进群申请({this.state.pendingJoinRequests})\n chevron_right\n : null}\n
      \n \n
      \n
        \n {messageNodes}\n
      \n
      \n {!this.state.isReader ?\n
      \n {this.state.readingBlocked ?\n
      \n \n
      \n : null }\n
      \n : null }\n
      \n check {this.state.toast}\n
      \n
      \n {this.state.peerMessagingDisabled && !this.state.unconfirmed ?\n
      \n block .\n
      : null}\n {!this.state.unconfirmed && this.state.relationshipContext &&\n this.state.relationshipContext.relationship == 'pending_inbound' ?\n
      以上是打招呼的消息
      : null}\n {!this.state.unconfirmed && this.state.relationshipContext &&\n this.state.relationshipContext.relationship == 'pending_outbound' ?\n
      好友申请正在等待处理
      : null}\n {!this.state.unconfirmed && this.state.relationshipContext &&\n this.state.relationshipContext.relationship == 'none' ?\n
      你们还不是好友,发送消息前需先验证 发送朋友验证
      : null}\n {this.props.selectMode ?\n \n : this.state.unconfirmed ?\n \n :\n }\n \n );\n\n component2 = (\n <>\n
      \n {this.props.displayMobile ?\n {e.preventDefault(); this.leave(this.state.topic); this.props.onHideMessagesView();}}>\n arrow_back\n \n :\n null}\n
      \n \n {!isChannel ? : null}\n
      \n
      \n
      {\n this.state.title ||\n \n }
      \n
      {lastSeen}
      \n
      \n
      \n {!this.props.displayMobile && this.state.pins.length > 0 ?\n this.setState({selectedPin: index})}\n onSelected={this.handleQuoteClick}\n onCancel={this.handleUnpinMessage} />\n : null}\n {groupTopic ?\n :\n null\n }\n \n
      \n {this.props.displayMobile ?\n <>\n {this.state.pins.length > 0 ?\n this.setState({selectedPin: index})}\n onSelected={this.handleQuoteClick}\n onCancel={this.handleUnpinMessage} />\n : null\n }\n \n \n : null}\n \n {messagesComponent}\n {this.state.dragging && this.isDragEnabled() ?\n
      {formatMessage(messages.drag_file)}
      \n : null}\n \n );\n }\n component =
      {component2}{overlay}{riskDialog}
      \n }\n return component;\n }\n};\n\nexport default injectIntl(MessagesView);\n","// Send message form.\nimport React, { Suspense } from 'react';\nimport { FormattedMessage, defineMessages, injectIntl } from 'react-intl';\nimport { Drafty, TheCard } from 'tinode-sdk';\n\n// Lazy-loading AudioRecorder because it's quite large due to\n// a dependency on webm-duration-fix.\nconst AudioRecorder = React.lazy(_ => import('./audio-recorder.jsx'));\n\nimport { KEYPRESS_DELAY } from '../config.js';\nimport { filePasted } from '../lib/blob-helpers.js';\nimport { replyFormatter } from '../lib/formatters.js';\nimport { forwardFavorites, getFavorites, getFileUrl, getFriends, translateReason } from '../lib/im-api.js';\n\n// 4.5-4.6 表情面板:参考图确认了\"只有2个tab\"(😊表情 / ♡)和\"发送按钮浅蓝禁用、深蓝启用\"这两点,\n// 但没有任何一张图能看清第二个tab具体展示什么内容——判断为\"常用\"(这是这类两tab设计里最常见的\n// 语义,也是本项目其它地方唯一有本地存储依据能撑起来的一种:不存在一个真实的\"收藏表情\"后端概念)。\n// 表情本身的具体清单——纠正一处之前的误判:参考图`表情包展开(发送按钮默认状态).png`/`表情包\n// 发送页面.png`其实清楚画出了一套具体的经典\"黄脸\"贴图(微信/QQ经典表情那种视觉风格),不是没有\n// 图片依据。只是这个项目没有对应的贴图素材资源,做不到跟截图完全一致的视觉,退而求其次选了一组\n// 常见、覆盖面广的系统 Unicode 表情——这是素材缺口下的折中方案,不是\"没有依据、随便选的\"。\nconst EMOJI_LIST = ['😀', '😁', '😂', '🤣', '😃', '😄', '😅', '😆', '😉', '😊', '😋', '😎', '😍', '😘',\n '🥰', '😗', '😙', '😚', '🙂', '🤗', '🤩', '🤔', '🤨', '😐', '😑', '😶', '🙄', '😏', '😣', '😥', '😮',\n '🤐', '😯', '😪', '😫', '🥱', '😴', '😌', '😛', '😜', '😝', '🤤', '😒', '😓', '😔', '😕', '🙃', '🤑',\n '😲', '☹️', '🙁', '😖', '😞', '😟', '😤', '😢', '😭', '😦', '😧', '😨', '😩', '🤯', '😬', '😰', '😱',\n '🥵', '🥶', '😳', '🤪', '😵', '😡', '😠', '🤬', '😷', '🤒', '🤕', '🤢', '🤮', '🥳', '🥴', '🥺', '🤫',\n '🤭', '🧐', '🤓', '😈', '👿', '👍', '👎', '👏', '🙌', '🤝', '🙏', '💪', '❤️', '🧡', '💛', '💚', '💙',\n '💜', '🖤', '💔', '💕', '💯', '🔥', '🎉', '🎂', '🌹', '☀️', '🌙', '⭐'];\n// 跟 content-library-view.jsx 的 TYPE_LABEL 是同一套值(那边是 view 层,这边是 widget,不方便\n// 互相 import,就近各自维护一份小常量)。收藏摘要要优先读 snapshot.content.txt 这个结构化字段,\n// 不能像最初那版一样直接展示 snapshot.text——那是整条 content 原样 JSON.stringify 的结果\n// (例如 {\"txt\":\"...\"}),不是给人看的,之前联调时真被这个坑绊了一次才发现。\nconst FAVORITE_TYPE_LABEL = {image: '[图片]', video: '[视频]', voice: '[语音]', file: '[文件]', link: '[链接]', text: '[文本]'};\nfunction favoriteSummary(item) {\n // image/video/voice favorites' snapshot.content.txt is a placeholder single space in this\n // project's convention (confirmed via a real GET /favorites response) -- reading it as the\n // summary showed a blank line instead of a type label for these three types.\n if (item.type === 'image' || item.type === 'video' || item.type === 'voice') {\n return FAVORITE_TYPE_LABEL[item.type];\n }\n const content = item.snapshot && item.snapshot.content;\n // A text favorite's snapshot.content is a plain string, not a {txt:...} Drafty object --\n // content.txt on it is undefined, which used to fall through all the way to the internal\n // item.type value (\"text\") being shown to the user verbatim.\n if (typeof content === 'string' && content.trim()) return content;\n if (content && typeof content.txt === 'string' && content.txt.trim()) return content.txt;\n return FAVORITE_TYPE_LABEL[item.type] || item.type || item.favorite_id;\n}\nconst RECENT_EMOJI_KEY = 'im-recent-emoji';\nconst MAX_RECENT_EMOJI = 30;\nfunction loadRecentEmoji() {\n try {\n const raw = JSON.parse(localStorage.getItem(RECENT_EMOJI_KEY) || '[]');\n return Array.isArray(raw) ? raw : [];\n } catch (_) {\n return [];\n }\n}\nfunction pushRecentEmoji(emoji) {\n try {\n const list = [emoji].concat(loadRecentEmoji().filter(e => e !== emoji)).slice(0, MAX_RECENT_EMOJI);\n localStorage.setItem(RECENT_EMOJI_KEY, JSON.stringify(list));\n } catch (_) { /* ignore */ }\n}\n\nconst messages = defineMessages({\n messaging_disabled: {\n id: 'messaging_disabled_prompt',\n defaultMessage: 'Messaging disabled',\n description: 'Prompt in SendMessage in read-only topic'\n },\n type_new_message: {\n id: 'new_message_prompt',\n defaultMessage: 'New message',\n description: 'Prompt in send message field'\n },\n add_image_caption: {\n id: 'image_caption_prompt',\n defaultMessage: 'Image caption',\n description: 'Prompt in SendMessage for attached image'\n },\n file_attachment_too_large: {\n id: 'file_attachment_too_large',\n defaultMessage: 'The file size {size} exceeds the {limit} limit.',\n description: 'Error message when attachment is too large'\n },\n cannot_initiate_upload: {\n id: 'cannot_initiate_file_upload',\n defaultMessage: 'Cannot initiate file upload.',\n description: 'Generic error messagewhen attachment fails'\n },\n icon_title_record_voice: {\n id: 'icon_title_record_voice',\n defaultMessage: 'Record voice message',\n description: 'Icon tool tip for recording a voice message'\n },\n icon_title_attach_file: {\n id: 'icon_title_attach_file',\n defaultMessage: 'Attach file',\n description: 'Icon tool tip for attaching a file'\n },\n icon_title_add_image: {\n id: 'icon_title_add_image',\n defaultMessage: 'Add image',\n description: 'Icon tool tip for attaching an image'\n },\n icon_title_send: {\n id: 'icon_title_send',\n defaultMessage: 'Send message',\n description: 'Icon tool tip for sending a message'\n },\n});\n\nclass SendMessage extends React.PureComponent {\n constructor(props) {\n super(props);\n\n this.state = {\n quote: null,\n message: '',\n audioRec: false,\n audioAvailable: !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia),\n // @提醒选择器:mentionQuery 非 null 时显示面板;mentionStart 是触发这次匹配的\"@\"在\n // message 里的字符下标(不是 fmt/grapheme 下标,纯 JS 字符串下标,跟 slice 配对用)。\n mentionQuery: null,\n mentionResults: [],\n mentionHighlight: 0,\n emojiOpen: false,\n emojiTab: 'emoji',\n recentEmoji: loadRecentEmoji(),\n attachOpen: false,\n cardPicker: null,\n favPicker: null,\n audioCancelling: false,\n };\n\n // Timestamp when the previous key press was sent to the server.\n this.keypressTimestamp = 0;\n\n this.handlePasteEvent = this.handlePasteEvent.bind(this);\n this.handleAttachImage = this.handleAttachImage.bind(this);\n this.handleAttachFile = this.handleAttachFile.bind(this);\n this.handleAttachAudio = this.handleAttachAudio.bind(this);\n this.handleSend = this.handleSend.bind(this);\n this.handleKeyPress = this.handleKeyPress.bind(this);\n this.handleMessageTyping = this.handleMessageTyping.bind(this);\n this.handleDropAttach = this.handleDropAttach.bind(this);\n\n this.handleQuoteClick = this.handleQuoteClick.bind(this);\n this.selectMention = this.selectMention.bind(this);\n this.startHoldRecording = this.startHoldRecording.bind(this);\n this.handleHoldMove = this.handleHoldMove.bind(this);\n this.endHoldRecording = this.endHoldRecording.bind(this);\n this.handleHoldVisibilityChange = this.handleHoldVisibilityChange.bind(this);\n this.toggleEmojiPanel = this.toggleEmojiPanel.bind(this);\n this.insertEmoji = this.insertEmoji.bind(this);\n this.deleteLastChar = this.deleteLastChar.bind(this);\n this.toggleAttachPanel = this.toggleAttachPanel.bind(this);\n this.openCardPicker = this.openCardPicker.bind(this);\n this.openFavPicker = this.openFavPicker.bind(this);\n this.sendCard = this.sendCard.bind(this);\n this.sendFavorite = this.sendFavorite.bind(this);\n\n this.formatReply = this.formatReply.bind(this);\n }\n\n componentDidMount() {\n if (this.messageEditArea) {\n this.messageEditArea.addEventListener('paste', this.handlePasteEvent, false);\n if (window.getComputedStyle(this.messageEditArea).getPropertyValue('transition-property') == 'all') {\n // Set focus on desktop, but not on mobile: focus causes soft keyboard to pop up.\n this.messageEditArea.focus();\n }\n }\n\n this.setState({quote: this.formatReply()});\n }\n\n componentWillUnmount() {\n if (this.messageEditArea) {\n this.messageEditArea.removeEventListener('paste', this.handlePasteEvent, false);\n }\n if (this.mentionSearchTimer) {\n window.clearTimeout(this.mentionSearchTimer);\n }\n window.removeEventListener('mousemove', this.handleHoldMove);\n window.removeEventListener('mouseup', this.endHoldRecording);\n window.removeEventListener('touchmove', this.handleHoldMove);\n window.removeEventListener('touchend', this.endHoldRecording);\n window.removeEventListener('blur', this.endHoldRecording);\n document.removeEventListener('visibilitychange', this.handleHoldVisibilityChange);\n }\n\n componentDidUpdate(prevProps) {\n if (this.messageEditArea) {\n if (window.getComputedStyle(this.messageEditArea).getPropertyValue('transition-property') == 'all') {\n // Set focus on desktop, but not on mobile: focus causes soft keyboard to pop up.\n this.messageEditArea.focus();\n }\n\n // Adjust height of the message area for the amount of text.\n this.messageEditArea.style.height = '0px';\n this.messageEditArea.style.height = this.messageEditArea.scrollHeight + 'px';\n }\n\n if (prevProps.topicName != this.props.topicName) {\n this.setState({message: this.props.initMessage || '', audioRec: false, quote: null, mentionQuery: null,\n mentionResults: [], emojiOpen: false, attachOpen: false, cardPicker: null, favPicker: null});\n } else if (!prevProps.disabled && this.props.disabled && this.state.audioRec) {\n // isWriter/etc are real-time ACS bits (messages-view.jsx re-derives them from {pres}/{meta}),\n // so `disabled` can flip to true mid-recording -- the other party blocking you, being removed\n // from a group, or getting muted, all without the user releasing the hold-to-talk button first.\n // Unmounting here (rather than leaving it mounted under a now-hidden branch)\n // is what actually stops the mic via its componentWillUnmount; without this the recording just\n // sits there with `disabled` true and no surviving UI able to end it, and if `disabled` later\n // reverts to false in the same topic, this stale `true` would remount a fresh \n // with no user gesture at all -- silently starting to record again on its own.\n //\n // By the time this runs, React has already committed the `disabled` render and unmounted\n // (its ref callback nulled this.audioRecorderInstance), so endHoldRecording()'s\n // own handleDone/handleDelete call is a no-op here -- it's called anyway for the six\n // mousemove/mouseup/touchmove/touchend/blur/visibilitychange listeners startHoldRecording\n // registered on window/document, which endHoldRecording always removes unconditionally\n // regardless of whether the recorder instance is still around. Skipping this left them\n // dangling until the next real mouseup/touchend/blur/tab-switch happened to fire.\n this.endHoldRecording();\n this.setState({audioRec: false});\n } else if (prevProps.initMessage != this.props.initMessage) {\n const msg = this.props.initMessage || '';\n this.setState({message: msg}, _ => {\n // If there is text, scroll to bottom and set caret to the end.\n this.messageEditArea.scrollTop = this.messageEditArea.scrollHeight;\n this.messageEditArea.setSelectionRange(msg.length, msg.length);\n });\n }\n if (prevProps.reply != this.props.reply) {\n this.setState({quote: this.formatReply()});\n }\n }\n\n formatReply() {\n return this.props.reply ?\n Drafty.format(this.props.reply.content, replyFormatter, {\n formatMessage: this.props.intl.formatMessage.bind(this.props.intl),\n authorizeURL: this.props.tinode.authorizeURL.bind(this.props.tinode)\n }) : null;\n }\n\n handlePasteEvent(e) {\n if (this.props.disabled) {\n return;\n }\n // onAttachImage/onAttachFile are explicitly null while forwarding a message\n // (messages-view.jsx) -- pasting a file in that state used to throw\n // \"onAttachImage is not a function\" instead of just not attaching anything.\n // FIXME: handle large files too.\n if (filePasted(e,\n file => { if (this.props.onAttachImage) { this.props.onAttachImage(file); } },\n file => { if (this.props.onAttachFile) { this.props.onAttachFile(file); } },\n this.props.onError)) {\n\n // If a file was pasted, don't paste base64 data into input field.\n e.preventDefault();\n }\n }\n\n handleAttachImage(e) {\n if (e.target.files && e.target.files.length > 0 && this.props.onAttachImage) {\n this.props.onAttachImage(e.target.files[0]);\n }\n // Clear the value so the same file can be uploaded again.\n e.target.value = '';\n }\n\n handleAttachFile(e) {\n if (e.target.files && e.target.files.length > 0 && this.props.onAttachFile) {\n this.props.onAttachFile(e.target.files[0]);\n }\n // Clear the value so the same file can be uploaded again.\n e.target.value = '';\n }\n\n handleDropAttach(files) {\n if (files && files.length > 0 && this.props.onAttachFile) {\n this.props.onAttachFile(files[0]);\n }\n }\n\n handleAttachAudio(url, preview, duration) {\n this.setState({audioRec: false});\n if (this.props.onAttachAudio) {\n this.props.onAttachAudio(url, preview, duration);\n }\n }\n\n handleSend(e) {\n e.preventDefault();\n const message = this.state.message.trim();\n if (message || this.props.acceptBlank || this.props.noInput) {\n const result = this.props.onSendMessage(message);\n // onSendMessage may return a promise resolving to `false` when a pre-send risk check blocked\n // or the user cancelled it -- in that case keep the composer text so nothing typed is lost.\n if (result && typeof result.then == 'function') {\n result.then(sent => { if (sent !== false) this.setState({message: ''}); });\n } else {\n this.setState({message: ''});\n }\n }\n }\n\n /* Send on Enter key */\n handleKeyPress(e) {\n if (this.state.audioRec) {\n // Ignore key presses while audio is being recorded.\n e.preventDefault();\n e.stopPropagation();\n return;\n }\n\n if (this.state.mentionQuery != null) {\n if (e.key === 'Escape') {\n e.preventDefault();\n this.setState({mentionQuery: null, mentionResults: []});\n return;\n }\n if (this.state.mentionResults.length > 0 && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {\n e.preventDefault();\n const delta = e.key === 'ArrowDown' ? 1 : -1;\n const count = this.state.mentionResults.length;\n this.setState({mentionHighlight: (this.state.mentionHighlight + delta + count) % count});\n return;\n }\n if (e.key === 'Enter' && this.state.mentionResults.length > 0) {\n e.preventDefault();\n e.stopPropagation();\n this.selectMention(this.state.mentionResults[this.state.mentionHighlight]);\n return;\n }\n }\n\n // Enter pressed: either send, or enter a new line.\n if (e.key === 'Enter') {\n if (this.props.sendOnEnter == 'plain') {\n // Have Shift-Enter insert a line break instead\n if (!e.shiftKey) {\n e.preventDefault();\n e.stopPropagation();\n\n this.handleSend(e);\n }\n } else {\n if (e.ctrlKey || e.metaKey) {\n e.preventDefault();\n e.stopPropagation();\n\n this.handleSend(e);\n }\n }\n }\n }\n\n handleMessageTyping(e) {\n this.setState({message: e.target.value});\n this.updateMentionState(e.target.value, e.target.selectionStart);\n if (this.props.onMessageChange) {\n this.props.onMessageChange(e.target.value);\n }\n if (this.props.onKeyPress) {\n const now = new Date().getTime();\n if (now - this.keypressTimestamp > KEYPRESS_DELAY) {\n this.props.onKeyPress();\n this.keypressTimestamp = now;\n }\n }\n }\n\n // 4.2-4.3 @提醒:只在群聊里挂 onMentionSearch(messages-view.jsx 只给群话题传这个 prop)。\n // 触发条件是\"光标前最近一个'@','@'前面是空白或整段开头,'@'和光标之间没有空白\"——这样\n // \"联系xx@xx.com\"这种邮箱场景里的@不会被误当成提醒触发。\n updateMentionState(text, caret) {\n if (!this.props.onMentionSearch || caret == null) {\n return;\n }\n const before = text.slice(0, caret);\n const match = /(?:^|\\s)@([^\\s@]*)$/.exec(before);\n if (!match) {\n if (this.state.mentionQuery != null) {\n this.setState({mentionQuery: null, mentionResults: []});\n }\n return;\n }\n const query = match[1];\n const start = caret - query.length - 1;\n this.setState({mentionQuery: query, mentionStart: start, mentionHighlight: 0});\n if (this.mentionSearchTimer) {\n window.clearTimeout(this.mentionSearchTimer);\n }\n this.mentionSearchTimer = window.setTimeout(() => {\n this.props.onMentionSearch(query).then(results => {\n // mentionQuery may have moved on (user kept typing, or closed the picker) by the time this\n // resolves -- only apply it if we're still showing a picker at all, matching the same\n // stale-response guard used everywhere else responses race state.\n if (this.state.mentionQuery != null) {\n this.setState({mentionResults: results || []});\n }\n }).catch(() => {});\n }, 200);\n }\n\n selectMention(item) {\n const {message, mentionStart, mentionQuery} = this.state;\n if (mentionStart == null || mentionQuery == null) {\n return;\n }\n const name = item.group_nickname || item.display_name || item.user_id;\n const insertion = '@' + name + ' ';\n const end = mentionStart + 1 + mentionQuery.length;\n const newMessage = message.slice(0, mentionStart) + insertion + message.slice(end);\n const caretPos = mentionStart + insertion.length;\n this.setState({message: newMessage, mentionQuery: null, mentionResults: []});\n if (this.props.onMentionSelected) {\n this.props.onMentionSelected(item.user_id, name);\n }\n if (this.props.onMessageChange) {\n this.props.onMessageChange(newMessage);\n }\n // Textarea's own DOM value needs the same update -- setState alone re-renders with the right\n // `value` prop, but the caret placement below needs the element's real value/selection to\n // already match, and doing it in the same tick (rather than waiting on the render) avoids a\n // visible flash of the stale text with the caret in the wrong place.\n requestAnimationFrame(() => {\n if (this.messageEditArea) {\n this.messageEditArea.focus();\n this.messageEditArea.setSelectionRange(caretPos, caretPos);\n }\n });\n }\n\n handleQuoteClick(e) {\n e.preventDefault();\n e.stopPropagation();\n if (this.props.reply && this.props.onQuoteClick) {\n const replyToSeq = this.props.reply.seq;\n this.props.onQuoteClick(replyToSeq);\n }\n }\n\n // 组合面板图标切换规律(核对图片确认):表情/附件两个入口固定在输入框右侧;哪个面板当前\n // 展开,对应的那个图标就变成\"⌨\"(点击收起换回键盘),另一个保持原样不变——不是两个一起变。\n // 这里只做了表情这一侧,附件面板(4.13/4.9-4.14)另外接线时要遵守同一条规则,不要各自发明。\n toggleEmojiPanel(e) {\n e.preventDefault();\n this.setState(s => ({emojiOpen: !s.emojiOpen, attachOpen: false, audioRec: false}));\n }\n\n insertEmoji(emoji) {\n const ta = this.messageEditArea;\n const start = ta ? ta.selectionStart : this.state.message.length;\n const end = ta ? ta.selectionEnd : this.state.message.length;\n const newMessage = this.state.message.slice(0, start) + emoji + this.state.message.slice(end);\n pushRecentEmoji(emoji);\n this.setState({message: newMessage, recentEmoji: loadRecentEmoji()});\n if (this.props.onMessageChange) {\n this.props.onMessageChange(newMessage);\n }\n const caretPosEmoji = start + emoji.length;\n requestAnimationFrame(() => {\n if (this.messageEditArea) {\n this.messageEditArea.focus();\n this.messageEditArea.setSelectionRange(caretPosEmoji, caretPosEmoji);\n }\n });\n }\n\n // 参考图的表情面板自带一个退格键,让\"只点表情不碰键盘\"这条路径也能删掉打错的字符——用\n // Array.from 而不是 slice(0,-1) 切最后一个 Unicode 码点,避免把一个占两个UTF-16码元的emoji\n // (比如复合肤色/家庭类emoji)齐腰斩断,删出半个乱码字符。\n deleteLastChar() {\n const ta = this.messageEditArea;\n const start = ta ? ta.selectionStart : this.state.message.length;\n const end = ta ? ta.selectionEnd : this.state.message.length;\n let newMessage, caretPos;\n if (start !== end) {\n newMessage = this.state.message.slice(0, start) + this.state.message.slice(end);\n caretPos = start;\n } else if (start > 0) {\n const before = Array.from(this.state.message.slice(0, start));\n before.pop();\n newMessage = before.join('') + this.state.message.slice(start);\n caretPos = before.join('').length;\n } else {\n return;\n }\n this.setState({message: newMessage});\n if (this.props.onMessageChange) {\n this.props.onMessageChange(newMessage);\n }\n requestAnimationFrame(() => {\n if (this.messageEditArea) {\n this.messageEditArea.focus();\n this.messageEditArea.setSelectionRange(caretPos, caretPos);\n }\n });\n }\n\n toggleAttachPanel(e) {\n e.preventDefault();\n this.setState(s => ({attachOpen: !s.attachOpen, emojiOpen: false}));\n }\n\n // 3.12/4.9-4.14 发名片:选一个好友,生成一张只含姓名+头像+该好友 uid 的名片消息发到当前会话。\n // uid 必须用 TheCard.setTinodeID 写进 comm 数组(vCard 的\"tinode\"协议项),不是随便塞进某个\n // 字段——widgets/the-card-mini.jsx 点开这张卡片时用 TheCard.getFirstTinodeID(card) 读这个\n // 协议项来判断\"发消息\"按钮该指向谁,写错地方那个按钮会永远不出现。\n openCardPicker(e) {\n e.preventDefault();\n this.setState({attachOpen: false, cardPicker: {loading: true}});\n getFriends().then(data => {\n this.setState({cardPicker: {loading: false, items: data.items || []}});\n }).catch(() => this.setState({cardPicker: {loading: false, items: [], error: true}}));\n }\n\n sendCard(item) {\n this.setState({cardPicker: null});\n const build = avatarUrl => {\n const card = new TheCard(item.display_name || item.user_id, avatarUrl);\n TheCard.setTinodeID(card, item.user_id);\n // Every other attachment sender (image/video/file/voice) threads a typeHint through to\n // messages-view.jsx's sendMessage(msg, uploadCompletionPromise, uploader, typeHint) so the\n // backend's imMessageType() classifier -- which only ever looks at head['x-im-type'] or a flat\n // content.file_id/url, never at real Drafty entities -- doesn't fall through to its \"text\"\n // default. This call was only ever passing the first argument, so every card message has been\n // silently misclassified as plain text (confirmed live: search/history summarize it as raw\n // Drafty JSON instead of a name).\n this.props.onSendMessage(Drafty.appendTheCard(null, card), undefined, undefined, 'card');\n };\n if (item.avatar_file_id) {\n getFileUrl(item.avatar_file_id).then(build).catch(() => build(undefined));\n } else {\n build(undefined);\n }\n }\n\n // 收藏发送:走的是 Ch.7 已有的 forwardFavorites REST 接口(转发收藏的同一个接口,目标只给\n // 当前会话一个),不经过 onSendMessage/Drafty——收藏本来就是后端已经存好快照的独立资源,\n // 不是本地新拼一条消息。\n openFavPicker(e) {\n e.preventDefault();\n this.setState({attachOpen: false, favPicker: {loading: true}});\n getFavorites({type: 'all'}).then(data => {\n this.setState({favPicker: {loading: false, items: data.items || []}});\n }).catch(() => this.setState({favPicker: {loading: false, items: [], error: true}}));\n }\n\n sendFavorite(item) {\n this.setState({favPicker: null});\n if (!this.props.topicName) {\n return;\n }\n // 这个接口恒定 200,真实成败要看 items[].status(跟批量收藏/批量转发是同一套设计,全局代码\n // 审查那一轮已经在其它几处调用点踩过同一个坑并修过——这是新写的这处,同样的坑要一起避开,\n // 不能只 .catch 网络层错误就当万事大吉。联调时真的用这条路径测出过 200 OK 但\n // items[0].status:\"failed\"、reason:\"PERMISSION_DENIED\" 的情况(对方是真实好友、这个会话\n // 本身正常能发消息),看起来是后端这个接口自己的权限判断有问题,不是本地能修的,如实报错\n // 而不是假装发送成功。\n forwardFavorites([item.favorite_id], [this.props.topicName]).then(result => {\n const failed = (result && result.items || []).filter(r => r.status === 'failed');\n if (failed.length && this.props.onError) {\n this.props.onError('发送失败:' + (translateReason(failed[0].reason) || failed[0].reason || '未知原因'), 'err');\n }\n }).catch(err => {\n if (this.props.onError) {\n this.props.onError((err && err.message) || '发送失败', 'err');\n }\n });\n }\n\n // 4.7-4.9 按住说话 + 上滑取消:mousedown/touchstart 直接挂载 AudioRecorder(挂载即开始录音,\n // 这一步跟原来点一下进入录音模式完全一样,没有改 AudioRecorder 自己的录音逻辑),松手时通过\n // ref 直接调它的 handleDone/handleDelete——这两个方法本来是绑给它自己按钮的 onClick,要求一个\n // 带 preventDefault 的事件对象,这里传一个最小的假事件满足这个要求,除此之外没有更深地伸手进\n // 它的内部状态。上滑距离阈值 80px 是参照大多数同类应用(微信等)的常见取值,没有对应的可验证\n // 数值来源,明确记录不是抄的哪个具体规格。\n startHoldRecording(e) {\n e.preventDefault();\n if (this.state.audioRec) {\n return;\n }\n this.holdStartY = 'touches' in e ? (e.touches[0] && e.touches[0].clientY) : e.clientY;\n this.setState({audioRec: true, audioCancelling: false, emojiOpen: false, attachOpen: false});\n window.addEventListener('mousemove', this.handleHoldMove);\n window.addEventListener('mouseup', this.endHoldRecording);\n window.addEventListener('touchmove', this.handleHoldMove, {passive: false});\n window.addEventListener('touchend', this.endHoldRecording);\n // mouseup/touchend only fire for a release point still inside this window/tab -- dragging the\n // pointer out of the browser entirely, switching tabs/apps, or a permission prompt stealing\n // focus (e.g. the very getUserMedia prompt this recording itself triggered, on a second call)\n // all leave the mic running with no further event this listener pair will ever see. Ending the\n // recording (same finish-or-cancel logic as a normal release, per the cancel-zone check) on\n // either signal is a safer default than waiting indefinitely for a mouseup that may never come.\n window.addEventListener('blur', this.endHoldRecording);\n document.addEventListener('visibilitychange', this.handleHoldVisibilityChange);\n }\n\n handleHoldVisibilityChange() {\n if (document.hidden) {\n this.endHoldRecording();\n }\n }\n\n handleHoldMove(e) {\n const y = 'touches' in e ? (e.touches[0] && e.touches[0].clientY) : e.clientY;\n if (y == null || this.holdStartY == null) {\n return;\n }\n const cancelling = (this.holdStartY - y) > 80;\n if (cancelling !== this.state.audioCancelling) {\n this.setState({audioCancelling: cancelling});\n }\n }\n\n endHoldRecording() {\n window.removeEventListener('mousemove', this.handleHoldMove);\n window.removeEventListener('mouseup', this.endHoldRecording);\n window.removeEventListener('touchmove', this.handleHoldMove);\n window.removeEventListener('touchend', this.endHoldRecording);\n window.removeEventListener('blur', this.endHoldRecording);\n document.removeEventListener('visibilitychange', this.handleHoldVisibilityChange);\n this.holdStartY = null;\n const fakeEvent = {preventDefault: () => {}};\n if (this.audioRecorderInstance) {\n if (this.state.audioCancelling) {\n this.audioRecorderInstance.handleDelete(fakeEvent);\n } else {\n this.audioRecorderInstance.handleDone(fakeEvent);\n }\n }\n }\n\n render() {\n const { formatMessage } = this.props.intl;\n const prompt = this.props.disabled ?\n formatMessage(messages.messaging_disabled) :\n (this.props.messagePrompt ?\n formatMessage(messages[this.props.messagePrompt]) :\n formatMessage(messages.type_new_message));\n\n const sendIcon = (this.props.reply && this.props.reply.editing) ?\n 'check_circle' : 'send';\n\n const quote = this.state.quote ?\n () : null;\n const audioEnabled = this.state.audioAvailable && this.props.onAttachAudio;\n const mentionPanel = this.state.mentionQuery != null ?\n (
      \n {this.state.mentionResults.length === 0 ?\n
      无匹配成员
      :\n this.state.mentionResults.map((item, i) => (\n
      { e.preventDefault(); this.selectMention(item); }}\n onMouseEnter={() => this.setState({mentionHighlight: i})}>\n {item.group_nickname || item.display_name || item.user_id}\n
      \n ))}\n
      ) : null;\n return (\n
      \n {!this.props.noInput ? quote : null}\n {mentionPanel}\n
      \n {!this.props.disabled ?\n <>\n {this.props.noInput ?\n (quote ||
      ) :\n (this.state.audioRec ?\n (
      }>\n {this.audioRecorderInstance = ref;}}\n holdMode={true}\n cancelling={this.state.audioCancelling}\n onRecordingProgress={_ => this.props.onKeyPress(true)}\n onDeleted={_ => this.setState({audioRec: false})}\n onFinished={this.handleAttachAudio}/>\n ) :\n