diff --git a/index.js b/index.js
index 6efc390c..eb2b4b47 100644
--- a/index.js
+++ b/index.js
@@ -37,10 +37,13 @@ var AVATAR_SIZE = 128;
// Number of chat messages to fetch in one call.
var MESSAGES_PAGE = 24;
-// Maximum in-band attachment size = 128K (included directly into the message). Increase
-// this limit to a greater value in production, if desired. Also increase max_message_size
-// in server config.
-var MAX_INBAND_ATTACHMENT_SIZE = 1 << 17;
+// Maximum in-band (included directly into the message) attachment size which fits into
+// a message of 256K in size, assuming base64 encoding and 1024 bytes of overhead.
+// This is size of an object *before* base64 encoding is applied.
+// Increase this limit to a greater value in production, if desired. Also increase
+// max_message_size in server config.
+// MAX_INBAND_ATTACHMENT_SIZE = base64DecodedLen(max_message_size - overhead);
+var MAX_INBAND_ATTACHMENT_SIZE = 195840;
// Absolute maximum attachment size to be used with the server = 8MB. Increase to
// something like 100MB in production.
@@ -48,7 +51,7 @@ var MAX_EXTERN_ATTACHMENT_SIZE = 1 << 23;
// Maximum allowed linear dimension of an inline image in pixels. You may want
// to adjust it to 1600 or 2400 for production.
-var MAX_IMAGE_SIZE = 768;
+var MAX_IMAGE_DIM = 768;
// Supported image MIME types and corresponding file extensions.
var SUPPORTED_IMAGE_FORMATS = ['image/jpeg', 'image/gif', 'image/png', 'image/svg', 'image/svg+xml'];
@@ -156,6 +159,18 @@ function getMimeType(header) {
return (mime && mime.length > 1) ? mime[1] : null;
}
+// Given length of a binary object in bytes, calculate the length after
+// base64 encoding.
+function base64EncodedLen(n) {
+ return Math.floor((n + 2) / 3) * 4;
+}
+
+// Given length of a base64-encoded object, calculate decoded size of the
+// pbject in bytes.
+function base64DecodedLen(n) {
+ return Math.floor(n / 4) * 3;
+}
+
// Convert uploaded image into a base64-encoded string possibly scaling
// linear dimensions or constraining to a square.
function imageFileScaledToBase64(file, width, height, forceSquare, onSuccess, onError) {
@@ -193,13 +208,13 @@ function imageFileScaledToBase64(file, width, height, forceSquare, onSuccess, on
var quality = 0.78;
if (mime == "image/jpeg") {
// Reduce size of the jpeg by reducing image quality
- while (imageBits.length * 0.75 > MAX_INBAND_ATTACHMENT_SIZE && quality > 0.45) {
+ while (base64DecodedLen(imageBits.length) > MAX_INBAND_ATTACHMENT_SIZE && quality > 0.45) {
imageBits = canvas.toDataURL(mime, quality);
quality *= 0.84;
}
}
- if (imageBits.length * 0.75 > MAX_INBAND_ATTACHMENT_SIZE) {
- onError("The image size " + bytesToHumanSize(imageBits.length * 0.75) +
+ if (base64DecodedLen(imageBits.length) > MAX_INBAND_ATTACHMENT_SIZE) {
+ onError("The image size " + bytesToHumanSize(base64DecodedLen(imageBits.length)) +
" exceeds the " + bytesToHumanSize(MAX_INBAND_ATTACHMENT_SIZE) + " limit.", "err");
return;
}
@@ -257,7 +272,7 @@ function filePasted(event, onImageSuccess, onAttachmentSuccess, onError) {
if (file.type && file.type.split("/")[0] == "image") {
// Handle inline image
if (file.size > MAX_INBAND_ATTACHMENT_SIZE || SUPPORTED_IMAGE_FORMATS.indexOf(file.type) < 0) {
- imageFileScaledToBase64(file, MAX_IMAGE_SIZE, MAX_IMAGE_SIZE, false, onImageSuccess, onError);
+ imageFileScaledToBase64(file, MAX_IMAGE_DIM, MAX_IMAGE_DIM, false, onImageSuccess, onError);
} else {
imageFileToBase64(file, onImageSuccess, onError);
}
@@ -448,6 +463,12 @@ function deleteMessages(all, hard, params, errorHandler) {
console.log("Topic not found: ", params.topicName);
return;
}
+ // We don't know if the message is still pending (e.g. attachment is being uploaded),
+ // so try cancelling first. No harm if we can't cancel.
+ if (topic.cancelSend(params.seq)) {
+ return new Promise.resolve();
+ }
+ // Can't cancel. Delete instead.
var promise = all ?
topic.delMessagesAll(hard) :
topic.delMessagesList([params.seq], hard);
@@ -2803,7 +2824,7 @@ class InfoView extends React.Component {
this.handleContextMenu = this.handleContextMenu.bind(this);
}
- // No need to separately handle componentWillMount.
+ // No need to separately handle component mount.
componentWillReceiveProps(props) {
var topic = Tinode.getTopic(props.topic);
if (!topic) {
@@ -3413,12 +3434,12 @@ class ChatMessage extends React.Component {
/* Received/read indicator */
class ReceivedMarker extends React.PureComponent {
render() {
- var timestamp = (this.props.received == Tinode.MESSAGE_STATUS_PENDING) ?
+ var timestamp = (this.props.received <= Tinode.MESSAGE_STATUS_SENDING) ?
"sending ..." :
shortDateFormat(this.props.timestamp);
var marker = null;
- if (this.props.received == Tinode.MESSAGE_STATUS_PENDING) {
+ if (this.props.received <= Tinode.MESSAGE_STATUS_SENDING) {
marker = (access_time); // watch face
} else if (this.props.received == Tinode.MESSAGE_STATUS_SENT) {
marker = (done); // checkmark
@@ -3779,7 +3800,8 @@ class MessagesView extends React.Component {
}
// Aknowledge all messages, including own messges.
- if (topic.msgStatus(msg) != Tinode.MESSAGE_STATUS_PENDING) {
+ let status = topic.msgStatus(msg);
+ if (status >= Tinode.MESSAGE_STATUS_SENT) {
this.props.readTimerHandler(() => {
topic.noteRead(msg.seq);
});
@@ -4037,7 +4059,7 @@ class SendMessage extends React.PureComponent {
// Check if the uploaded file is indeed an image and if it isn't too large.
if (file.size > MAX_INBAND_ATTACHMENT_SIZE || SUPPORTED_IMAGE_FORMATS.indexOf(file.type) < 0) {
// Convert image for size or format.
- imageFileScaledToBase64(file, MAX_IMAGE_SIZE, MAX_IMAGE_SIZE, false,
+ imageFileScaledToBase64(file, MAX_IMAGE_DIM, MAX_IMAGE_DIM, false,
// Success
(bits, mime, width, height, fname) => {
this.props.sendMessage(Drafty.insertImage(null,
@@ -4585,7 +4607,7 @@ class TinodeWeb extends React.Component {
// Sending "received" notifications
tnData(data) {
let topic = Tinode.getTopic(data.topic);
- if (topic.msgStatus(data) != Tinode.MESSAGE_STATUS_PENDING) {
+ if (topic.msgStatus(data) > Tinode.MESSAGE_STATUS_SENDING) {
clearTimeout(this.receivedTimer);
this.receivedTimer = setTimeout(() => {
this.receivedTimer = undefined;
diff --git a/index.min.js b/index.min.js
index 42844dd4..c96cfc79 100644
--- a/index.min.js
+++ b/index.min.js
@@ -1 +1 @@
-var APP_NAME="TinodeWeb/0.15",KNOWN_HOSTS={hosted:"api.tinode.co",local:"localhost:6060"},DEFAULT_HOST=KNOWN_HOSTS.hosted,POP_SOUND=new Audio("audio/msg.mp3"),DEL_CHAR="\u2421",API_KEY="AQEAAAABAAD_rAp4DJh05a1HAwFT3A6K",KEYPRESS_DELAY=3000,RECEIVED_DELAY=500,READ_DELAY=1e3,MIN_TAG_LENGTH=4,MEDIA_BREAKPOINT=640,REM_SIZE=13,AVATAR_SIZE=128,MESSAGES_PAGE=24,MAX_INBAND_ATTACHMENT_SIZE=131072,MAX_EXTERN_ATTACHMENT_SIZE=8388608,MAX_IMAGE_SIZE=768,SUPPORTED_IMAGE_FORMATS=["image/jpeg","image/gif","image/png","image/svg","image/svg+xml"],MIME_EXTENSIONS=["jpg","gif","png","svg","svg"],Drafty=Tinode.Drafty;Storage.prototype.setObject=function(e,t){this.setItem(e,JSON.stringify(t))},Storage.prototype.getObject=function(e){var t=this.getItem(e);return t&&JSON.parse(t)};function shortDateFormat(e){var t=window.navigator.userLanguage||window.navigator.language,a=new Date;return e.getFullYear()==a.getFullYear()?e.getMonth()==a.getMonth()&&e.getDate()==a.getDate()?e.toLocaleTimeString(t,{hour12:!1,hour:"2-digit",minute:"2-digit"}):e.toLocaleDateString(t,{hour12:!1,month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"}):e.toLocaleDateString(t,{hour12:!1,year:"numeric",month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}function bytesToHumanSize(e){if(!e||0==e)return"0 Bytes";var t=["Bytes","KB","MB","GB","TB","PB"],a=Math.min(0|Math.floor(Math.log2(e)/10),t.length-1),n=e/Math.pow(1024,a),s=0n?2:30>n?1:0:0;return n.toFixed(s)+" "+t[a]}function makeImageUrl(e){return e&&e.type&&e.data?"data:image/"+e.type+";base64,"+e.data:null}function fitImageSize(e,t,a,n,s){var o=Math.min;if(!e||!t||!a||!n)return null;s&&(a=n=o(a,n));var r=o(o(e,a)/e,o(t,n)/t),i={dstWidth:0|e*r,dstHeight:0|t*r};return s?(i.dstWidth=i.dstHeight=o(i.dstWidth,i.dstHeight),i.srcWidth=i.srcHeight=o(e,t),i.xoffset=0|(e-i.srcWidth)/2,i.yoffset=0|(t-i.srcWidth)/2):(i.xoffset=i.yoffset=0,i.srcWidth=e,i.srcHeight=t),i}function fileNameForMime(e,t){var a=SUPPORTED_IMAGE_FORMATS.indexOf(t),n=MIME_EXTENSIONS[a],s=e.lastIndexOf(".");return 0<=s&&(e=e.substring(0,s)),e+"."+n}function getMimeType(e){var t=/^data:(image\/[-+a-z0-9.]+);base64/.exec(e);return t&&1SUPPORTED_IMAGE_FORMATS.indexOf(e.type)?"image/jpeg":e.type,c=i.toDataURL(l),p=c.split(",");if(l=getMimeType(p[0]),!l)return void o("Unsupported image format");var m=.78;if("image/jpeg"==l)for(;.75*c.length>MAX_INBAND_ATTACHMENT_SIZE&&.45MAX_INBAND_ATTACHMENT_SIZE?void o("The image size "+bytesToHumanSize(.75*c.length)+" exceeds the "+bytesToHumanSize(MAX_INBAND_ATTACHMENT_SIZE)+" limit.","err"):void(i=null,s(c.split(",")[1],l,r.dstWidth,r.dstHeight,fileNameForMime(e.name,l)))},r.src=URL.createObjectURL(e)}function imageFileToBase64(e,t,a){var n=new FileReader;n.addEventListener("load",function(){var s=n.result.split(","),o=getMimeType(s[0]);if(!o)return void a("Failed to process image file");var r=new Image;r.crossOrigin="Anonymous",r.onload=function(){t(s[1],o,this.width,this.height,fileNameForMime(e.name,o))},r.onerror=function(){a("Image format not recognized")},r.src=URL.createObjectURL(e)},!1),n.readAsDataURL(e)}function fileToBase64(e,t){var a=new FileReader;a.addEventListener("load",function(){t(e.type,a.result.split(",")[1],e.name)}),a.readAsDataURL(e)}function filePasted(e,t,a,n){var s=(e.clipboardData||e.originalEvent.clipboardData||{}).items;for(var o in s){var r=s[o];if("file"===r.kind){var i=r.getAsFile();if(!i){console.log("Failed to get file object from pasted file item",r.kind,r.type);continue}return i.type&&"image"==i.type.split("/")[0]?i.size>MAX_INBAND_ATTACHMENT_SIZE||0>SUPPORTED_IMAGE_FORMATS.indexOf(i.type)?imageFileScaledToBase64(i,MAX_IMAGE_SIZE,MAX_IMAGE_SIZE,!1,t,n):imageFileToBase64(i,t,n):fileToBase64(i,a,n),!0}}return!1}function updateFavicon(e){var t=document.getElementById("shortcut-icon");if(t){var a=document.head||document.getElementsByTagName("head")[0],n=document.createElement("link");n.type="image/png",n.id="shortcut-icon",n.rel="shortcut icon",n.href="img/logo32x32"+(0n.indexOf(e)))&&o.push(React.createElement("tr",{key:e},React.createElement("td",null,t[e]),React.createElement("td",{className:"checkbox"},0>a.indexOf(e)?React.createElement(CheckBox,{name:e,checked:0<=n.indexOf(e),onChange:this.handleChange}):React.createElement(CheckBox,{name:e,checked:0<=n.indexOf(e)})),this.props.compare?React.createElement("td",{className:"checkbox"},React.createElement(CheckBox,{name:e,checked:0<=s.indexOf(e)})):null));return React.createElement("div",{className:"panel-form-column"},this.props.userTitle?React.createElement("ul",{className:"contact-box"},React.createElement(Contact,{item:this.props.item,title:this.props.userTitle,avatar:makeImageUrl(this.props.userAvatar?this.props.userAvatar:null)})):null,React.createElement("label",{className:"small"},"Permissions"),React.createElement("table",{className:"permission-editor"},this.props.compare?React.createElement("thead",null,React.createElement("tr",null,React.createElement("th",null),React.createElement("th",null,this.props.modeTitle),React.createElement("th",null,this.props.compareTitle))):null,React.createElement("tbody",null,o)),React.createElement("br",null),React.createElement("div",{className:"dialog-buttons"},React.createElement("button",{className:"blue",onClick:this.handleSubmit},"Ok"),React.createElement("button",{className:"white",onClick:this.handleCancel},"Cancel")))}}class ChipInput extends React.Component{constructor(e){super(e),this.state={placeholder:e.chips?"":e.prompt,sortedChips:ChipInput.sortChips(e.chips,e.required),chipIndex:ChipInput.indexChips(e.chips),input:"",focused:!1},this.handleTextInput=this.handleTextInput.bind(this),this.removeChipAt=this.removeChipAt.bind(this),this.handleChipCancel=this.handleChipCancel.bind(this),this.handleFocusGained=this.handleFocusGained.bind(this),this.handleFocusLost=this.handleFocusLost.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this)}componentWillReceiveProps(e){this.setState({sortedChips:ChipInput.sortChips(e.chips,e.required),chipIndex:ChipInput.indexChips(e.chips)}),e.chips.length>this.props.chips.length&&this.setState({input:""})}static indexChips(e){var t={},a=0;return e.map(function(e){t[e.user]=a,a++}),t}static sortChips(e,t){var a=[],n=[];return e.map(function(e){e.user===t?a.push(e):n.push(e)}),a.concat(n)}handleTextInput(t){this.setState({input:t.target.value}),this.props.filterFunc&&this.props.filterFunc(t.target.value)}removeChipAt(e){var t=this.state.sortedChips[e];this.props.onChipRemoved(t.user,this.state.chipIndex[t.user])}handleChipCancel(e,t){this.removeChipAt(t)}handleFocusGained(){this.setState({focused:!0})}handleFocusLost(){this.setState({focused:!1}),this.props.onFocusLost&&this.props.onFocusLost(this.state.input)}handleKeyDown(t){if(!("Backspace"===t.key))"Enter"===t.key?this.props.onEnter&&this.props.onEnter(this.state.input):"Escape"===t.key&&this.props.onCancel&&this.props.onCancel();else if(0==this.state.input.length&&0{e.push(React.createElement("div",{className:"avatar-box"},React.createElement(LetterTile,{topic:t.user,avatar:makeImageUrl(t.public?t.public.photo:null)||!0,title:t.public?t.public.fn:null,key:t.user})))}),React.createElement("div",{id:"topic-users"},e)}}class LoginView extends React.Component{constructor(e){super(e),this.state={login:e.login,password:"",hostName:e.serverAddress,saveToken:localStorage.getObject("keep-logged-in")},this.handleLoginChange=this.handleLoginChange.bind(this),this.handlePasswordChange=this.handlePasswordChange.bind(this),this.handleServerAddressChange=this.handleServerAddressChange.bind(this),this.handleToggleSaveToken=this.handleToggleSaveToken.bind(this),this.handleSubmit=this.handleSubmit.bind(this)}handleLoginChange(t){this.setState({login:t.target.value})}handlePasswordChange(t){this.setState({password:t.target.value})}handleServerAddressChange(e){this.setState({hostName:e}),this.props.onServerAddressChange(e)}handleToggleSaveToken(){localStorage.setObject("keep-logged-in",!this.state.saveToken),this.setState({saveToken:!this.state.saveToken})}handleSubmit(t){t.preventDefault(),this.props.onLogin(this.state.login.trim(),this.state.password.trim())}render(){var e="blue";return this.props.disabled&&(e+=" disabled"),React.createElement("form",{id:"login-form",onSubmit:this.handleSubmit},React.createElement("input",{type:"text",id:"inputLogin",placeholder:"Login (alice, bob, carol, dave, frank)",autoComplete:"username",value:this.state.login,onChange:this.handleLoginChange,required:!0,autoFocus:!0}),React.createElement("input",{type:"password",id:"inputPassword",placeholder:"Password (alice123, bob123, ...)",autoComplete:"current-password",value:this.state.password,onChange:this.handlePasswordChange,required:!0}),React.createElement("div",{className:"panel-form-row"},React.createElement(HostSelector,{serverAddress:this.props.serverAddress,onServerAddressChange:this.handleServerAddressChange})),React.createElement("div",{className:"panel-form-row"},React.createElement(CheckBox,{id:"save-token",name:"save-token",checked:this.state.saveToken,onChange:this.handleToggleSaveToken}),React.createElement("label",{forHtml:"save-token"},"\xA0Keep me logged in")),React.createElement("div",{className:"dialog-buttons"},React.createElement("button",{className:e,type:"submit"},"Sign in")))}}class CreateAccountView extends React.PureComponent{constructor(e){super(e),this.state={login:"",password:"",password2:"",email:"",fn:"",imageDataUrl:null,errorCleared:!1,saveToken:localStorage.getObject("keep-logged-in")},this.handleLoginChange=this.handleLoginChange.bind(this),this.handlePasswordChange=this.handlePasswordChange.bind(this),this.handlePassword2Change=this.handlePassword2Change.bind(this),this.handleEmailChange=this.handleEmailChange.bind(this),this.handleFnChange=this.handleFnChange.bind(this),this.handleImageChanged=this.handleImageChanged.bind(this),this.handleToggleSaveToken=this.handleToggleSaveToken.bind(this),this.handleSubmit=this.handleSubmit.bind(this)}handleLoginChange(t){this.setState({login:t.target.value})}handlePasswordChange(t){this.setState({password:t.target.value})}handlePassword2Change(t){this.setState({password2:t.target.value})}handleEmailChange(t){this.setState({email:t.target.value})}handleFnChange(t){this.setState({fn:t.target.value})}handleImageChanged(e){this.setState({imageDataUrl:e})}handleToggleSaveToken(){localStorage.setObject("keep-logged-in",!this.state.saveToken),this.setState({saveToken:!this.state.saveToken})}handleSubmit(t){t.preventDefault(),this.state.password.trim()==this.state.password2.trim()?(this.setState({errorCleared:!1}),this.props.onCreateAccount(this.state.login.trim(),this.state.password.trim(),vcard(this.state.fn,this.state.imageDataUrl),{meth:"email",val:this.state.email})):this.props.onError("Passwords don't match","warn")}render(){var e="blue";return this.props.disabled&&(e+=" disabled"),React.createElement("form",{className:"panel-form-column",onSubmit:this.handleSubmit},React.createElement("div",{className:"panel-form-row"},React.createElement("div",{className:"panel-form-column"},React.createElement("input",{type:"text",placeholder:"Login",autoComplete:"user-name",value:this.state.login,onChange:this.handleLoginChange,required:!0,autoFocus:!0}),React.createElement("input",{type:"password",placeholder:"Password",autoComplete:"new-password",value:this.state.password,onChange:this.handlePasswordChange,required:!0}),React.createElement("input",{type:"password",placeholder:"Repeat password",autoComplete:"new-password",value:this.state.password2,onChange:this.handlePassword2Change,required:!0})),React.createElement(AvatarUpload,{onImageChanged:this.handleImageChanged,onError:this.props.onError})),React.createElement("div",{className:"panel-form-row"},React.createElement("input",{type:"email",placeholder:"Email, e.g john.doe@example.com",autoComplete:"email",value:this.state.email,onChange:this.handleEmailChange,required:!0})),React.createElement("div",{className:"panel-form-row"},React.createElement("input",{type:"text",placeholder:"Full name, e.g. John Doe",autoComplete:"name",value:this.state.fn,onChange:this.handleFnChange,required:!0})),React.createElement("div",{className:"panel-form-row"},React.createElement(CheckBox,{id:"save-token",name:"save-token",checked:this.state.saveToken,onChange:this.handleToggleSaveToken}),React.createElement("label",{forHtml:"save-token"},"\xA0Keep me logged in")),React.createElement("div",{className:"dialog-buttons"},React.createElement("button",{className:e,type:"submit"},"Sign up")))}}class AvatarUpload extends React.Component{constructor(e){super(e),this.state={dataUrl:e.avatar},this.handleFileUpload=this.handleFileUpload.bind(this)}componentWillReceiveProps(e){this.props.avatar!=e.avatar&&this.setState({dataUrl:e.avatar})}handleFileUpload(t){var e=this;imageFileScaledToBase64(t.target.files[0],AVATAR_SIZE,AVATAR_SIZE,!0,function(t,a){var n=makeImageUrl({data:t,type:a});e.setState({dataUrl:n}),e.props.onImageChanged(n)},function(e){this.props.onError(e,"err")}),t.target.value=""}render(){var e="file-input-avatar-"+(Math.random()+"").substr(2);return React.createElement("div",{className:"avatar-upload"},this.state.dataUrl?React.createElement("img",{src:this.state.dataUrl,className:"preview"}):this.props.readOnly&&this.props.uid?React.createElement("div",{className:"avatar-box"},React.createElement(LetterTile,{avatar:!0,topic:this.props.uid,title:this.props.title})):React.createElement("div",{className:"blank"},"128\xD7128"),this.props.readOnly?null:React.createElement("input",{type:"file",id:e,className:"inputfile hidden",accept:"image/*",onChange:this.handleFileUpload}),this.props.readOnly?null:React.createElement("label",{htmlFor:e,className:"round"},React.createElement("i",{className:"material-icons"},"file_upload")))}}class SettingsView extends React.PureComponent{constructor(e){super(e),this.state={transport:"def"},this.handleSubmit=this.handleSubmit.bind(this),this.handleTransportSelected=this.handleTransportSelected.bind(this)}handleSubmit(t){t.preventDefault(),this.props.onUpdate(null,this.state.transport)}handleTransportSelected(t){this.setState({transport:t.currentTarget.value})}render(){var e={def:"default",ws:"websocket",lp:"long polling"},t=[],a=this;return["def","ws","lp"].map(function(n){var s="transport-"+n,o=e[n];t.push(React.createElement("li",{key:n},React.createElement("input",{type:"radio",id:s,name:"transport-select",value:n,checked:a.state.transport===n,onChange:a.handleTransportSelected}),React.createElement("label",{htmlFor:s},o)))}),React.createElement("form",{id:"settings-form",onSubmit:this.handleSubmit},React.createElement("label",{className:"small"},"Wire transport:"),React.createElement("ul",{className:"quoted"},t),React.createElement("div",{className:"dialog-buttons"},React.createElement("button",{type:"submit",className:"blue"},"Update")))}}class SideNavbar extends React.PureComponent{render(){return React.createElement("div",{id:"side-caption-panel",className:"caption-panel"},React.createElement("div",{id:"self-avatar",className:"avatar-box"},React.createElement(LetterTile,{avatar:this.props.avatar,topic:this.props.myUserId,title:this.props.title})),React.createElement("div",{id:"sidepanel-title",className:"panel-title"},this.props.title),"login"===this.props.state?React.createElement(MenuStart,{onSignUp:this.props.onSignUp,onSettings:this.props.onSettings}):"contacts"===this.props.state?React.createElement(MenuContacts,{onNewTopic:this.props.onNewTopic,onSettings:this.props.onSettings}):null,this.props.onCancel?React.createElement(MenuCancel,{onCancel:this.props.onCancel}):null)}}class MenuStart extends React.PureComponent{render(){return React.createElement("div",null,React.createElement("a",{href:"javascript:;",onClick:this.props.onSignUp},React.createElement("i",{className:"material-icons"},"person_add")),"\xA0",React.createElement("a",{href:"javascript:;",onClick:this.props.onSettings},React.createElement("i",{className:"material-icons"},"settings")))}}class MenuContacts extends React.PureComponent{render(){return React.createElement("div",null,React.createElement("a",{href:"javascript:;",onClick:this.props.onNewTopic},React.createElement("i",{className:"material-icons"},"chat")),"\xA0",React.createElement("a",{href:"javascript:;",onClick:this.props.onSettings},React.createElement("i",{className:"material-icons"},"settings")))}}class SidepanelView extends React.Component{constructor(e){super(e),this.handleLoginRequested=this.handleLoginRequested.bind(this)}handleLoginRequested(e,t){this.props.onLoginRequest(e,t)}render(){var e=null,t=!1,a=void 0,n=this.props.state||(this.props.myUserId?"contacts":"login");switch(n){case"login":e="Sign In";break;case"register":e="Create Account",a=this.props.onCancel;break;case"settings":e="Settings",a=this.props.onCancel;break;case"edit":e="Edit Account",a=this.props.onCancel;break;case"contacts":e=this.props.title,t=!this.props.avatar||this.props.avatar;break;case"newtpk":e="Start New Chat",a=this.props.onCancel;break;case"cred":e="Confirm Credentials",a=this.props.onCancel;break;default:;}return React.createElement("div",{id:"sidepanel",className:this.props.hideSelf?"nodisplay":null},React.createElement(SideNavbar,{state:n,title:e,avatar:t,myUserId:this.props.myUserId,onSignUp:this.props.onSignUp,onSettings:this.props.onSettings,onNewTopic:this.props.onNewTopic,onCancel:a}),React.createElement(ErrorPanel,{level:this.props.errorLevel,text:this.props.errorText,onClearError:this.props.onError}),"login"===n?React.createElement(LoginView,{login:this.props.login,disabled:this.props.loginDisabled,serverAddress:this.props.serverAddress,onLogin:this.handleLoginRequested,onServerAddressChange:this.props.onConnectionSettings}):"register"===n?React.createElement(CreateAccountView,{onCreateAccount:this.props.onCreateAccount,onCancel:this.props.onCancel,onError:this.props.onError}):"settings"===n?React.createElement(SettingsView,{onCancel:this.props.onCancel,onUpdate:this.props.onConnectionSettings}):"edit"===n?React.createElement(EditAccountView,{login:this.props.login,onSubmit:this.props.onUpdateAccount,onUpdateTags:this.props.onUpdateAccountTags,onLogout:this.props.onLogout,onCancel:this.props.onCancel,onError:this.props.onError}):"contacts"===n?React.createElement(ContactsView,{connected:this.props.connected,topicSelected:this.props.topicSelected,showContextMenu:this.props.showContextMenu,onTopicSelected:this.props.onTopicSelected,onAcsChange:this.props.onAcsChange,onOnlineChange:this.props.onOnlineChange}):"newtpk"===n?React.createElement(NewTopicView,{contactsSearchQuery:this.props.contactsSearchQuery,foundContacts:this.props.foundContacts,onInitFind:this.props.onInitFind,onSearchContacts:this.props.onSearchContacts,onCreateTopic:this.props.onCreateTopic,onError:this.props.onError}):"cred"===n?React.createElement(ValidationView,{credCode:this.props.credCode,credMethod:this.props.credMethod,onSubmit:this.props.onValidateCredentials,onCancel:this.props.onCancel,onError:this.props.onError}):null)}}class ErrorPanel extends React.PureComponent{constructor(e){super(e),this.state={show:!1},this.hide=this.hide.bind(this)}componentWillReceiveProps(e){this.setState({show:!!e.level})}hide(){this.setState({show:!1}),this.props.onClearError&&this.props.onClearError()}render(){var e="err"==this.props.level?"error":"warning";return React.createElement("div",{className:this.state.show?"err"==this.props.level?"alert-box error":"alert-box warning":"alert-box"},React.createElement("div",{className:"icon"},React.createElement("i",{className:"material-icons"},e)),this.props.text,React.createElement("div",{className:"cancel"},React.createElement(MenuCancel,{onCancel:this.hide})))}}class EditAccountView extends React.Component{constructor(e){super(e);let t=Tinode.getMeTopic(),a=t.getDefaultAccess(),n=Tinode.getFndTopic();this.state={fullName:t.public?t.public.fn:void 0,avatar:makeImageUrl(t.public?t.public.photo:null),address:Tinode.getCurrentUserID(),auth:a.auth,anon:a.anon,tags:n.tags(),previousOnTags:n.onTagsUpdated},this.tnNewTags=this.tnNewTags.bind(this),this.handleFullNameUpdate=this.handleFullNameUpdate.bind(this),this.handlePasswordUpdate=this.handlePasswordUpdate.bind(this),this.handleImageChanged=this.handleImageChanged.bind(this),this.handleTagsUpdated=this.handleTagsUpdated.bind(this)}componentDidMount(){let e=Tinode.getFndTopic();e.onTagsUpdated=this.tnNewTags,e.isSubscribed()||e.subscribe(e.startMetaQuery().withLaterDesc().withTags().build()).catch(e=>{this.props.onError(e.message,"err")})}componentWillUnmount(){var e=Tinode.getFndTopic();e.onTagsUpdated=this.state.previousOnTags}tnNewTags(e){this.setState({tags:e})}handleFullNameUpdate(e){this.setState({fullName:e}),this.props.onSubmit(null,vcard(e,this.state.avatar))}handlePasswordUpdate(e){this.setState({password:e}),this.props.onSubmit(e,null)}handleImageChanged(e){this.setState({avatar:e}),this.props.onSubmit(null,vcard(this.state.fullName,e))}handleTagsUpdated(e){arrayEqual(this.state.tags.slice(0),e.slice(0))||this.props.onUpdateTags(e)}render(){var e=[];return this.state.tags.map(function(t){e.push(React.createElement("span",{className:"badge",key:e.length},t))}),0==e.length&&(e=React.createElement("i",null,"No tags defined. Add some.")),React.createElement("div",{id:"edit-account",className:"panel-form"},React.createElement("div",{className:"panel-form-row"},React.createElement("div",{className:"panel-form-column"},React.createElement("div",null,React.createElement("label",{className:"small"},"Your name")),React.createElement("div",null,React.createElement(InPlaceEdit,{placeholder:"Full name, e.g. John Doe",text:this.state.fullName,onFinished:this.handleFullNameUpdate})),React.createElement("div",null,React.createElement("label",{className:"small"},"Password")),React.createElement("div",null,React.createElement(InPlaceEdit,{placeholder:"Unchanged",type:"password",onFinished:this.handlePasswordUpdate}))),React.createElement(AvatarUpload,{avatar:this.state.avatar,uid:this.state.address,title:this.state.fullName,onImageChanged:this.handleImageChanged,onError:this.props.onError})),React.createElement("div",{className:"hr"}),React.createElement("div",{className:"panel-form-column"},React.createElement("div",{className:"panel-form-row"},React.createElement("label",null,"Login:"),React.createElement("tt",null,this.props.login)),React.createElement("div",{className:"panel-form-row"},React.createElement("label",null,"Address:"),React.createElement("tt",null,this.state.address)),React.createElement("div",null,React.createElement("label",{className:"small"},"Default access mode:")),React.createElement("div",{className:"quoted"},React.createElement("div",null,"Auth: ",React.createElement("tt",null,this.state.auth)),React.createElement("div",null,"Anon: ",React.createElement("tt",null,this.state.anon)))),React.createElement("div",{className:"hr"}),React.createElement(TagManager,{title:"Tags (user discovery)",activated:!1,tags:this.state.tags,onSubmit:this.handleTagsUpdated}),React.createElement("div",{className:"hr"}),React.createElement("div",{className:"panel-form-column"},React.createElement("a",{href:"javascript:;",className:"red flat-button",onClick:this.props.onLogout},React.createElement("i",{className:"material-icons"},"exit_to_app")," Logout")))}}class TagManager extends React.Component{constructor(e){super(e),this.state={tags:this.props.tags,tagInput:"",activated:this.props.activated,noTagsMessage:"Add some tags"},this.handleShowTagManager=this.handleShowTagManager.bind(this),this.handleTagInput=this.handleTagInput.bind(this),this.handleAddTag=this.handleAddTag.bind(this),this.handleRemoveTag=this.handleRemoveTag.bind(this),this.handleSubmit=this.handleSubmit.bind(this),this.handleCancel=this.handleCancel.bind(this)}componentWillReceiveProps(e){this.setState({tags:e.tags})}handleShowTagManager(){this.setState({activated:!0})}handleTagInput(e){if(this.setState({tagInput:e}),0=MIN_TAG_LENGTH&&this.handleAddTag(a)}}}handleAddTag(e){if(e=e.trim(),0e.state.index[s].delta&&n.push(s)}),this.props.onSubmit(t,a,n)}handleCancel(){this.props.onCancel()}render(){return React.createElement("div",{id:"group-manager"},React.createElement("div",{className:"panel-form-row"},React.createElement("label",{className:"small"},"Group members")),React.createElement("div",{className:"panel-form-row"},React.createElement(ChipInput,{chips:this.state.members,required:this.props.requiredMember,prompt:"add members",filterFunc:this.handleContactFilter,onChipRemoved:this.handleMemberRemoved})),React.createElement("div",{className:"panel-form-row"},React.createElement("label",{className:"small"},"All contacts")),React.createElement(ContactList,{contacts:this.props.contacts,topicSelected:this.state.selectedContacts,filter:this.state.contactFilter,filterFunc:GroupManager.doContactFiltering,emptyListMessage:this.state.noContactsMessage,showOnline:!1,showUnread:!1,onTopicSelected:this.handleContactSelected}),React.createElement("div",{id:"group-manager-buttons",className:"panel-form-row"},React.createElement("button",{className:"blue",onClick:this.handleSubmit},"OK"),React.createElement("button",{className:"white",onClick:this.handleCancel},"Cancel")))}}class NewTopicView extends React.Component{constructor(e){super(e),this.state={tabSelected:"p2p",searchQuery:e.contactsSearchQuery,contactList:e.foundContacts,contactSelected:null},this.handleTabClick=this.handleTabClick.bind(this),this.handleContactSelected=this.handleContactSelected.bind(this),this.handleNewGroupSubmit=this.handleNewGroupSubmit.bind(this),this.handleGroupByID=this.handleGroupByID.bind(this)}componentDidMount(){this.props.onInitFind()}componentWillReceiveProps(e){this.setState({searchQuery:e.contactsSearchQuery,contactList:e.foundContacts})}handleTabClick(t){t.preventDefault(),window.location.hash=addUrlParam(window.location.hash,"tab",t.currentTarget.dataset.id),this.setState({tabSelected:t.currentTarget.dataset.id,contactSelected:null})}handleContactSelected(e){"p2p"===this.state.tabSelected&&(window.location.hash=removeUrlParam(window.location.hash,"tab"),this.props.onCreateTopic(e,void 0))}handleNewGroupSubmit(e,t,a,n){window.location.hash=removeUrlParam(window.location.hash,"tab"),this.props.onCreateTopic(void 0,vcard(e,t),a,n)}handleGroupByID(e){window.location.hash=removeUrlParam(window.location.hash,"tab"),this.props.onCreateTopic(e)}render(){return React.createElement("div",{className:"flex-column"},React.createElement("ul",{className:"tabbar"},React.createElement("li",{className:"p2p"===this.state.tabSelected?"active":null},React.createElement("a",{href:"javascript:;","data-id":"p2p",onClick:this.handleTabClick},"1:1")),React.createElement("li",{className:"grp"===this.state.tabSelected?"active":null},React.createElement("a",{href:"javascript:;","data-id":"grp",onClick:this.handleTabClick},"group")),React.createElement("li",{className:"byid"===this.state.tabSelected?"active":null},React.createElement("a",{href:"javascript:;","data-id":"byid",onClick:this.handleTabClick},"by id"))),"grp"===this.state.tabSelected?React.createElement(NewTopicGroup,{onSubmit:this.handleNewGroupSubmit}):"byid"===this.state.tabSelected?React.createElement(NewTopicById,{onSubmit:this.handleGroupByID,onError:this.props.onError}):React.createElement("div",{className:"flex-column"},React.createElement(SearchContacts,{type:"p2p",searchQuery:this.state.searchQuery,onSearchContacts:this.props.onSearchContacts}),React.createElement(ContactList,{contacts:this.state.contactList,emptyListMessage:"Use search to find contacts",topicSelected:this.state.selectedContact,showOnline:!1,showUnread:!1,showContextMenu:!1,onTopicSelected:this.handleContactSelected})))}}class NewTopicGroup extends React.PureComponent{constructor(e){super(e),this.state={fn:"",private:"",imageDataUrl:null,tags:[]},this.handleFnChange=this.handleFnChange.bind(this),this.handlePrivateChange=this.handlePrivateChange.bind(this),this.handleImageChanged=this.handleImageChanged.bind(this),this.handleTagsChanged=this.handleTagsChanged.bind(this),this.handleTagsChanged=this.handleTagsChanged.bind(this),this.handleSubmit=this.handleSubmit.bind(this)}handleFnChange(t){this.setState({fn:t.target.value})}handlePrivateChange(t){this.setState({private:t.target.value})}handleImageChanged(e){this.setState({imageDataUrl:e})}handleTagsChanged(e){this.setState({tags:e})}handleSubmit(t){t.preventDefault(),this.state.fn&&this.state.fn.trim()&&this.props.onSubmit(this.state.fn.trim(),this.state.imageDataUrl,this.state.private.trim(),this.state.tags)}render(){var e="blue";return this.props.disabled&&(e+=" disabled"),React.createElement("form",{className:"panel-form",onSubmit:this.handleSubmit},React.createElement("div",{className:"panel-form-row"},React.createElement("div",{className:"panel-form-column"},React.createElement("label",{className:"small",htmlFor:"new-topic-fn"},"Group name"),React.createElement("input",{type:"text",id:"new-topic-fn",placeholder:"Freeform name of the group",value:this.state.fn,onChange:this.handleFnChange,autoFocus:!0,required:!0}),React.createElement("br",null),React.createElement("label",{className:"small",htmlFor:"new-topic-priv"},"Private comment"),React.createElement("input",{type:"text",id:"new-topic-priv",placeholder:"Visible to you only",value:this.state.private,onChange:this.handlePrivateChange})),React.createElement(AvatarUpload,{onError:this.props.onError,onImageChanged:this.handleImageChanged})),React.createElement(TagManager,{tags:this.state.tags,activated:!0,onTagsChanged:this.handleTagsChanged,title:"Optional tags (search and discovery)"}),React.createElement("div",{className:"dialog-buttons"},React.createElement("button",{className:e},"Create")))}}class SearchContacts extends React.Component{constructor(e){super(e),this.state={edited:!1,search:e.searchQuery},this.handleSearchChange=this.handleSearchChange.bind(this),this.handleSearch=this.handleSearch.bind(this),this.handleClear=this.handleClear.bind(this),this.handleKeyPress=this.handleKeyPress.bind(this)}componentWillUnmount(){this.state.search&&(this.setState({search:""}),this.props.onSearchContacts(DEL_CHAR))}handleSearchChange(t){this.setState({search:t.target.value})}handleSearch(t){t.preventDefault();var e=this.state.search.trim();0this.props.progress?React.createElement("a",{href:"javascript:;",onClick:this.props.onCancel},React.createElement("i",{className:"material-icons"},"close")," cancel"):React.createElement("span",null,"finishing..."))}}class Attachment extends React.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,a){var n=Tinode.getLargeFileHelper();this.setState({downloader:n}),n.download(e,t,a,e=>{this.setState({progress:e/this.props.size})}).then(()=>{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.uploader?this.props.onCancelUpload():this.state.downloader&&this.state.downloader.cancel()}render(){let e=this.props.filename||"file_attachment";36{this.downloadFile(this.props.downloadUrl,this.props.filename,this.props.mimetype)}),React.createElement("div",{className:"attachment"},React.createElement("div",null,React.createElement("i",{className:"material-icons big gray"},"insert_drive_file")),React.createElement("div",{className:"flex-column"},React.createElement("div",null,e," ",n),this.props.uploader||this.state.downloader?React.createElement(FileProgress,{progress:this.props.uploader?this.props.progress:this.state.progress,onCancel:this.handleCancel}):React.createElement("div",null,React.createElement("a",{href:t,download:this.props.filename,onClick:a},React.createElement("i",{className:"material-icons"},"file_download")," save"))))}}class MessagesView extends React.Component{constructor(e){super(e),this.state={messages:[],onlineSubs:[],topic:"",title:"",avatar:null,scrollPosition:0,readOnly:!e.acs||!e.acs.isWriter(),writeOnly:!e.acs||!e.acs.isReader(),typingIndicator:!1,imagePreview:null},this.propsChange=this.propsChange.bind(this),this.leave=this.leave.bind(this),this.handleScrollReference=this.handleScrollReference.bind(this),this.fetchMoreMessages=this.fetchMoreMessages.bind(this),this.handleDescChange=this.handleDescChange.bind(this),this.handleSubsUpdated=this.handleSubsUpdated.bind(this),this.handleNewMessage=this.handleNewMessage.bind(this),this.handleInfoReceipt=this.handleInfoReceipt.bind(this),this.handleImagePreview=this.handleImagePreview.bind(this),this.handleCloseImagePreview=this.handleCloseImagePreview.bind(this),this.handleContextClick=this.handleContextClick.bind(this),this.handleShowContextMenuMessage=this.handleShowContextMenuMessage.bind(this),this.handleBackNavigation=this.handleBackNavigation.bind(this)}componentDidUpdate(e,t){this.messagesScroller&&(t.title!=this.state.title||t.messages.length!=this.state.messages.length)&&(this.messagesScroller.scrollTop=this.messagesScroller.scrollHeight-this.state.scrollPosition)}componentDidMount(){this.propsChange(this.props),this.messagesScroller&&this.messagesScroller.addEventListener("scroll",this.fetchMoreMessages)}componentWillUnmount(){this.leave(),this.messagesScroller&&this.messagesScroller.removeEventListener("scroll",this.fetchMoreMessages)}componentWillReceiveProps(e){this.propsChange(e)}propsChange(e){if(!e||!e.topic)return this.setState({messages:[],onlineSubs:[],topic:null}),void this.leave();if(!e.connected)return void this.setState({onlineSubs:[]});var t=!this.props.connected&&e.connected,a=Tinode.getTopic(e.topic);if(e.topic!=this.state.topic){var n=[],s=[];a.onData=this.handleNewMessage,a.onInfo=this.handleInfoReceipt,a.onMetaDesc=this.handleDescChange,a.onSubsUpdated=this.handleSubsUpdated,a.onPres=this.handleSubsUpdated,this.leave(),this.handleDescChange(a);var o=this.props.myUserId;a.subscribers(function(e){e.online&&e.user!=o&&s.push(e)}),a.messages(function(e){e.deleted||(n=n.concat(e))}),this.setState({messages:n,onlineSubs:s,topic:e.topic,imagePreview:null,scrollPosition:0}),t=!0,this.props.readTimerHandler(null)}if(this.setState({readOnly:!e.acs||!e.acs.isWriter(),writeOnly:!e.acs||!e.acs.isReader()}),!a.isSubscribed()&&t){var r=a.startMetaQuery().withLaterDesc().withLaterSub().withLaterData(MESSAGES_PAGE).withLaterDel();this.setState({fetchingMessages:!0}),a.subscribe(r.build()).then(()=>{this.setState({fetchingMessages:!1})}).catch(e=>{this.props.onError(e.message,"err"),this.setState({title:"Not found",avatar:null,readOnly:!0,writeOnly:!0,fetchingMessages:!1})})}}leave(){if(this.state.topic){var e=Tinode.getTopic(this.state.topic);e&&(e.isSubscribed()&&e.leave(!1).catch(function(e){console.log(e)}),e.onData=void 0,e.onInfo=void 0,e.onMetaDesc=void 0,e.onSubsUpdated=void 0,e.onPres=void 0)}}handleScrollReference(e){e&&(e.addEventListener("scroll",this.fetchMoreMessages),this.messagesScroller=e)}fetchMoreMessages(e){var t=this;if(0>=e.target.scrollTop){var a={scrollPosition:e.target.scrollHeight-e.target.scrollTop};this.setState(function(e){if(!e.fetchingMessages){var n=Tinode.getTopic(t.state.topic);n&&n.isSubscribed()&&n.msgHasMoreMessages()&&(a.fetchingMessages=!0,n.getMessagesPage(MESSAGES_PAGE).then(function(){t.setState({fetchingMessages:!1})}).catch(function(e){t.setState({fetchingMessages:!1}),t.props.onError(e.message,"err")}))}return a})}}handleDescChange(e){e.public&&this.setState({title:e.public.fn,avatar:makeImageUrl(e.public.photo)}),e.acs&&this.setState({readOnly:!e.acs.isWriter(),writeOnly:!e.acs.isReader()})}handleSubsUpdated(){if(this.state.topic){var e=[],t=this.props.myUserId,a=Tinode.getTopic(this.state.topic);a.subscribers(function(a){a.online&&a.user!=t&&e.push(a)}),this.setState({onlineSubs:e})}}handleNewMessage(e){var t=Tinode.getTopic(this.state.topic),a={messages:[]};t.messages(function(e){e.deleted||(a.messages=a.messages.concat(e))}),e&&!e.deleted&&(t.isNewMessage(e.seq)&&(a.scrollPosition=0),t.msgStatus(e)!=Tinode.MESSAGE_STATUS_PENDING&&this.props.readTimerHandler(()=>{t.noteRead(e.seq)}),this.props.onData(e)),this.setState(a)}handleInfoReceipt(e){switch(e.what){case"kp":{clearTimeout(this.keyPressTimer);var t=this;this.keyPressTimer=setTimeout(function(){t.setState({typingIndicator:!1})},4000),this.state.typingIndicator||this.setState({typingIndicator:!0});break}case"read":case"recv":this.forceUpdate();break;default:console.log("Other change in topic: ",e.what);}}handleImagePreview(e){this.setState({imagePreview:e})}handleCloseImagePreview(){this.setState({imagePreview:null})}handleContextClick(t){t.preventDefault(),t.stopPropagation(),this.props.showContextMenu({topicName:this.state.topic,y:t.pageY,x:t.pageX})}handleShowContextMenuMessage(e){e.topicName=this.state.topic;var t=[ContextMenuItems.message_delete],a=Tinode.getTopic(e.topicName);if(a){var n=a.getAccessMode();n&&n.isDeleter()&&t.push(ContextMenuItems.message_delete_hard)}this.props.showContextMenu(e,t)}handleBackNavigation(){this.props.onHideMessagesView()}render(){var e=null;if(this.state.topic){for(var t=[],a=Tinode.getTopic(this.state.topic),n="grp"===a.getType(),s=null,o=0;o{this.props.sendMessage(Drafty.insertImage(null,0,t,e,a,n,s))},(e,t,a)=>{this.props.sendMessage(Drafty.attachFile(null,e,t,a))},this.props.onError)&&t.preventDefault()}handleAttachImage(t){if(t.target.files&&0MAX_INBAND_ATTACHMENT_SIZE||0>SUPPORTED_IMAGE_FORMATS.indexOf(e.type)?imageFileScaledToBase64(e,MAX_IMAGE_SIZE,MAX_IMAGE_SIZE,!1,(e,t,a,n,s)=>{this.props.sendMessage(Drafty.insertImage(null,0,t,e,a,n,s))},e=>{this.props.onError(e,"err")}):imageFileToBase64(e,(e,t,a,n,s)=>{this.props.sendMessage(Drafty.insertImage(null,0,t,e,a,n,s))},e=>{this.props.onError(e,"err")})}t.target.value=""}handleAttachFile(t){if(t.target.files&&0MAX_EXTERN_ATTACHMENT_SIZE)this.props.onError("The file size "+bytesToHumanSize(e.size)+" exceeds the "+bytesToHumanSize(MAX_EXTERN_ATTACHMENT_SIZE)+" limit.","err");else if(e.size>MAX_INBAND_ATTACHMENT_SIZE){let t=Tinode.getLargeFileHelper();if(!t)return void this.props.onError("Cannot initiate file upload.");let a=t.upload(e),n=Drafty.attachFile(null,e.type,null,e.name,e.size,a);this.props.sendMessage(n,a,t)}else fileToBase64(e,(e,t,a)=>{this.props.sendMessage(Drafty.attachFile(null,e,t,a))},this.props.onError)}t.target.value=""}handleSend(){var e=this.state.message.trim();e&&(this.props.sendMessage(this.state.message.trim()),this.setState({message:""}))}handleKeyPress(t){"Enter"!==t.key||t.shiftKey||(t.preventDefault(),t.stopPropagation(),this.handleSend())}handleMessageTyping(t){var e={message:t.target.value},a=new Date().getTime();if(a-this.state.keypressTimestamp>KEYPRESS_DELAY){var n=Tinode.getTopic(this.props.topic);n.isSubscribed()&&n.noteKeyPress(),e.keypressTimestamp=a}this.setState(e)}render(){var e=this.props.disabled?"Messaging disabled":"New message",t=this;return React.createElement("div",{id:"send-message-panel"},this.props.disabled?React.createElement("i",{className:"material-icons disabled"},"photo"):React.createElement("a",{href:"javascript:;",onClick:function(){t.attachImage.click()},title:"Add image"},React.createElement("i",{className:"material-icons secondary"},"photo")),this.props.disabled?React.createElement("i",{className:"material-icons disabled"},"attach_file"):React.createElement("a",{href:"javascript:;",onClick:function(){t.attachFile.click()},title:"Attach file"},React.createElement("i",{className:"material-icons secondary"},"attach_file")),React.createElement("textarea",{id:"sendMessage",placeholder:e,disabled:this.props.disabled,value:this.state.message,onChange:this.handleMessageTyping,onKeyPress:this.handleKeyPress,ref:function(e){t.pasteFile=e},autoFocus:!0}),this.props.disabled?React.createElement("i",{className:"material-icons disabled"},"send"):React.createElement("a",{href:"javascript:;",onClick:this.handleSend,title:"Send"},React.createElement("i",{className:"material-icons"},"send")),React.createElement("input",{type:"file",ref:function(e){t.attachFile=e},onChange:this.handleAttachFile,style:{display:"none"}}),React.createElement("input",{type:"file",ref:function(e){t.attachImage=e},accept:"image/*",onChange:this.handleAttachImage,style:{display:"none"}}))}}class LogoView extends React.PureComponent{render(){var e=Tinode.getVersion()+" build "+document.lastModified;return React.createElement("div",{id:"dummy-view",className:this.props.hideSelf?"nodisplay":null},React.createElement("div",null,React.createElement("a",{href:"https://github.com/tinode/chat/"},React.createElement("img",{id:"logo",alt:"logo",src:"img/logo.svg"}),React.createElement("h2",null,"Tinode Demo Chat")),React.createElement("p",null,"Client: ",e),React.createElement("p",null,"Server: ",this.props.serverVersion," (",this.props.serverAddress,")")))}}class ImagePreview extends React.PureComponent{constructor(e){super(e),this.state={}}componentDidMount(){this.setState({width:this.container.clientWidth,height:this.container.clientHeight})}render(){if(!this.props.content)return null;var e=this,t=fitImageSize(this.props.content.width,this.props.content.height,this.state.width,this.state.height,!1),a=t?{width:t.dstWidth+"px",height:t.dstHeight+"px"}:this.props.content.width>this.props.content.height?{width:"100%"}:{height:"100%"};a.maxWidth="100%",a.maxHeight="100%";var n=this.props.content.filename,s=0|this.props.content.width/REM_SIZE;return n.length>s&&(n=n.slice(0,s-2)+"..."+n.slice(2-s)),React.createElement("div",{id:"image-preview",onClick:this.props.onClose},React.createElement("div",{id:"image-preview-caption-panel"},React.createElement("a",{href:"javascript:;",download:this.props.content.filename},React.createElement("i",{className:"material-icons"},"file_download")," download"),React.createElement("a",{href:"javascript:;",onClick:this.props.onClose},React.createElement("i",{className:"material-icons gray"},"close"))),React.createElement("div",{id:"image-preview-container",ref:function(t){e.container=t}},React.createElement("img",{src:this.props.content.url,style:a})),React.createElement("div",{id:"image-preview-footer"},React.createElement("div",null,React.createElement("div",null,React.createElement("b",null,"File name"),":"),React.createElement("div",null,React.createElement("span",{title:this.props.content.filename},n))),React.createElement("div",null,React.createElement("div",null,React.createElement("b",null,"Content type"),":"),React.createElement("div",null,this.props.content.type)),React.createElement("div",null,React.createElement("div",null,React.createElement("b",null,"Size"),":"),React.createElement("div",null,this.props.content.width," \xD7 ",this.props.content.height," px; ",bytesToHumanSize(this.props.content.size)))))}}class TinodeWeb extends React.Component{constructor(e){super(e),this.state=this.getInitialState(),this.handleResize=this.handleResize.bind(this),this.handleHashRoute=this.handleHashRoute.bind(this),this.handleOnline=this.handleOnline.bind(this),this.handleAppVisibility=this.handleAppVisibility.bind(this),this.handleReadTimer=this.handleReadTimer.bind(this),this.handleVisibilityEvent=this.handleVisibilityEvent.bind(this),this.handleError=this.handleError.bind(this),this.handleLoginRequest=this.handleLoginRequest.bind(this),this.handleConnected=this.handleConnected.bind(this),this.doLogin=this.doLogin.bind(this),this.handleCredentialsRequest=this.handleCredentialsRequest.bind(this),this.handleLoginSuccessful=this.handleLoginSuccessful.bind(this),this.handleDisconnect=this.handleDisconnect.bind(this),this.tnMeMetaDesc=this.tnMeMetaDesc.bind(this),this.tnData=this.tnData.bind(this),this.tnInitFind=this.tnInitFind.bind(this),this.tnFndSubsUpdated=this.tnFndSubsUpdated.bind(this),this.handleSearchContacts=this.handleSearchContacts.bind(this),this.handleTopicSelected=this.handleTopicSelected.bind(this),this.handleTopicSelectedOnline=this.handleTopicSelectedOnline.bind(this),this.handleTopicSelectedAcs=this.handleTopicSelectedAcs.bind(this),this.handleHideMessagesView=this.handleHideMessagesView.bind(this),this.handleSendMessage=this.handleSendMessage.bind(this),this.handleNewAccount=this.handleNewAccount.bind(this),this.handleNewAccountRequest=this.handleNewAccountRequest.bind(this),this.handleUpdateAccountRequest=this.handleUpdateAccountRequest.bind(this),this.handleUpdateAccountTagsRequest=this.handleUpdateAccountTagsRequest.bind(this),this.handleSettings=this.handleSettings.bind(this),this.handleConnectionSettings=this.handleConnectionSettings.bind(this),this.handleSidepanelCancel=this.handleSidepanelCancel.bind(this),this.handleNewTopic=this.handleNewTopic.bind(this),this.handleNewTopicRequest=this.handleNewTopicRequest.bind(this),this.handleTopicUpdateRequest=this.handleTopicUpdateRequest.bind(this),this.handleChangePermissions=this.handleChangePermissions.bind(this),this.handleTagsUpdated=this.handleTagsUpdated.bind(this),this.handleLogout=this.handleLogout.bind(this),this.handleLeaveUnsubRequest=this.handleLeaveUnsubRequest.bind(this),this.handleDialogCancel=this.handleDialogCancel.bind(this),this.handleShowContextMenu=this.handleShowContextMenu.bind(this),this.defaultTopicContextMenu=this.defaultTopicContextMenu.bind(this),this.handleHideContextMenu=this.handleHideContextMenu.bind(this),this.handleShowInfoView=this.handleShowInfoView.bind(this),this.handleHideInfoView=this.handleHideInfoView.bind(this),this.handleMemberUpdateRequest=this.handleMemberUpdateRequest.bind(this),this.handleValidateCredentialsRequest=this.handleValidateCredentialsRequest.bind(this)}getInitialState(){return{connected:!1,transport:null,serverAddress:detectServerAddress(),sidePanelSelected:"login",sidePanelTitle:null,sidePanelAvatar:null,dialogSelected:null,contextMenuVisible:!1,login:"",password:"",myUserId:null,errorText:"",errorLevel:null,liveConnection:navigator.onLine,topicSelected:"",topicSelectedOnline:!1,topicSelectedAcs:null,loginDisabled:!1,displayMobile:window.innerWidth<=MEDIA_BREAKPOINT,showInfoPanel:!1,mobilePanel:"sidepanel",contextMenuVisible:!1,contextMenuBounds:null,contextMenuClickAt:null,contextMenuParams:null,contextMenuItems:[],serverVersion:"no connection",contactsSearchQuery:"",foundContacts:[],credMethod:""}}componentDidMount(){var e=this;window.addEventListener("resize",this.handleResize),window.addEventListener("online",function(){e.handleOnline(!0)}),window.addEventListener("offline",function(){e.handleOnline(!1)}),window.addEventListener("hashchange",this.handleHashRoute),document.addEventListener("visibilitychange",this.handleVisibilityEvent),this.setState({viewportWidth:document.documentElement.clientWidth}),Tinode.enableLogging(!0,!0),Tinode.onConnect=this.handleConnected,Tinode.onDisconnect=this.handleDisconnect,TinodeWeb.tnSetup(this.state.serverAddress,this.state.transport);var t;if(localStorage.getObject("keep-logged-in")&&(t=localStorage.getObject("auth-token")),t){t.expires=new Date(t.expires),Tinode.setAuthToken(t),Tinode.connect().catch(function(t){e.handleError(t.message,"err")});var a=parseUrlHash(window.location.hash);delete a.params.info,delete a.params.tab,a.path[0]="",window.location.hash=composeUrlHash(a.path,a.params)}else window.location.hash="";this.readTimer=null,this.readTimerCallback=null}componentWillUnmount(){window.removeEventListener("resize",this.handleResize),window.removeEventListener("hashchange",this.handleHashRoute),document.removeEventListener("visibilitychange",this.handleVisibilityEvent)}static tnSetup(e,t){Tinode.setup(APP_NAME,e,API_KEY,t)}handleResize(){var e=document.documentElement.clientWidth<=MEDIA_BREAKPOINT;this.setState({viewportWidth:document.documentElement.clientWidth}),this.state.displayMobile!=e&&this.setState({displayMobile:e})}handleHashRoute(){var e=parseUrlHash(window.location.hash);if(e.path&&0{300<=e.code&&"validate credentials"===e.text?o.handleCredentialsRequest(e.params):o.handleLoginSuccessful(o)}).catch(e=>{o.setState({loginDisabled:!1}),o.handleError(e.message,"err"),localStorage.removeItem("auth-token"),window.location.hash=""})}handleCredentialsRequest(e){var t=parseUrlHash(window.location.hash);t.path[0]="cred",t.params.method=e.cred[0],window.location.hash=composeUrlHash(t.path,t.params)}handleLoginSuccessful(e){e.handleError("",null),localStorage.getObject("keep-logged-in")&&localStorage.setObject("auth-token",Tinode.getAuthToken());var t=Tinode.getMeTopic();t.onMetaDesc=e.tnMeMetaDesc,e.setState({connected:!0,myUserId:Tinode.getCurrentUserID()}),t.subscribe(t.startMetaQuery().withLaterSub().withDesc().build()).catch(function(t){localStorage.removeItem("auth-token"),e.handleError(t.message,"err"),window.location.hash=""}),window.location.hash=setUrlSidePanel(window.location.hash,"contacts")}handleDisconnect(e){this.setState({connected:!1,topicSelectedOnline:!1,dialogSelected:null,errorText:e&&e.message?e.message:"Disconnected",errorLevel:e&&e.message?"err":"warn",loginDisabled:!1,contextMenuVisible:!1,serverVersion:"no connection"})}tnMeMetaDesc(e){e&&e.public&&this.setState({sidePanelTitle:e.public.fn,sidePanelAvatar:makeImageUrl(e.public.photo)})}tnData(e){let t=Tinode.getTopic(e.topic);t.msgStatus(e)!=Tinode.MESSAGE_STATUS_PENDING&&(clearTimeout(this.receivedTimer),this.receivedTimer=setTimeout(()=>{this.receivedTimer=void 0,t.noteRecv(e.seq)},RECEIVED_DELAY))}tnInitFind(){var e=Tinode.getFndTopic();if(e.isSubscribed())this.setState({contactsSearchQuery:""}),this.tnFndSubsUpdated();else{e.onSubsUpdated=this.tnFndSubsUpdated;var t=this;e.subscribe(e.startMetaQuery().withSub().withTags().build()).catch(function(e){t.handleError(e.message,"err")})}}tnFndSubsUpdated(){var e=[];Tinode.getFndTopic().contacts(function(t){e.push(t)}),this.setState({foundContacts:e})}handleSearchContacts(e){var t=Tinode.getFndTopic(),a=this;t.setMeta({desc:{public:e}}).then(function(){return t.getMeta(t.startMetaQuery().withSub().build())}).catch(function(e){a.handleError(e.message,"err")})}handleTopicSelected(e,t,a,n){e?(this.state.topicSelected!=e&&(window.location.hash=setUrlTopic(window.location.hash,e)),this.setState({errorText:"",errorLevel:null,mobilePanel:"topic-view",topicSelectedOnline:a,topicSelectedAcs:n,showInfoPanel:!1})):(this.state.topicSelected&&(window.location.hash=setUrlTopic(window.location.hash,null)),this.setState({errorText:"",errorLevel:null,mobilePanel:"sidepanel",topicSelectedOnline:!1,topicSelectedAcs:null,showInfoPanel:!1}))}handleTopicSelectedOnline(e){"boolean"==typeof e&&this.setState({topicSelectedOnline:e})}handleTopicSelectedAcs(e){this.setState({topicSelectedAcs:e})}handleHideMessagesView(){this.setState({mobilePanel:"sidepanel"}),window.location.hash=setUrlTopic(window.location.hash,null)}handleSendMessage(e,t,a){let n=Tinode.getTopic(this.state.topicSelected),s=Drafty.parse(e);s&&!Drafty.isPlainText(s)&&(e=s),e=n.createMessage(e),e._uploader=a,t&&t.catch(e=>{this.handleError(e.message,"err")}),n.isSubscribed()||(!t&&(t=Promise.resolve()),t=t.then(()=>n.subscribe())),n.publishDraft(e,t).catch(e=>{this.handleError(e.message,"err")})}handleNewAccount(){window.location.hash=setUrlSidePanel(window.location.hash,"register")}handleNewAccountRequest(e,t,a,n,s){var o=this;Tinode.connect(this.state.serverAddress).then(function(){var o=Tinode.addCredential({public:a,tags:s},n);return Tinode.createAccountBasic(e,t,o)}).then(function(e){300<=e.code&&"validate credentials"===e.text?o.handleCredentialsRequest(e.params):o.handleLoginSuccessful(o)}).catch(function(e){o.handleError(e.message,"err")})}handleUpdateAccountRequest(e,t,a){var n=this;(t||a)&&Tinode.getMeTopic().setMeta({desc:{public:t,private:a}}).catch(function(e){n.handleError(e.message,"err")}),e&&Tinode.updateAccountBasic(null,Tinode.getCurrentLogin(),e).catch(function(e){n.handleError(e.message,"err")})}handleUpdateAccountTagsRequest(e){var t=this;Tinode.getFndTopic().setMeta({tags:e}).catch(function(e){t.handleError(e.message,"err")})}handleSettings(){window.location.hash=setUrlSidePanel(window.location.hash,this.state.myUserId?"edit":"settings")}handleConnectionSettings(e,t){t=t||this.state.transport,e=e||this.state.serverAddress,this.setState({serverAddress:e,transport:t,sidePanelSelected:"login"}),TinodeWeb.tnSetup(e,t)}handleSidepanelCancel(){var e=parseUrlHash(window.location.hash);e.path[0]=this.state.myUserId?"contacts":"",e.params&&(delete e.params.code,delete e.params.method,delete e.params.tab),window.location.hash=composeUrlHash(e.path,e.params),this.setState({errorText:"",errorLevel:null})}handleNewTopic(){window.location.hash=setUrlSidePanel(window.location.hash,"newtpk")}handleNewTopicRequest(e,t,a,n){var s,o=this,r=e?Tinode.newTopicWith(e):Tinode.newTopic(),i=r.startMetaQuery().withDesc().withSub().withData();e||(i=i.withTags(),s={desc:{public:t,private:a},tags:n}),r.subscribe(i.build(),s).then(function(){window.location.hash=setUrlSidePanel(window.location.hash,"contacts"),o.handleTopicSelected(r.name,void 0,Tinode.isTopicOnline(r.name),r.getAccessMode())}).catch(function(e){o.handleError(e.message,"err")})}handleTopicUpdateRequest(e,t,a,n){var s=this,o=Tinode.getTopic(e);if(o){var r={};t&&(r.public=t),a&&(r.private={comment:a}),n&&(r.defacs=n),o.setMeta({desc:r}).catch(function(e){s.handleError(e.message,"err")})}}handleChangePermissions(e,t,a){var n=this,s=Tinode.getTopic(e);if(s){var o=s.getAccessMode();a?(o.updateGiven(t),t=o.getGiven()):(o.updateWant(t),t=o.getWant()),s.setMeta({sub:{user:a,mode:t}}).catch(function(e){n.handleError(e.message,"err")})}}handleTagsUpdated(e,t){var a=Tinode.getTopic(e);if(a){var n=this;a.setMeta({tags:t}).catch(function(e){n.handleError(e.message,"err")})}}handleLogout(){localStorage.removeItem("auth-token"),this.setState(this.getInitialState()),TinodeWeb.tnSetup(this.state.serverAddress,this.state.transport),window.location.hash=""}handleLeaveUnsubRequest(e){var t=Tinode.getTopic(e);t&&t.leave(!0).then(()=>{window.location.hash=setUrlTopic(window.location.hash,"")}).catch(e=>{this.handleError(e.message,"err")})}handleDialogCancel(){this.setState({dialogSelected:null})}handleShowContextMenu(e,t){this.setState({contextMenuVisible:!0,contextMenuClickAt:{x:e.x,y:e.y},contextMenuParams:e,contextMenuItems:t||this.defaultTopicContextMenu(e.topicName),contextMenuBounds:ReactDOM.findDOMNode(this).getBoundingClientRect()})}defaultTopicContextMenu(e){var t=!1,a=!1,n=!1,s=!1,o=Tinode.getTopic(e);if(o&&o.isSubscribed()){n=!0;var r=o.getAccessMode();t=r&&r.isMuted(),a=r&&!r.isJoiner(),s=r&&r.isDeleter()}return[n?{title:"Info",handler:this.handleShowInfoView}:null,n?ContextMenuItems.messages_clear:null,n&&s?ContextMenuItems.messages_clear_hard:null,n?t?ContextMenuItems.topic_unmute:ContextMenuItems.topic_mute:null,n?a?ContextMenuItems.topic_unblock:ContextMenuItems.topic_block:null,ContextMenuItems.topic_delete]}handleHideContextMenu(){this.setState({contextMenuVisible:!1,contextMenuClickAt:null,contextMenuParams:null,contextMenuBounds:null})}handleShowInfoView(){window.location.hash=addUrlParam(window.location.hash,"info",!0),this.setState({showInfoPanel:!0})}handleHideInfoView(){window.location.hash=removeUrlParam(window.location.hash,"info"),this.setState({showInfoPanel:!1})}handleMemberUpdateRequest(e,t,a){if(e){var n=Tinode.getTopic(e);if(n){var s=this;t&&0n?2:30>n?1:0:0;return n.toFixed(s)+" "+t[a]}function makeImageUrl(e){return e&&e.type&&e.data?"data:image/"+e.type+";base64,"+e.data:null}function fitImageSize(e,t,a,n,s){var o=Math.min;if(!e||!t||!a||!n)return null;s&&(a=n=o(a,n));var r=o(o(e,a)/e,o(t,n)/t),i={dstWidth:0|e*r,dstHeight:0|t*r};return s?(i.dstWidth=i.dstHeight=o(i.dstWidth,i.dstHeight),i.srcWidth=i.srcHeight=o(e,t),i.xoffset=0|(e-i.srcWidth)/2,i.yoffset=0|(t-i.srcWidth)/2):(i.xoffset=i.yoffset=0,i.srcWidth=e,i.srcHeight=t),i}function fileNameForMime(e,t){var a=SUPPORTED_IMAGE_FORMATS.indexOf(t),n=MIME_EXTENSIONS[a],s=e.lastIndexOf(".");return 0<=s&&(e=e.substring(0,s)),e+"."+n}function getMimeType(e){var t=/^data:(image\/[-+a-z0-9.]+);base64/.exec(e);return t&&1SUPPORTED_IMAGE_FORMATS.indexOf(e.type)?"image/jpeg":e.type,c=i.toDataURL(l),p=c.split(",");if(l=getMimeType(p[0]),!l)return void o("Unsupported image format");var m=.78;if("image/jpeg"==l)for(;base64DecodedLen(c.length)>MAX_INBAND_ATTACHMENT_SIZE&&.45MAX_INBAND_ATTACHMENT_SIZE?void o("The image size "+bytesToHumanSize(base64DecodedLen(c.length))+" exceeds the "+bytesToHumanSize(MAX_INBAND_ATTACHMENT_SIZE)+" limit.","err"):void(i=null,s(c.split(",")[1],l,r.dstWidth,r.dstHeight,fileNameForMime(e.name,l)))},r.src=URL.createObjectURL(e)}function imageFileToBase64(e,t,a){var n=new FileReader;n.addEventListener("load",function(){var s=n.result.split(","),o=getMimeType(s[0]);if(!o)return void a("Failed to process image file");var r=new Image;r.crossOrigin="Anonymous",r.onload=function(){t(s[1],o,this.width,this.height,fileNameForMime(e.name,o))},r.onerror=function(){a("Image format not recognized")},r.src=URL.createObjectURL(e)},!1),n.readAsDataURL(e)}function fileToBase64(e,t){var a=new FileReader;a.addEventListener("load",function(){t(e.type,a.result.split(",")[1],e.name)}),a.readAsDataURL(e)}function filePasted(e,t,a,n){var s=(e.clipboardData||e.originalEvent.clipboardData||{}).items;for(var o in s){var r=s[o];if("file"===r.kind){var i=r.getAsFile();if(!i){console.log("Failed to get file object from pasted file item",r.kind,r.type);continue}return i.type&&"image"==i.type.split("/")[0]?i.size>MAX_INBAND_ATTACHMENT_SIZE||0>SUPPORTED_IMAGE_FORMATS.indexOf(i.type)?imageFileScaledToBase64(i,MAX_IMAGE_DIM,MAX_IMAGE_DIM,!1,t,n):imageFileToBase64(i,t,n):fileToBase64(i,a,n),!0}}return!1}function updateFavicon(e){var t=document.getElementById("shortcut-icon");if(t){var a=document.head||document.getElementsByTagName("head")[0],n=document.createElement("link");n.type="image/png",n.id="shortcut-icon",n.rel="shortcut icon",n.href="img/logo32x32"+(0n.indexOf(e)))&&o.push(React.createElement("tr",{key:e},React.createElement("td",null,t[e]),React.createElement("td",{className:"checkbox"},0>a.indexOf(e)?React.createElement(CheckBox,{name:e,checked:0<=n.indexOf(e),onChange:this.handleChange}):React.createElement(CheckBox,{name:e,checked:0<=n.indexOf(e)})),this.props.compare?React.createElement("td",{className:"checkbox"},React.createElement(CheckBox,{name:e,checked:0<=s.indexOf(e)})):null));return React.createElement("div",{className:"panel-form-column"},this.props.userTitle?React.createElement("ul",{className:"contact-box"},React.createElement(Contact,{item:this.props.item,title:this.props.userTitle,avatar:makeImageUrl(this.props.userAvatar?this.props.userAvatar:null)})):null,React.createElement("label",{className:"small"},"Permissions"),React.createElement("table",{className:"permission-editor"},this.props.compare?React.createElement("thead",null,React.createElement("tr",null,React.createElement("th",null),React.createElement("th",null,this.props.modeTitle),React.createElement("th",null,this.props.compareTitle))):null,React.createElement("tbody",null,o)),React.createElement("br",null),React.createElement("div",{className:"dialog-buttons"},React.createElement("button",{className:"blue",onClick:this.handleSubmit},"Ok"),React.createElement("button",{className:"white",onClick:this.handleCancel},"Cancel")))}}class ChipInput extends React.Component{constructor(e){super(e),this.state={placeholder:e.chips?"":e.prompt,sortedChips:ChipInput.sortChips(e.chips,e.required),chipIndex:ChipInput.indexChips(e.chips),input:"",focused:!1},this.handleTextInput=this.handleTextInput.bind(this),this.removeChipAt=this.removeChipAt.bind(this),this.handleChipCancel=this.handleChipCancel.bind(this),this.handleFocusGained=this.handleFocusGained.bind(this),this.handleFocusLost=this.handleFocusLost.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this)}componentWillReceiveProps(e){this.setState({sortedChips:ChipInput.sortChips(e.chips,e.required),chipIndex:ChipInput.indexChips(e.chips)}),e.chips.length>this.props.chips.length&&this.setState({input:""})}static indexChips(e){var t={},a=0;return e.map(function(e){t[e.user]=a,a++}),t}static sortChips(e,t){var a=[],n=[];return e.map(function(e){e.user===t?a.push(e):n.push(e)}),a.concat(n)}handleTextInput(t){this.setState({input:t.target.value}),this.props.filterFunc&&this.props.filterFunc(t.target.value)}removeChipAt(e){var t=this.state.sortedChips[e];this.props.onChipRemoved(t.user,this.state.chipIndex[t.user])}handleChipCancel(e,t){this.removeChipAt(t)}handleFocusGained(){this.setState({focused:!0})}handleFocusLost(){this.setState({focused:!1}),this.props.onFocusLost&&this.props.onFocusLost(this.state.input)}handleKeyDown(t){if(!("Backspace"===t.key))"Enter"===t.key?this.props.onEnter&&this.props.onEnter(this.state.input):"Escape"===t.key&&this.props.onCancel&&this.props.onCancel();else if(0==this.state.input.length&&0{e.push(React.createElement("div",{className:"avatar-box"},React.createElement(LetterTile,{topic:t.user,avatar:makeImageUrl(t.public?t.public.photo:null)||!0,title:t.public?t.public.fn:null,key:t.user})))}),React.createElement("div",{id:"topic-users"},e)}}class LoginView extends React.Component{constructor(e){super(e),this.state={login:e.login,password:"",hostName:e.serverAddress,saveToken:localStorage.getObject("keep-logged-in")},this.handleLoginChange=this.handleLoginChange.bind(this),this.handlePasswordChange=this.handlePasswordChange.bind(this),this.handleServerAddressChange=this.handleServerAddressChange.bind(this),this.handleToggleSaveToken=this.handleToggleSaveToken.bind(this),this.handleSubmit=this.handleSubmit.bind(this)}handleLoginChange(t){this.setState({login:t.target.value})}handlePasswordChange(t){this.setState({password:t.target.value})}handleServerAddressChange(e){this.setState({hostName:e}),this.props.onServerAddressChange(e)}handleToggleSaveToken(){localStorage.setObject("keep-logged-in",!this.state.saveToken),this.setState({saveToken:!this.state.saveToken})}handleSubmit(t){t.preventDefault(),this.props.onLogin(this.state.login.trim(),this.state.password.trim())}render(){var e="blue";return this.props.disabled&&(e+=" disabled"),React.createElement("form",{id:"login-form",onSubmit:this.handleSubmit},React.createElement("input",{type:"text",id:"inputLogin",placeholder:"Login (alice, bob, carol, dave, frank)",autoComplete:"username",value:this.state.login,onChange:this.handleLoginChange,required:!0,autoFocus:!0}),React.createElement("input",{type:"password",id:"inputPassword",placeholder:"Password (alice123, bob123, ...)",autoComplete:"current-password",value:this.state.password,onChange:this.handlePasswordChange,required:!0}),React.createElement("div",{className:"panel-form-row"},React.createElement(HostSelector,{serverAddress:this.props.serverAddress,onServerAddressChange:this.handleServerAddressChange})),React.createElement("div",{className:"panel-form-row"},React.createElement(CheckBox,{id:"save-token",name:"save-token",checked:this.state.saveToken,onChange:this.handleToggleSaveToken}),React.createElement("label",{forHtml:"save-token"},"\xA0Keep me logged in")),React.createElement("div",{className:"dialog-buttons"},React.createElement("button",{className:e,type:"submit"},"Sign in")))}}class CreateAccountView extends React.PureComponent{constructor(e){super(e),this.state={login:"",password:"",password2:"",email:"",fn:"",imageDataUrl:null,errorCleared:!1,saveToken:localStorage.getObject("keep-logged-in")},this.handleLoginChange=this.handleLoginChange.bind(this),this.handlePasswordChange=this.handlePasswordChange.bind(this),this.handlePassword2Change=this.handlePassword2Change.bind(this),this.handleEmailChange=this.handleEmailChange.bind(this),this.handleFnChange=this.handleFnChange.bind(this),this.handleImageChanged=this.handleImageChanged.bind(this),this.handleToggleSaveToken=this.handleToggleSaveToken.bind(this),this.handleSubmit=this.handleSubmit.bind(this)}handleLoginChange(t){this.setState({login:t.target.value})}handlePasswordChange(t){this.setState({password:t.target.value})}handlePassword2Change(t){this.setState({password2:t.target.value})}handleEmailChange(t){this.setState({email:t.target.value})}handleFnChange(t){this.setState({fn:t.target.value})}handleImageChanged(e){this.setState({imageDataUrl:e})}handleToggleSaveToken(){localStorage.setObject("keep-logged-in",!this.state.saveToken),this.setState({saveToken:!this.state.saveToken})}handleSubmit(t){t.preventDefault(),this.state.password.trim()==this.state.password2.trim()?(this.setState({errorCleared:!1}),this.props.onCreateAccount(this.state.login.trim(),this.state.password.trim(),vcard(this.state.fn,this.state.imageDataUrl),{meth:"email",val:this.state.email})):this.props.onError("Passwords don't match","warn")}render(){var e="blue";return this.props.disabled&&(e+=" disabled"),React.createElement("form",{className:"panel-form-column",onSubmit:this.handleSubmit},React.createElement("div",{className:"panel-form-row"},React.createElement("div",{className:"panel-form-column"},React.createElement("input",{type:"text",placeholder:"Login",autoComplete:"user-name",value:this.state.login,onChange:this.handleLoginChange,required:!0,autoFocus:!0}),React.createElement("input",{type:"password",placeholder:"Password",autoComplete:"new-password",value:this.state.password,onChange:this.handlePasswordChange,required:!0}),React.createElement("input",{type:"password",placeholder:"Repeat password",autoComplete:"new-password",value:this.state.password2,onChange:this.handlePassword2Change,required:!0})),React.createElement(AvatarUpload,{onImageChanged:this.handleImageChanged,onError:this.props.onError})),React.createElement("div",{className:"panel-form-row"},React.createElement("input",{type:"email",placeholder:"Email, e.g john.doe@example.com",autoComplete:"email",value:this.state.email,onChange:this.handleEmailChange,required:!0})),React.createElement("div",{className:"panel-form-row"},React.createElement("input",{type:"text",placeholder:"Full name, e.g. John Doe",autoComplete:"name",value:this.state.fn,onChange:this.handleFnChange,required:!0})),React.createElement("div",{className:"panel-form-row"},React.createElement(CheckBox,{id:"save-token",name:"save-token",checked:this.state.saveToken,onChange:this.handleToggleSaveToken}),React.createElement("label",{forHtml:"save-token"},"\xA0Keep me logged in")),React.createElement("div",{className:"dialog-buttons"},React.createElement("button",{className:e,type:"submit"},"Sign up")))}}class AvatarUpload extends React.Component{constructor(e){super(e),this.state={dataUrl:e.avatar},this.handleFileUpload=this.handleFileUpload.bind(this)}componentWillReceiveProps(e){this.props.avatar!=e.avatar&&this.setState({dataUrl:e.avatar})}handleFileUpload(t){var e=this;imageFileScaledToBase64(t.target.files[0],AVATAR_SIZE,AVATAR_SIZE,!0,function(t,a){var n=makeImageUrl({data:t,type:a});e.setState({dataUrl:n}),e.props.onImageChanged(n)},function(e){this.props.onError(e,"err")}),t.target.value=""}render(){var e="file-input-avatar-"+(Math.random()+"").substr(2);return React.createElement("div",{className:"avatar-upload"},this.state.dataUrl?React.createElement("img",{src:this.state.dataUrl,className:"preview"}):this.props.readOnly&&this.props.uid?React.createElement("div",{className:"avatar-box"},React.createElement(LetterTile,{avatar:!0,topic:this.props.uid,title:this.props.title})):React.createElement("div",{className:"blank"},"128\xD7128"),this.props.readOnly?null:React.createElement("input",{type:"file",id:e,className:"inputfile hidden",accept:"image/*",onChange:this.handleFileUpload}),this.props.readOnly?null:React.createElement("label",{htmlFor:e,className:"round"},React.createElement("i",{className:"material-icons"},"file_upload")))}}class SettingsView extends React.PureComponent{constructor(e){super(e),this.state={transport:"def"},this.handleSubmit=this.handleSubmit.bind(this),this.handleTransportSelected=this.handleTransportSelected.bind(this)}handleSubmit(t){t.preventDefault(),this.props.onUpdate(null,this.state.transport)}handleTransportSelected(t){this.setState({transport:t.currentTarget.value})}render(){var e={def:"default",ws:"websocket",lp:"long polling"},t=[],a=this;return["def","ws","lp"].map(function(n){var s="transport-"+n,o=e[n];t.push(React.createElement("li",{key:n},React.createElement("input",{type:"radio",id:s,name:"transport-select",value:n,checked:a.state.transport===n,onChange:a.handleTransportSelected}),React.createElement("label",{htmlFor:s},o)))}),React.createElement("form",{id:"settings-form",onSubmit:this.handleSubmit},React.createElement("label",{className:"small"},"Wire transport:"),React.createElement("ul",{className:"quoted"},t),React.createElement("div",{className:"dialog-buttons"},React.createElement("button",{type:"submit",className:"blue"},"Update")))}}class SideNavbar extends React.PureComponent{render(){return React.createElement("div",{id:"side-caption-panel",className:"caption-panel"},React.createElement("div",{id:"self-avatar",className:"avatar-box"},React.createElement(LetterTile,{avatar:this.props.avatar,topic:this.props.myUserId,title:this.props.title})),React.createElement("div",{id:"sidepanel-title",className:"panel-title"},this.props.title),"login"===this.props.state?React.createElement(MenuStart,{onSignUp:this.props.onSignUp,onSettings:this.props.onSettings}):"contacts"===this.props.state?React.createElement(MenuContacts,{onNewTopic:this.props.onNewTopic,onSettings:this.props.onSettings}):null,this.props.onCancel?React.createElement(MenuCancel,{onCancel:this.props.onCancel}):null)}}class MenuStart extends React.PureComponent{render(){return React.createElement("div",null,React.createElement("a",{href:"javascript:;",onClick:this.props.onSignUp},React.createElement("i",{className:"material-icons"},"person_add")),"\xA0",React.createElement("a",{href:"javascript:;",onClick:this.props.onSettings},React.createElement("i",{className:"material-icons"},"settings")))}}class MenuContacts extends React.PureComponent{render(){return React.createElement("div",null,React.createElement("a",{href:"javascript:;",onClick:this.props.onNewTopic},React.createElement("i",{className:"material-icons"},"chat")),"\xA0",React.createElement("a",{href:"javascript:;",onClick:this.props.onSettings},React.createElement("i",{className:"material-icons"},"settings")))}}class SidepanelView extends React.Component{constructor(e){super(e),this.handleLoginRequested=this.handleLoginRequested.bind(this)}handleLoginRequested(e,t){this.props.onLoginRequest(e,t)}render(){var e=null,t=!1,a=void 0,n=this.props.state||(this.props.myUserId?"contacts":"login");switch(n){case"login":e="Sign In";break;case"register":e="Create Account",a=this.props.onCancel;break;case"settings":e="Settings",a=this.props.onCancel;break;case"edit":e="Edit Account",a=this.props.onCancel;break;case"contacts":e=this.props.title,t=!this.props.avatar||this.props.avatar;break;case"newtpk":e="Start New Chat",a=this.props.onCancel;break;case"cred":e="Confirm Credentials",a=this.props.onCancel;break;default:;}return React.createElement("div",{id:"sidepanel",className:this.props.hideSelf?"nodisplay":null},React.createElement(SideNavbar,{state:n,title:e,avatar:t,myUserId:this.props.myUserId,onSignUp:this.props.onSignUp,onSettings:this.props.onSettings,onNewTopic:this.props.onNewTopic,onCancel:a}),React.createElement(ErrorPanel,{level:this.props.errorLevel,text:this.props.errorText,onClearError:this.props.onError}),"login"===n?React.createElement(LoginView,{login:this.props.login,disabled:this.props.loginDisabled,serverAddress:this.props.serverAddress,onLogin:this.handleLoginRequested,onServerAddressChange:this.props.onConnectionSettings}):"register"===n?React.createElement(CreateAccountView,{onCreateAccount:this.props.onCreateAccount,onCancel:this.props.onCancel,onError:this.props.onError}):"settings"===n?React.createElement(SettingsView,{onCancel:this.props.onCancel,onUpdate:this.props.onConnectionSettings}):"edit"===n?React.createElement(EditAccountView,{login:this.props.login,onSubmit:this.props.onUpdateAccount,onUpdateTags:this.props.onUpdateAccountTags,onLogout:this.props.onLogout,onCancel:this.props.onCancel,onError:this.props.onError}):"contacts"===n?React.createElement(ContactsView,{connected:this.props.connected,topicSelected:this.props.topicSelected,showContextMenu:this.props.showContextMenu,onTopicSelected:this.props.onTopicSelected,onAcsChange:this.props.onAcsChange,onOnlineChange:this.props.onOnlineChange}):"newtpk"===n?React.createElement(NewTopicView,{contactsSearchQuery:this.props.contactsSearchQuery,foundContacts:this.props.foundContacts,onInitFind:this.props.onInitFind,onSearchContacts:this.props.onSearchContacts,onCreateTopic:this.props.onCreateTopic,onError:this.props.onError}):"cred"===n?React.createElement(ValidationView,{credCode:this.props.credCode,credMethod:this.props.credMethod,onSubmit:this.props.onValidateCredentials,onCancel:this.props.onCancel,onError:this.props.onError}):null)}}class ErrorPanel extends React.PureComponent{constructor(e){super(e),this.state={show:!1},this.hide=this.hide.bind(this)}componentWillReceiveProps(e){this.setState({show:!!e.level})}hide(){this.setState({show:!1}),this.props.onClearError&&this.props.onClearError()}render(){var e="err"==this.props.level?"error":"warning";return React.createElement("div",{className:this.state.show?"err"==this.props.level?"alert-box error":"alert-box warning":"alert-box"},React.createElement("div",{className:"icon"},React.createElement("i",{className:"material-icons"},e)),this.props.text,React.createElement("div",{className:"cancel"},React.createElement(MenuCancel,{onCancel:this.hide})))}}class EditAccountView extends React.Component{constructor(e){super(e);let t=Tinode.getMeTopic(),a=t.getDefaultAccess(),n=Tinode.getFndTopic();this.state={fullName:t.public?t.public.fn:void 0,avatar:makeImageUrl(t.public?t.public.photo:null),address:Tinode.getCurrentUserID(),auth:a.auth,anon:a.anon,tags:n.tags(),previousOnTags:n.onTagsUpdated},this.tnNewTags=this.tnNewTags.bind(this),this.handleFullNameUpdate=this.handleFullNameUpdate.bind(this),this.handlePasswordUpdate=this.handlePasswordUpdate.bind(this),this.handleImageChanged=this.handleImageChanged.bind(this),this.handleTagsUpdated=this.handleTagsUpdated.bind(this)}componentDidMount(){let e=Tinode.getFndTopic();e.onTagsUpdated=this.tnNewTags,e.isSubscribed()||e.subscribe(e.startMetaQuery().withLaterDesc().withTags().build()).catch(e=>{this.props.onError(e.message,"err")})}componentWillUnmount(){var e=Tinode.getFndTopic();e.onTagsUpdated=this.state.previousOnTags}tnNewTags(e){this.setState({tags:e})}handleFullNameUpdate(e){this.setState({fullName:e}),this.props.onSubmit(null,vcard(e,this.state.avatar))}handlePasswordUpdate(e){this.setState({password:e}),this.props.onSubmit(e,null)}handleImageChanged(e){this.setState({avatar:e}),this.props.onSubmit(null,vcard(this.state.fullName,e))}handleTagsUpdated(e){arrayEqual(this.state.tags.slice(0),e.slice(0))||this.props.onUpdateTags(e)}render(){var e=[];return this.state.tags.map(function(t){e.push(React.createElement("span",{className:"badge",key:e.length},t))}),0==e.length&&(e=React.createElement("i",null,"No tags defined. Add some.")),React.createElement("div",{id:"edit-account",className:"panel-form"},React.createElement("div",{className:"panel-form-row"},React.createElement("div",{className:"panel-form-column"},React.createElement("div",null,React.createElement("label",{className:"small"},"Your name")),React.createElement("div",null,React.createElement(InPlaceEdit,{placeholder:"Full name, e.g. John Doe",text:this.state.fullName,onFinished:this.handleFullNameUpdate})),React.createElement("div",null,React.createElement("label",{className:"small"},"Password")),React.createElement("div",null,React.createElement(InPlaceEdit,{placeholder:"Unchanged",type:"password",onFinished:this.handlePasswordUpdate}))),React.createElement(AvatarUpload,{avatar:this.state.avatar,uid:this.state.address,title:this.state.fullName,onImageChanged:this.handleImageChanged,onError:this.props.onError})),React.createElement("div",{className:"hr"}),React.createElement("div",{className:"panel-form-column"},React.createElement("div",{className:"panel-form-row"},React.createElement("label",null,"Login:"),React.createElement("tt",null,this.props.login)),React.createElement("div",{className:"panel-form-row"},React.createElement("label",null,"Address:"),React.createElement("tt",null,this.state.address)),React.createElement("div",null,React.createElement("label",{className:"small"},"Default access mode:")),React.createElement("div",{className:"quoted"},React.createElement("div",null,"Auth: ",React.createElement("tt",null,this.state.auth)),React.createElement("div",null,"Anon: ",React.createElement("tt",null,this.state.anon)))),React.createElement("div",{className:"hr"}),React.createElement(TagManager,{title:"Tags (user discovery)",activated:!1,tags:this.state.tags,onSubmit:this.handleTagsUpdated}),React.createElement("div",{className:"hr"}),React.createElement("div",{className:"panel-form-column"},React.createElement("a",{href:"javascript:;",className:"red flat-button",onClick:this.props.onLogout},React.createElement("i",{className:"material-icons"},"exit_to_app")," Logout")))}}class TagManager extends React.Component{constructor(e){super(e),this.state={tags:this.props.tags,tagInput:"",activated:this.props.activated,noTagsMessage:"Add some tags"},this.handleShowTagManager=this.handleShowTagManager.bind(this),this.handleTagInput=this.handleTagInput.bind(this),this.handleAddTag=this.handleAddTag.bind(this),this.handleRemoveTag=this.handleRemoveTag.bind(this),this.handleSubmit=this.handleSubmit.bind(this),this.handleCancel=this.handleCancel.bind(this)}componentWillReceiveProps(e){this.setState({tags:e.tags})}handleShowTagManager(){this.setState({activated:!0})}handleTagInput(e){if(this.setState({tagInput:e}),0=MIN_TAG_LENGTH&&this.handleAddTag(a)}}}handleAddTag(e){if(e=e.trim(),0e.state.index[s].delta&&n.push(s)}),this.props.onSubmit(t,a,n)}handleCancel(){this.props.onCancel()}render(){return React.createElement("div",{id:"group-manager"},React.createElement("div",{className:"panel-form-row"},React.createElement("label",{className:"small"},"Group members")),React.createElement("div",{className:"panel-form-row"},React.createElement(ChipInput,{chips:this.state.members,required:this.props.requiredMember,prompt:"add members",filterFunc:this.handleContactFilter,onChipRemoved:this.handleMemberRemoved})),React.createElement("div",{className:"panel-form-row"},React.createElement("label",{className:"small"},"All contacts")),React.createElement(ContactList,{contacts:this.props.contacts,topicSelected:this.state.selectedContacts,filter:this.state.contactFilter,filterFunc:GroupManager.doContactFiltering,emptyListMessage:this.state.noContactsMessage,showOnline:!1,showUnread:!1,onTopicSelected:this.handleContactSelected}),React.createElement("div",{id:"group-manager-buttons",className:"panel-form-row"},React.createElement("button",{className:"blue",onClick:this.handleSubmit},"OK"),React.createElement("button",{className:"white",onClick:this.handleCancel},"Cancel")))}}class NewTopicView extends React.Component{constructor(e){super(e),this.state={tabSelected:"p2p",searchQuery:e.contactsSearchQuery,contactList:e.foundContacts,contactSelected:null},this.handleTabClick=this.handleTabClick.bind(this),this.handleContactSelected=this.handleContactSelected.bind(this),this.handleNewGroupSubmit=this.handleNewGroupSubmit.bind(this),this.handleGroupByID=this.handleGroupByID.bind(this)}componentDidMount(){this.props.onInitFind()}componentWillReceiveProps(e){this.setState({searchQuery:e.contactsSearchQuery,contactList:e.foundContacts})}handleTabClick(t){t.preventDefault(),window.location.hash=addUrlParam(window.location.hash,"tab",t.currentTarget.dataset.id),this.setState({tabSelected:t.currentTarget.dataset.id,contactSelected:null})}handleContactSelected(e){"p2p"===this.state.tabSelected&&(window.location.hash=removeUrlParam(window.location.hash,"tab"),this.props.onCreateTopic(e,void 0))}handleNewGroupSubmit(e,t,a,n){window.location.hash=removeUrlParam(window.location.hash,"tab"),this.props.onCreateTopic(void 0,vcard(e,t),a,n)}handleGroupByID(e){window.location.hash=removeUrlParam(window.location.hash,"tab"),this.props.onCreateTopic(e)}render(){return React.createElement("div",{className:"flex-column"},React.createElement("ul",{className:"tabbar"},React.createElement("li",{className:"p2p"===this.state.tabSelected?"active":null},React.createElement("a",{href:"javascript:;","data-id":"p2p",onClick:this.handleTabClick},"1:1")),React.createElement("li",{className:"grp"===this.state.tabSelected?"active":null},React.createElement("a",{href:"javascript:;","data-id":"grp",onClick:this.handleTabClick},"group")),React.createElement("li",{className:"byid"===this.state.tabSelected?"active":null},React.createElement("a",{href:"javascript:;","data-id":"byid",onClick:this.handleTabClick},"by id"))),"grp"===this.state.tabSelected?React.createElement(NewTopicGroup,{onSubmit:this.handleNewGroupSubmit}):"byid"===this.state.tabSelected?React.createElement(NewTopicById,{onSubmit:this.handleGroupByID,onError:this.props.onError}):React.createElement("div",{className:"flex-column"},React.createElement(SearchContacts,{type:"p2p",searchQuery:this.state.searchQuery,onSearchContacts:this.props.onSearchContacts}),React.createElement(ContactList,{contacts:this.state.contactList,emptyListMessage:"Use search to find contacts",topicSelected:this.state.selectedContact,showOnline:!1,showUnread:!1,showContextMenu:!1,onTopicSelected:this.handleContactSelected})))}}class NewTopicGroup extends React.PureComponent{constructor(e){super(e),this.state={fn:"",private:"",imageDataUrl:null,tags:[]},this.handleFnChange=this.handleFnChange.bind(this),this.handlePrivateChange=this.handlePrivateChange.bind(this),this.handleImageChanged=this.handleImageChanged.bind(this),this.handleTagsChanged=this.handleTagsChanged.bind(this),this.handleTagsChanged=this.handleTagsChanged.bind(this),this.handleSubmit=this.handleSubmit.bind(this)}handleFnChange(t){this.setState({fn:t.target.value})}handlePrivateChange(t){this.setState({private:t.target.value})}handleImageChanged(e){this.setState({imageDataUrl:e})}handleTagsChanged(e){this.setState({tags:e})}handleSubmit(t){t.preventDefault(),this.state.fn&&this.state.fn.trim()&&this.props.onSubmit(this.state.fn.trim(),this.state.imageDataUrl,this.state.private.trim(),this.state.tags)}render(){var e="blue";return this.props.disabled&&(e+=" disabled"),React.createElement("form",{className:"panel-form",onSubmit:this.handleSubmit},React.createElement("div",{className:"panel-form-row"},React.createElement("div",{className:"panel-form-column"},React.createElement("label",{className:"small",htmlFor:"new-topic-fn"},"Group name"),React.createElement("input",{type:"text",id:"new-topic-fn",placeholder:"Freeform name of the group",value:this.state.fn,onChange:this.handleFnChange,autoFocus:!0,required:!0}),React.createElement("br",null),React.createElement("label",{className:"small",htmlFor:"new-topic-priv"},"Private comment"),React.createElement("input",{type:"text",id:"new-topic-priv",placeholder:"Visible to you only",value:this.state.private,onChange:this.handlePrivateChange})),React.createElement(AvatarUpload,{onError:this.props.onError,onImageChanged:this.handleImageChanged})),React.createElement(TagManager,{tags:this.state.tags,activated:!0,onTagsChanged:this.handleTagsChanged,title:"Optional tags (search and discovery)"}),React.createElement("div",{className:"dialog-buttons"},React.createElement("button",{className:e},"Create")))}}class SearchContacts extends React.Component{constructor(e){super(e),this.state={edited:!1,search:e.searchQuery},this.handleSearchChange=this.handleSearchChange.bind(this),this.handleSearch=this.handleSearch.bind(this),this.handleClear=this.handleClear.bind(this),this.handleKeyPress=this.handleKeyPress.bind(this)}componentWillUnmount(){this.state.search&&(this.setState({search:""}),this.props.onSearchContacts(DEL_CHAR))}handleSearchChange(t){this.setState({search:t.target.value})}handleSearch(t){t.preventDefault();var e=this.state.search.trim();0this.props.progress?React.createElement("a",{href:"javascript:;",onClick:this.props.onCancel},React.createElement("i",{className:"material-icons"},"close")," cancel"):React.createElement("span",null,"finishing..."))}}class Attachment extends React.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,a){var n=Tinode.getLargeFileHelper();this.setState({downloader:n}),n.download(e,t,a,e=>{this.setState({progress:e/this.props.size})}).then(()=>{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.uploader?this.props.onCancelUpload():this.state.downloader&&this.state.downloader.cancel()}render(){let e=this.props.filename||"file_attachment";36{this.downloadFile(this.props.downloadUrl,this.props.filename,this.props.mimetype)}),React.createElement("div",{className:"attachment"},React.createElement("div",null,React.createElement("i",{className:"material-icons big gray"},"insert_drive_file")),React.createElement("div",{className:"flex-column"},React.createElement("div",null,e," ",n),this.props.uploader||this.state.downloader?React.createElement(FileProgress,{progress:this.props.uploader?this.props.progress:this.state.progress,onCancel:this.handleCancel}):React.createElement("div",null,React.createElement("a",{href:t,download:this.props.filename,onClick:a},React.createElement("i",{className:"material-icons"},"file_download")," save"))))}}class MessagesView extends React.Component{constructor(e){super(e),this.state={messages:[],onlineSubs:[],topic:"",title:"",avatar:null,scrollPosition:0,readOnly:!e.acs||!e.acs.isWriter(),writeOnly:!e.acs||!e.acs.isReader(),typingIndicator:!1,imagePreview:null},this.propsChange=this.propsChange.bind(this),this.leave=this.leave.bind(this),this.handleScrollReference=this.handleScrollReference.bind(this),this.fetchMoreMessages=this.fetchMoreMessages.bind(this),this.handleDescChange=this.handleDescChange.bind(this),this.handleSubsUpdated=this.handleSubsUpdated.bind(this),this.handleNewMessage=this.handleNewMessage.bind(this),this.handleInfoReceipt=this.handleInfoReceipt.bind(this),this.handleImagePreview=this.handleImagePreview.bind(this),this.handleCloseImagePreview=this.handleCloseImagePreview.bind(this),this.handleContextClick=this.handleContextClick.bind(this),this.handleShowContextMenuMessage=this.handleShowContextMenuMessage.bind(this),this.handleBackNavigation=this.handleBackNavigation.bind(this)}componentDidUpdate(e,t){this.messagesScroller&&(t.title!=this.state.title||t.messages.length!=this.state.messages.length)&&(this.messagesScroller.scrollTop=this.messagesScroller.scrollHeight-this.state.scrollPosition)}componentDidMount(){this.propsChange(this.props),this.messagesScroller&&this.messagesScroller.addEventListener("scroll",this.fetchMoreMessages)}componentWillUnmount(){this.leave(),this.messagesScroller&&this.messagesScroller.removeEventListener("scroll",this.fetchMoreMessages)}componentWillReceiveProps(e){this.propsChange(e)}propsChange(e){if(!e||!e.topic)return this.setState({messages:[],onlineSubs:[],topic:null}),void this.leave();if(!e.connected)return void this.setState({onlineSubs:[]});var t=!this.props.connected&&e.connected,a=Tinode.getTopic(e.topic);if(e.topic!=this.state.topic){var n=[],s=[];a.onData=this.handleNewMessage,a.onInfo=this.handleInfoReceipt,a.onMetaDesc=this.handleDescChange,a.onSubsUpdated=this.handleSubsUpdated,a.onPres=this.handleSubsUpdated,this.leave(),this.handleDescChange(a);var o=this.props.myUserId;a.subscribers(function(e){e.online&&e.user!=o&&s.push(e)}),a.messages(function(e){e.deleted||(n=n.concat(e))}),this.setState({messages:n,onlineSubs:s,topic:e.topic,imagePreview:null,scrollPosition:0}),t=!0,this.props.readTimerHandler(null)}if(this.setState({readOnly:!e.acs||!e.acs.isWriter(),writeOnly:!e.acs||!e.acs.isReader()}),!a.isSubscribed()&&t){var r=a.startMetaQuery().withLaterDesc().withLaterSub().withLaterData(MESSAGES_PAGE).withLaterDel();this.setState({fetchingMessages:!0}),a.subscribe(r.build()).then(()=>{this.setState({fetchingMessages:!1})}).catch(e=>{this.props.onError(e.message,"err"),this.setState({title:"Not found",avatar:null,readOnly:!0,writeOnly:!0,fetchingMessages:!1})})}}leave(){if(this.state.topic){var e=Tinode.getTopic(this.state.topic);e&&(e.isSubscribed()&&e.leave(!1).catch(function(e){console.log(e)}),e.onData=void 0,e.onInfo=void 0,e.onMetaDesc=void 0,e.onSubsUpdated=void 0,e.onPres=void 0)}}handleScrollReference(e){e&&(e.addEventListener("scroll",this.fetchMoreMessages),this.messagesScroller=e)}fetchMoreMessages(e){var t=this;if(0>=e.target.scrollTop){var a={scrollPosition:e.target.scrollHeight-e.target.scrollTop};this.setState(function(e){if(!e.fetchingMessages){var n=Tinode.getTopic(t.state.topic);n&&n.isSubscribed()&&n.msgHasMoreMessages()&&(a.fetchingMessages=!0,n.getMessagesPage(MESSAGES_PAGE).then(function(){t.setState({fetchingMessages:!1})}).catch(function(e){t.setState({fetchingMessages:!1}),t.props.onError(e.message,"err")}))}return a})}}handleDescChange(e){e.public&&this.setState({title:e.public.fn,avatar:makeImageUrl(e.public.photo)}),e.acs&&this.setState({readOnly:!e.acs.isWriter(),writeOnly:!e.acs.isReader()})}handleSubsUpdated(){if(this.state.topic){var e=[],t=this.props.myUserId,a=Tinode.getTopic(this.state.topic);a.subscribers(function(a){a.online&&a.user!=t&&e.push(a)}),this.setState({onlineSubs:e})}}handleNewMessage(e){var t=Tinode.getTopic(this.state.topic),a={messages:[]};if(t.messages(function(e){e.deleted||(a.messages=a.messages.concat(e))}),e&&!e.deleted){t.isNewMessage(e.seq)&&(a.scrollPosition=0);let n=t.msgStatus(e);n>=Tinode.MESSAGE_STATUS_SENT&&this.props.readTimerHandler(()=>{t.noteRead(e.seq)}),this.props.onData(e)}this.setState(a)}handleInfoReceipt(e){switch(e.what){case"kp":{clearTimeout(this.keyPressTimer);var t=this;this.keyPressTimer=setTimeout(function(){t.setState({typingIndicator:!1})},4000),this.state.typingIndicator||this.setState({typingIndicator:!0});break}case"read":case"recv":this.forceUpdate();break;default:console.log("Other change in topic: ",e.what);}}handleImagePreview(e){this.setState({imagePreview:e})}handleCloseImagePreview(){this.setState({imagePreview:null})}handleContextClick(t){t.preventDefault(),t.stopPropagation(),this.props.showContextMenu({topicName:this.state.topic,y:t.pageY,x:t.pageX})}handleShowContextMenuMessage(e){e.topicName=this.state.topic;var t=[ContextMenuItems.message_delete],a=Tinode.getTopic(e.topicName);if(a){var n=a.getAccessMode();n&&n.isDeleter()&&t.push(ContextMenuItems.message_delete_hard)}this.props.showContextMenu(e,t)}handleBackNavigation(){this.props.onHideMessagesView()}render(){var e=null;if(this.state.topic){for(var t=[],a=Tinode.getTopic(this.state.topic),n="grp"===a.getType(),s=null,o=0;o{this.props.sendMessage(Drafty.insertImage(null,0,t,e,a,n,s))},(e,t,a)=>{this.props.sendMessage(Drafty.attachFile(null,e,t,a))},this.props.onError)&&t.preventDefault()}handleAttachImage(t){if(t.target.files&&0MAX_INBAND_ATTACHMENT_SIZE||0>SUPPORTED_IMAGE_FORMATS.indexOf(e.type)?imageFileScaledToBase64(e,MAX_IMAGE_DIM,MAX_IMAGE_DIM,!1,(e,t,a,n,s)=>{this.props.sendMessage(Drafty.insertImage(null,0,t,e,a,n,s))},e=>{this.props.onError(e,"err")}):imageFileToBase64(e,(e,t,a,n,s)=>{this.props.sendMessage(Drafty.insertImage(null,0,t,e,a,n,s))},e=>{this.props.onError(e,"err")})}t.target.value=""}handleAttachFile(t){if(t.target.files&&0MAX_EXTERN_ATTACHMENT_SIZE)this.props.onError("The file size "+bytesToHumanSize(e.size)+" exceeds the "+bytesToHumanSize(MAX_EXTERN_ATTACHMENT_SIZE)+" limit.","err");else if(e.size>MAX_INBAND_ATTACHMENT_SIZE){let t=Tinode.getLargeFileHelper();if(!t)return void this.props.onError("Cannot initiate file upload.");let a=t.upload(e),n=Drafty.attachFile(null,e.type,null,e.name,e.size,a);this.props.sendMessage(n,a,t)}else fileToBase64(e,(e,t,a)=>{this.props.sendMessage(Drafty.attachFile(null,e,t,a))},this.props.onError)}t.target.value=""}handleSend(){var e=this.state.message.trim();e&&(this.props.sendMessage(this.state.message.trim()),this.setState({message:""}))}handleKeyPress(t){"Enter"!==t.key||t.shiftKey||(t.preventDefault(),t.stopPropagation(),this.handleSend())}handleMessageTyping(t){var e={message:t.target.value},a=new Date().getTime();if(a-this.state.keypressTimestamp>KEYPRESS_DELAY){var n=Tinode.getTopic(this.props.topic);n.isSubscribed()&&n.noteKeyPress(),e.keypressTimestamp=a}this.setState(e)}render(){var e=this.props.disabled?"Messaging disabled":"New message",t=this;return React.createElement("div",{id:"send-message-panel"},this.props.disabled?React.createElement("i",{className:"material-icons disabled"},"photo"):React.createElement("a",{href:"javascript:;",onClick:function(){t.attachImage.click()},title:"Add image"},React.createElement("i",{className:"material-icons secondary"},"photo")),this.props.disabled?React.createElement("i",{className:"material-icons disabled"},"attach_file"):React.createElement("a",{href:"javascript:;",onClick:function(){t.attachFile.click()},title:"Attach file"},React.createElement("i",{className:"material-icons secondary"},"attach_file")),React.createElement("textarea",{id:"sendMessage",placeholder:e,disabled:this.props.disabled,value:this.state.message,onChange:this.handleMessageTyping,onKeyPress:this.handleKeyPress,ref:function(e){t.pasteFile=e},autoFocus:!0}),this.props.disabled?React.createElement("i",{className:"material-icons disabled"},"send"):React.createElement("a",{href:"javascript:;",onClick:this.handleSend,title:"Send"},React.createElement("i",{className:"material-icons"},"send")),React.createElement("input",{type:"file",ref:function(e){t.attachFile=e},onChange:this.handleAttachFile,style:{display:"none"}}),React.createElement("input",{type:"file",ref:function(e){t.attachImage=e},accept:"image/*",onChange:this.handleAttachImage,style:{display:"none"}}))}}class LogoView extends React.PureComponent{render(){var e=Tinode.getVersion()+" build "+document.lastModified;return React.createElement("div",{id:"dummy-view",className:this.props.hideSelf?"nodisplay":null},React.createElement("div",null,React.createElement("a",{href:"https://github.com/tinode/chat/"},React.createElement("img",{id:"logo",alt:"logo",src:"img/logo.svg"}),React.createElement("h2",null,"Tinode Demo Chat")),React.createElement("p",null,"Client: ",e),React.createElement("p",null,"Server: ",this.props.serverVersion," (",this.props.serverAddress,")")))}}class ImagePreview extends React.PureComponent{constructor(e){super(e),this.state={}}componentDidMount(){this.setState({width:this.container.clientWidth,height:this.container.clientHeight})}render(){if(!this.props.content)return null;var e=this,t=fitImageSize(this.props.content.width,this.props.content.height,this.state.width,this.state.height,!1),a=t?{width:t.dstWidth+"px",height:t.dstHeight+"px"}:this.props.content.width>this.props.content.height?{width:"100%"}:{height:"100%"};a.maxWidth="100%",a.maxHeight="100%";var n=this.props.content.filename,s=0|this.props.content.width/REM_SIZE;return n.length>s&&(n=n.slice(0,s-2)+"..."+n.slice(2-s)),React.createElement("div",{id:"image-preview",onClick:this.props.onClose},React.createElement("div",{id:"image-preview-caption-panel"},React.createElement("a",{href:"javascript:;",download:this.props.content.filename},React.createElement("i",{className:"material-icons"},"file_download")," download"),React.createElement("a",{href:"javascript:;",onClick:this.props.onClose},React.createElement("i",{className:"material-icons gray"},"close"))),React.createElement("div",{id:"image-preview-container",ref:function(t){e.container=t}},React.createElement("img",{src:this.props.content.url,style:a})),React.createElement("div",{id:"image-preview-footer"},React.createElement("div",null,React.createElement("div",null,React.createElement("b",null,"File name"),":"),React.createElement("div",null,React.createElement("span",{title:this.props.content.filename},n))),React.createElement("div",null,React.createElement("div",null,React.createElement("b",null,"Content type"),":"),React.createElement("div",null,this.props.content.type)),React.createElement("div",null,React.createElement("div",null,React.createElement("b",null,"Size"),":"),React.createElement("div",null,this.props.content.width," \xD7 ",this.props.content.height," px; ",bytesToHumanSize(this.props.content.size)))))}}class TinodeWeb extends React.Component{constructor(e){super(e),this.state=this.getInitialState(),this.handleResize=this.handleResize.bind(this),this.handleHashRoute=this.handleHashRoute.bind(this),this.handleOnline=this.handleOnline.bind(this),this.handleAppVisibility=this.handleAppVisibility.bind(this),this.handleReadTimer=this.handleReadTimer.bind(this),this.handleVisibilityEvent=this.handleVisibilityEvent.bind(this),this.handleError=this.handleError.bind(this),this.handleLoginRequest=this.handleLoginRequest.bind(this),this.handleConnected=this.handleConnected.bind(this),this.doLogin=this.doLogin.bind(this),this.handleCredentialsRequest=this.handleCredentialsRequest.bind(this),this.handleLoginSuccessful=this.handleLoginSuccessful.bind(this),this.handleDisconnect=this.handleDisconnect.bind(this),this.tnMeMetaDesc=this.tnMeMetaDesc.bind(this),this.tnData=this.tnData.bind(this),this.tnInitFind=this.tnInitFind.bind(this),this.tnFndSubsUpdated=this.tnFndSubsUpdated.bind(this),this.handleSearchContacts=this.handleSearchContacts.bind(this),this.handleTopicSelected=this.handleTopicSelected.bind(this),this.handleTopicSelectedOnline=this.handleTopicSelectedOnline.bind(this),this.handleTopicSelectedAcs=this.handleTopicSelectedAcs.bind(this),this.handleHideMessagesView=this.handleHideMessagesView.bind(this),this.handleSendMessage=this.handleSendMessage.bind(this),this.handleNewAccount=this.handleNewAccount.bind(this),this.handleNewAccountRequest=this.handleNewAccountRequest.bind(this),this.handleUpdateAccountRequest=this.handleUpdateAccountRequest.bind(this),this.handleUpdateAccountTagsRequest=this.handleUpdateAccountTagsRequest.bind(this),this.handleSettings=this.handleSettings.bind(this),this.handleConnectionSettings=this.handleConnectionSettings.bind(this),this.handleSidepanelCancel=this.handleSidepanelCancel.bind(this),this.handleNewTopic=this.handleNewTopic.bind(this),this.handleNewTopicRequest=this.handleNewTopicRequest.bind(this),this.handleTopicUpdateRequest=this.handleTopicUpdateRequest.bind(this),this.handleChangePermissions=this.handleChangePermissions.bind(this),this.handleTagsUpdated=this.handleTagsUpdated.bind(this),this.handleLogout=this.handleLogout.bind(this),this.handleLeaveUnsubRequest=this.handleLeaveUnsubRequest.bind(this),this.handleDialogCancel=this.handleDialogCancel.bind(this),this.handleShowContextMenu=this.handleShowContextMenu.bind(this),this.defaultTopicContextMenu=this.defaultTopicContextMenu.bind(this),this.handleHideContextMenu=this.handleHideContextMenu.bind(this),this.handleShowInfoView=this.handleShowInfoView.bind(this),this.handleHideInfoView=this.handleHideInfoView.bind(this),this.handleMemberUpdateRequest=this.handleMemberUpdateRequest.bind(this),this.handleValidateCredentialsRequest=this.handleValidateCredentialsRequest.bind(this)}getInitialState(){return{connected:!1,transport:null,serverAddress:detectServerAddress(),sidePanelSelected:"login",sidePanelTitle:null,sidePanelAvatar:null,dialogSelected:null,contextMenuVisible:!1,login:"",password:"",myUserId:null,errorText:"",errorLevel:null,liveConnection:navigator.onLine,topicSelected:"",topicSelectedOnline:!1,topicSelectedAcs:null,loginDisabled:!1,displayMobile:window.innerWidth<=MEDIA_BREAKPOINT,showInfoPanel:!1,mobilePanel:"sidepanel",contextMenuVisible:!1,contextMenuBounds:null,contextMenuClickAt:null,contextMenuParams:null,contextMenuItems:[],serverVersion:"no connection",contactsSearchQuery:"",foundContacts:[],credMethod:""}}componentDidMount(){var e=this;window.addEventListener("resize",this.handleResize),window.addEventListener("online",function(){e.handleOnline(!0)}),window.addEventListener("offline",function(){e.handleOnline(!1)}),window.addEventListener("hashchange",this.handleHashRoute),document.addEventListener("visibilitychange",this.handleVisibilityEvent),this.setState({viewportWidth:document.documentElement.clientWidth}),Tinode.enableLogging(!0,!0),Tinode.onConnect=this.handleConnected,Tinode.onDisconnect=this.handleDisconnect,TinodeWeb.tnSetup(this.state.serverAddress,this.state.transport);var t;if(localStorage.getObject("keep-logged-in")&&(t=localStorage.getObject("auth-token")),t){t.expires=new Date(t.expires),Tinode.setAuthToken(t),Tinode.connect().catch(function(t){e.handleError(t.message,"err")});var a=parseUrlHash(window.location.hash);delete a.params.info,delete a.params.tab,a.path[0]="",window.location.hash=composeUrlHash(a.path,a.params)}else window.location.hash="";this.readTimer=null,this.readTimerCallback=null}componentWillUnmount(){window.removeEventListener("resize",this.handleResize),window.removeEventListener("hashchange",this.handleHashRoute),document.removeEventListener("visibilitychange",this.handleVisibilityEvent)}static tnSetup(e,t){Tinode.setup(APP_NAME,e,API_KEY,t)}handleResize(){var e=document.documentElement.clientWidth<=MEDIA_BREAKPOINT;this.setState({viewportWidth:document.documentElement.clientWidth}),this.state.displayMobile!=e&&this.setState({displayMobile:e})}handleHashRoute(){var e=parseUrlHash(window.location.hash);if(e.path&&0{300<=e.code&&"validate credentials"===e.text?o.handleCredentialsRequest(e.params):o.handleLoginSuccessful(o)}).catch(e=>{o.setState({loginDisabled:!1}),o.handleError(e.message,"err"),localStorage.removeItem("auth-token"),window.location.hash=""})}handleCredentialsRequest(e){var t=parseUrlHash(window.location.hash);t.path[0]="cred",t.params.method=e.cred[0],window.location.hash=composeUrlHash(t.path,t.params)}handleLoginSuccessful(e){e.handleError("",null),localStorage.getObject("keep-logged-in")&&localStorage.setObject("auth-token",Tinode.getAuthToken());var t=Tinode.getMeTopic();t.onMetaDesc=e.tnMeMetaDesc,e.setState({connected:!0,myUserId:Tinode.getCurrentUserID()}),t.subscribe(t.startMetaQuery().withLaterSub().withDesc().build()).catch(function(t){localStorage.removeItem("auth-token"),e.handleError(t.message,"err"),window.location.hash=""}),window.location.hash=setUrlSidePanel(window.location.hash,"contacts")}handleDisconnect(e){this.setState({connected:!1,topicSelectedOnline:!1,dialogSelected:null,errorText:e&&e.message?e.message:"Disconnected",errorLevel:e&&e.message?"err":"warn",loginDisabled:!1,contextMenuVisible:!1,serverVersion:"no connection"})}tnMeMetaDesc(e){e&&e.public&&this.setState({sidePanelTitle:e.public.fn,sidePanelAvatar:makeImageUrl(e.public.photo)})}tnData(e){let t=Tinode.getTopic(e.topic);t.msgStatus(e)>Tinode.MESSAGE_STATUS_SENDING&&(clearTimeout(this.receivedTimer),this.receivedTimer=setTimeout(()=>{this.receivedTimer=void 0,t.noteRecv(e.seq)},RECEIVED_DELAY))}tnInitFind(){var e=Tinode.getFndTopic();if(e.isSubscribed())this.setState({contactsSearchQuery:""}),this.tnFndSubsUpdated();else{e.onSubsUpdated=this.tnFndSubsUpdated;var t=this;e.subscribe(e.startMetaQuery().withSub().withTags().build()).catch(function(e){t.handleError(e.message,"err")})}}tnFndSubsUpdated(){var e=[];Tinode.getFndTopic().contacts(function(t){e.push(t)}),this.setState({foundContacts:e})}handleSearchContacts(e){var t=Tinode.getFndTopic(),a=this;t.setMeta({desc:{public:e}}).then(function(){return t.getMeta(t.startMetaQuery().withSub().build())}).catch(function(e){a.handleError(e.message,"err")})}handleTopicSelected(e,t,a,n){e?(this.state.topicSelected!=e&&(window.location.hash=setUrlTopic(window.location.hash,e)),this.setState({errorText:"",errorLevel:null,mobilePanel:"topic-view",topicSelectedOnline:a,topicSelectedAcs:n,showInfoPanel:!1})):(this.state.topicSelected&&(window.location.hash=setUrlTopic(window.location.hash,null)),this.setState({errorText:"",errorLevel:null,mobilePanel:"sidepanel",topicSelectedOnline:!1,topicSelectedAcs:null,showInfoPanel:!1}))}handleTopicSelectedOnline(e){"boolean"==typeof e&&this.setState({topicSelectedOnline:e})}handleTopicSelectedAcs(e){this.setState({topicSelectedAcs:e})}handleHideMessagesView(){this.setState({mobilePanel:"sidepanel"}),window.location.hash=setUrlTopic(window.location.hash,null)}handleSendMessage(e,t,a){let n=Tinode.getTopic(this.state.topicSelected),s=Drafty.parse(e);s&&!Drafty.isPlainText(s)&&(e=s),e=n.createMessage(e),e._uploader=a,t&&t.catch(e=>{this.handleError(e.message,"err")}),n.isSubscribed()||(!t&&(t=Promise.resolve()),t=t.then(()=>n.subscribe())),n.publishDraft(e,t).catch(e=>{this.handleError(e.message,"err")})}handleNewAccount(){window.location.hash=setUrlSidePanel(window.location.hash,"register")}handleNewAccountRequest(e,t,a,n,s){var o=this;Tinode.connect(this.state.serverAddress).then(function(){var o=Tinode.addCredential({public:a,tags:s},n);return Tinode.createAccountBasic(e,t,o)}).then(function(e){300<=e.code&&"validate credentials"===e.text?o.handleCredentialsRequest(e.params):o.handleLoginSuccessful(o)}).catch(function(e){o.handleError(e.message,"err")})}handleUpdateAccountRequest(e,t,a){var n=this;(t||a)&&Tinode.getMeTopic().setMeta({desc:{public:t,private:a}}).catch(function(e){n.handleError(e.message,"err")}),e&&Tinode.updateAccountBasic(null,Tinode.getCurrentLogin(),e).catch(function(e){n.handleError(e.message,"err")})}handleUpdateAccountTagsRequest(e){var t=this;Tinode.getFndTopic().setMeta({tags:e}).catch(function(e){t.handleError(e.message,"err")})}handleSettings(){window.location.hash=setUrlSidePanel(window.location.hash,this.state.myUserId?"edit":"settings")}handleConnectionSettings(e,t){t=t||this.state.transport,e=e||this.state.serverAddress,this.setState({serverAddress:e,transport:t,sidePanelSelected:"login"}),TinodeWeb.tnSetup(e,t)}handleSidepanelCancel(){var e=parseUrlHash(window.location.hash);e.path[0]=this.state.myUserId?"contacts":"",e.params&&(delete e.params.code,delete e.params.method,delete e.params.tab),window.location.hash=composeUrlHash(e.path,e.params),this.setState({errorText:"",errorLevel:null})}handleNewTopic(){window.location.hash=setUrlSidePanel(window.location.hash,"newtpk")}handleNewTopicRequest(e,t,a,n){var s,o=this,r=e?Tinode.newTopicWith(e):Tinode.newTopic(),i=r.startMetaQuery().withDesc().withSub().withData();e||(i=i.withTags(),s={desc:{public:t,private:a},tags:n}),r.subscribe(i.build(),s).then(function(){window.location.hash=setUrlSidePanel(window.location.hash,"contacts"),o.handleTopicSelected(r.name,void 0,Tinode.isTopicOnline(r.name),r.getAccessMode())}).catch(function(e){o.handleError(e.message,"err")})}handleTopicUpdateRequest(e,t,a,n){var s=this,o=Tinode.getTopic(e);if(o){var r={};t&&(r.public=t),a&&(r.private={comment:a}),n&&(r.defacs=n),o.setMeta({desc:r}).catch(function(e){s.handleError(e.message,"err")})}}handleChangePermissions(e,t,a){var n=this,s=Tinode.getTopic(e);if(s){var o=s.getAccessMode();a?(o.updateGiven(t),t=o.getGiven()):(o.updateWant(t),t=o.getWant()),s.setMeta({sub:{user:a,mode:t}}).catch(function(e){n.handleError(e.message,"err")})}}handleTagsUpdated(e,t){var a=Tinode.getTopic(e);if(a){var n=this;a.setMeta({tags:t}).catch(function(e){n.handleError(e.message,"err")})}}handleLogout(){localStorage.removeItem("auth-token"),this.setState(this.getInitialState()),TinodeWeb.tnSetup(this.state.serverAddress,this.state.transport),window.location.hash=""}handleLeaveUnsubRequest(e){var t=Tinode.getTopic(e);t&&t.leave(!0).then(()=>{window.location.hash=setUrlTopic(window.location.hash,"")}).catch(e=>{this.handleError(e.message,"err")})}handleDialogCancel(){this.setState({dialogSelected:null})}handleShowContextMenu(e,t){this.setState({contextMenuVisible:!0,contextMenuClickAt:{x:e.x,y:e.y},contextMenuParams:e,contextMenuItems:t||this.defaultTopicContextMenu(e.topicName),contextMenuBounds:ReactDOM.findDOMNode(this).getBoundingClientRect()})}defaultTopicContextMenu(e){var t=!1,a=!1,n=!1,s=!1,o=Tinode.getTopic(e);if(o&&o.isSubscribed()){n=!0;var r=o.getAccessMode();t=r&&r.isMuted(),a=r&&!r.isJoiner(),s=r&&r.isDeleter()}return[n?{title:"Info",handler:this.handleShowInfoView}:null,n?ContextMenuItems.messages_clear:null,n&&s?ContextMenuItems.messages_clear_hard:null,n?t?ContextMenuItems.topic_unmute:ContextMenuItems.topic_mute:null,n?a?ContextMenuItems.topic_unblock:ContextMenuItems.topic_block:null,ContextMenuItems.topic_delete]}handleHideContextMenu(){this.setState({contextMenuVisible:!1,contextMenuClickAt:null,contextMenuParams:null,contextMenuBounds:null})}handleShowInfoView(){window.location.hash=addUrlParam(window.location.hash,"info",!0),this.setState({showInfoPanel:!0})}handleHideInfoView(){window.location.hash=removeUrlParam(window.location.hash,"info"),this.setState({showInfoPanel:!1})}handleMemberUpdateRequest(e,t,a){if(e){var n=Tinode.getTopic(e);if(n){var s=this;t&&0