refactoring upload progress
This commit is contained in:
@@ -240,6 +240,7 @@ function fileToBase64(file, onSuccess, onError) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// File pasted from the clipboard. It's either an inline image or a file attachment.
|
// File pasted from the clipboard. It's either an inline image or a file attachment.
|
||||||
|
// FIXME: handle large files out of band.
|
||||||
function filePasted(event, onImageSuccess, onAttachmentSuccess, onError) {
|
function filePasted(event, onImageSuccess, onAttachmentSuccess, onError) {
|
||||||
var items = (event.clipboardData || event.originalEvent.clipboardData || {}).items;
|
var items = (event.clipboardData || event.originalEvent.clipboardData || {}).items;
|
||||||
for (var i in items) {
|
for (var i in items) {
|
||||||
@@ -963,14 +964,10 @@ class ChipInput extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
// FIXME: these two methods should be static.
|
|
||||||
this.indexChips = this.indexChips.bind(this);
|
|
||||||
this.sortChips = this.sortChips.bind(this);
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
placeholder: props.chips ? "" : props.prompt,
|
placeholder: props.chips ? "" : props.prompt,
|
||||||
sortedChips: this.sortChips(props.chips, props.required),
|
sortedChips: ChipInput.sortChips(props.chips, props.required),
|
||||||
chipIndex: this.indexChips(props.chips),
|
chipIndex: ChipInput.indexChips(props.chips),
|
||||||
input: '',
|
input: '',
|
||||||
focused: false
|
focused: false
|
||||||
};
|
};
|
||||||
@@ -985,8 +982,8 @@ class ChipInput extends React.Component {
|
|||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
this.setState({
|
this.setState({
|
||||||
sortedChips: this.sortChips(nextProps.chips, nextProps.required),
|
sortedChips: ChipInput.sortChips(nextProps.chips, nextProps.required),
|
||||||
chipIndex: this.indexChips(nextProps.chips)
|
chipIndex: ChipInput.indexChips(nextProps.chips)
|
||||||
});
|
});
|
||||||
if (nextProps.chips.length > this.props.chips.length) {
|
if (nextProps.chips.length > this.props.chips.length) {
|
||||||
// Chip added: clear input.
|
// Chip added: clear input.
|
||||||
@@ -995,8 +992,7 @@ class ChipInput extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Map chip index to user name
|
// Map chip index to user name
|
||||||
// FIXME: convert to static method.
|
static indexChips(chips) {
|
||||||
indexChips(chips) {
|
|
||||||
var index = {};
|
var index = {};
|
||||||
var count = 0;
|
var count = 0;
|
||||||
chips.map(function(item) {
|
chips.map(function(item) {
|
||||||
@@ -1007,8 +1003,7 @@ class ChipInput extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Have non-removable chips appear before all other chips.
|
// Have non-removable chips appear before all other chips.
|
||||||
// FIXME: convert to static method.
|
static sortChips(chips, keep) {
|
||||||
sortChips(chips, keep) {
|
|
||||||
var required = [];
|
var required = [];
|
||||||
var normal = [];
|
var normal = [];
|
||||||
chips.map(function(item) {
|
chips.map(function(item) {
|
||||||
@@ -2043,7 +2038,7 @@ class UnreadBadge extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Contact's labels: [you], [muted], [blocked], etc */
|
/* Contact's labels: [you], [muted], [blocked], etc */
|
||||||
// FIXME: this class is unused
|
// FIXME: this class is unused.
|
||||||
class ContactBadges_UNUSED_REMOVE extends React.Component {
|
class ContactBadges_UNUSED_REMOVE extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
var badges = null;
|
var badges = null;
|
||||||
@@ -2065,7 +2060,6 @@ class ContactsView extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
// FIXME: make static
|
|
||||||
this.prepareContactList = this.prepareContactList.bind(this);
|
this.prepareContactList = this.prepareContactList.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -2153,7 +2147,6 @@ class ContactsView extends React.Component {
|
|||||||
this.resetContactList();
|
this.resetContactList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: make this method static.
|
|
||||||
prepareContactList() {
|
prepareContactList() {
|
||||||
var instance = this;
|
var instance = this;
|
||||||
var contacts = [];
|
var contacts = [];
|
||||||
@@ -2283,10 +2276,10 @@ class GroupManager extends React.Component {
|
|||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
members: props.members,
|
members: props.members,
|
||||||
index: this.indexMembers(props.members),
|
index: GroupManager.indexMembers(props.members),
|
||||||
contactFilter: '',
|
contactFilter: '',
|
||||||
noContactsMessage: 'You have no contacts :-(',
|
noContactsMessage: 'You have no contacts :-(',
|
||||||
selectedContacts: this.selectedContacts(props.members)
|
selectedContacts: GroupManager.selectedContacts(props.members)
|
||||||
};
|
};
|
||||||
|
|
||||||
this.handleContactSelected = this.handleContactSelected.bind(this);
|
this.handleContactSelected = this.handleContactSelected.bind(this);
|
||||||
@@ -2296,8 +2289,7 @@ class GroupManager extends React.Component {
|
|||||||
this.handleCancel = this.handleCancel.bind(this);
|
this.handleCancel = this.handleCancel.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: make method static
|
static indexMembers(members) {
|
||||||
indexMembers(members) {
|
|
||||||
var index = {};
|
var index = {};
|
||||||
members.map(function(m) {
|
members.map(function(m) {
|
||||||
index[m.user] = {delta: 0, present: true}; // Delta: 0 unchanged, +1 added, -1 removed
|
index[m.user] = {delta: 0, present: true}; // Delta: 0 unchanged, +1 added, -1 removed
|
||||||
@@ -2305,8 +2297,7 @@ class GroupManager extends React.Component {
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: make method static
|
static selectedContacts(members) {
|
||||||
selectedContacts(members) {
|
|
||||||
var sel = [];
|
var sel = [];
|
||||||
members.map(function(m) {
|
members.map(function(m) {
|
||||||
sel.push(m.user);
|
sel.push(m.user);
|
||||||
@@ -2365,8 +2356,7 @@ class GroupManager extends React.Component {
|
|||||||
this.setState({contactFilter: val, noContactsMessage: msg});
|
this.setState({contactFilter: val, noContactsMessage: msg});
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: make static
|
static doContactFiltering(filter, values) {
|
||||||
doContactFiltering(filter, values) {
|
|
||||||
if (filter) {
|
if (filter) {
|
||||||
for (var i=0; i<values.length; i++) {
|
for (var i=0; i<values.length; i++) {
|
||||||
if (values[i].indexOf(filter) >= 0) {
|
if (values[i].indexOf(filter) >= 0) {
|
||||||
@@ -2424,7 +2414,7 @@ class GroupManager extends React.Component {
|
|||||||
contacts={this.props.contacts}
|
contacts={this.props.contacts}
|
||||||
topicSelected={this.state.selectedContacts}
|
topicSelected={this.state.selectedContacts}
|
||||||
filter={this.state.contactFilter}
|
filter={this.state.contactFilter}
|
||||||
filterFunc={this.doContactFiltering}
|
filterFunc={GroupManager.doContactFiltering}
|
||||||
emptyListMessage={this.state.noContactsMessage}
|
emptyListMessage={this.state.noContactsMessage}
|
||||||
showOnline={false}
|
showOnline={false}
|
||||||
showUnread={false}
|
showUnread={false}
|
||||||
@@ -3384,12 +3374,16 @@ class ChatMessage extends React.Component {
|
|||||||
|
|
||||||
var content = this.props.content;
|
var content = this.props.content;
|
||||||
var attachments = [];
|
var attachments = [];
|
||||||
if (this.props.mimeType === Drafty.getContentType()) {
|
if (this.props.mimeType == Drafty.getContentType()) {
|
||||||
Drafty.attachments(content, function(att, i) {
|
Drafty.attachments(content, function(att, i) {
|
||||||
attachments.push(<AttachmentProgress
|
attachments.push(<Attachment
|
||||||
filename={att.name} downloadUrl={Drafty.getDownloadUrl(att)}
|
downloadUrl={Drafty.getDownloadUrl(att)}
|
||||||
|
filename={att.name} uploader={Drafty.isUploading(att)}
|
||||||
mimetype={att.mime} size={Drafty.getEntitySize(att)}
|
mimetype={att.mime} size={Drafty.getEntitySize(att)}
|
||||||
onError={this.props.onError} key={i} />);
|
progress={this.props.progress}
|
||||||
|
onCancelUpload={this.props.onCancelUpload}
|
||||||
|
onError={this.props.onError}
|
||||||
|
key={i} />);
|
||||||
}, this);
|
}, this);
|
||||||
content = React.createElement('span', null, Drafty.format(content, formatter, this));
|
content = React.createElement('span', null, Drafty.format(content, formatter, this));
|
||||||
}
|
}
|
||||||
@@ -3408,8 +3402,10 @@ class ChatMessage extends React.Component {
|
|||||||
<div className={bubbleClass}>
|
<div className={bubbleClass}>
|
||||||
<p>{content}
|
<p>{content}
|
||||||
{attachments}
|
{attachments}
|
||||||
<ReceivedMarker response={this.props.response}
|
<ReceivedMarker
|
||||||
timestamp={this.props.timestamp} received={this.props.received} />
|
response={this.props.response}
|
||||||
|
timestamp={this.props.timestamp}
|
||||||
|
received={this.props.received} />
|
||||||
</p>
|
</p>
|
||||||
<span className="menuTrigger">
|
<span className="menuTrigger">
|
||||||
<a href="javascript:;" onClick={this.handleContextClick}>
|
<a href="javascript:;" onClick={this.handleContextClick}>
|
||||||
@@ -3430,7 +3426,7 @@ class MessageUploader extends React.PureComponent {
|
|||||||
var bubbleClass = "bubble tip";
|
var bubbleClass = "bubble tip";
|
||||||
|
|
||||||
var attachments = [
|
var attachments = [
|
||||||
<AttachmentProgress
|
<Attachment
|
||||||
uploader={true} filename={this.props.filename} size={this.props.size}
|
uploader={true} filename={this.props.filename} size={this.props.size}
|
||||||
progress={this.props.progress}
|
progress={this.props.progress}
|
||||||
onCancelUpload={this.props.onCancelUpload}
|
onCancelUpload={this.props.onCancelUpload}
|
||||||
@@ -3442,8 +3438,10 @@ class MessageUploader extends React.PureComponent {
|
|||||||
<div>
|
<div>
|
||||||
<div className="bubble tip">
|
<div className="bubble tip">
|
||||||
<p>{attachments}
|
<p>{attachments}
|
||||||
<ReceivedMarker response={this.props.response}
|
<ReceivedMarker
|
||||||
timestamp={this.props.timestamp} received={this.props.received} />
|
response={this.props.response}
|
||||||
|
timestamp={this.props.timestamp}
|
||||||
|
received={this.props.received} />
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -3479,7 +3477,7 @@ class ReceivedMarker extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class AttachmentProgress extends React.Component {
|
class Attachment extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
@@ -3517,25 +3515,24 @@ class AttachmentProgress extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var filename = this.props.filename || "file_attachment";
|
let filename = this.props.filename || "file_attachment";
|
||||||
if (filename.length > 36) {
|
if (filename.length > 36) {
|
||||||
filename = filename.substr(0, 16) + "..." + filename.substr(-16);
|
filename = filename.substr(0, 16) + "..." + filename.substr(-16);
|
||||||
}
|
}
|
||||||
var size = this.props.size > 0 ?
|
let size = this.props.size > 0 ?
|
||||||
<span className="small gray">({bytesToHumanSize(this.props.size)})</span> :
|
<span className="small gray">({bytesToHumanSize(this.props.size)})</span> :
|
||||||
null;
|
null;
|
||||||
|
|
||||||
// Detect if the download URL is relative or absolute.
|
// Detect if the download URL is relative or absolute.
|
||||||
// If the URL is relative use LargeFileHelper to attach authentication
|
// If the URL is relative use LargeFileHelper to attach authentication
|
||||||
// credentials to the request.
|
// credentials to the request.
|
||||||
var url, helperFunc;
|
let url, helperFunc;
|
||||||
if (!this.props.uploader && !this.state.downloader &&
|
if (!this.props.uploader && !this.state.downloader &&
|
||||||
!(/^(?:(?:[a-z]+:)?\/\/)/i.test(this.props.downloadUrl))) {
|
!(/^(?:(?:[a-z]+:)?\/\/)/i.test(this.props.downloadUrl))) {
|
||||||
// Relative URL. Use download helper.
|
// Relative URL. Use download helper.
|
||||||
url = "javascript:;";
|
url = "javascript:;";
|
||||||
var instance = this;
|
helperFunc = (e) => {
|
||||||
helperFunc = function(e) {
|
this.downloadFile(this.props.downloadUrl, this.props.filename, this.props.mimetype);
|
||||||
instance.downloadFile(instance.props.downloadUrl, instance.props.filename, instance.props.mimetype);
|
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
url = this.props.downloadUrl;
|
url = this.props.downloadUrl;
|
||||||
@@ -3591,8 +3588,6 @@ class MessagesView extends React.Component {
|
|||||||
this.handleContextClick = this.handleContextClick.bind(this);
|
this.handleContextClick = this.handleContextClick.bind(this);
|
||||||
this.handleShowContextMenuMessage = this.handleShowContextMenuMessage.bind(this);
|
this.handleShowContextMenuMessage = this.handleShowContextMenuMessage.bind(this);
|
||||||
this.handleBackNavigation = this.handleBackNavigation.bind(this);
|
this.handleBackNavigation = this.handleBackNavigation.bind(this);
|
||||||
this.handleUploadProgress = this.handleUploadProgress.bind(this);
|
|
||||||
this.handleCancelUpload = this.handleCancelUpload.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scroll last message into view on component update e.g. on message received.
|
// Scroll last message into view on component update e.g. on message received.
|
||||||
@@ -3865,17 +3860,6 @@ class MessagesView extends React.Component {
|
|||||||
this.props.onHideMessagesView();
|
this.props.onHideMessagesView();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleUploadProgress(progress) {
|
|
||||||
this.setState({uploadProgress: progress});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCancelUpload() {
|
|
||||||
if (this.state.uploadFile && this.state.uploadFile.uploader) {
|
|
||||||
this.state.uploadFile.uploader.cancel();
|
|
||||||
}
|
|
||||||
this.setState({uploadFile: null});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var component = null;
|
var component = null;
|
||||||
if (this.state.topic) {
|
if (this.state.topic) {
|
||||||
@@ -3999,7 +3983,6 @@ class MessagesView extends React.Component {
|
|||||||
topic={this.props.topic}
|
topic={this.props.topic}
|
||||||
disabled={this.state.readOnly}
|
disabled={this.state.readOnly}
|
||||||
sendMessage={this.props.sendMessage}
|
sendMessage={this.props.sendMessage}
|
||||||
onUploadProgress={this.handleUploadProgress}
|
|
||||||
onError={this.props.onError} />
|
onError={this.props.onError} />
|
||||||
{this.state.imagePreview ?
|
{this.state.imagePreview ?
|
||||||
<ImagePreview content={this.state.imagePreview}
|
<ImagePreview content={this.state.imagePreview}
|
||||||
@@ -4048,52 +4031,51 @@ class SendMessage extends React.PureComponent {
|
|||||||
if (this.props.disabled) {
|
if (this.props.disabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var instance = this;
|
// FIXME: handle large files too.
|
||||||
if (filePasted(e,
|
if (filePasted(e,
|
||||||
function(bits, mime, width, height, fname) {
|
(bits, mime, width, height, fname) => {
|
||||||
instance.props.sendMessage(Drafty.insertImage(null,
|
this.props.sendMessage(Drafty.insertImage(null,
|
||||||
0, mime, bits, width, height, fname));
|
0, mime, bits, width, height, fname));
|
||||||
},
|
},
|
||||||
function(mime, bits, fname) {
|
(mime, bits, fname) => {
|
||||||
instance.props.sendMessage(Drafty.attachFile(null, mime, bits, fname));
|
this.props.sendMessage(Drafty.attachFile(null, mime, bits, fname));
|
||||||
},
|
},
|
||||||
instance.props.onError)) {
|
this.props.onError)) {
|
||||||
|
|
||||||
// If file was pasted, don't paste base64 daata into input field.
|
// If a file was pasted, don't paste base64 data into input field.
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleAttachImage(e) {
|
handleAttachImage(e) {
|
||||||
if (e.target.files && e.target.files.length > 0) {
|
if (e.target.files && e.target.files.length > 0) {
|
||||||
var instance = this;
|
let file = e.target.files[0];
|
||||||
var file = e.target.files[0];
|
|
||||||
// Check if the uploaded file is indeed an image and if it isn't too large.
|
// 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) {
|
if (file.size > MAX_INBAND_ATTACHMENT_SIZE || SUPPORTED_IMAGE_FORMATS.indexOf(file.type) < 0) {
|
||||||
// Convert image for size or format.
|
// Convert image for size or format.
|
||||||
imageFileScaledToBase64(file, MAX_IMAGE_SIZE, MAX_IMAGE_SIZE, false,
|
imageFileScaledToBase64(file, MAX_IMAGE_SIZE, MAX_IMAGE_SIZE, false,
|
||||||
// Success
|
// Success
|
||||||
function(bits, mime, width, height, fname) {
|
(bits, mime, width, height, fname) => {
|
||||||
instance.props.sendMessage(Drafty.insertImage(null,
|
this.props.sendMessage(Drafty.insertImage(null,
|
||||||
0, mime, bits, width, height, fname));
|
0, mime, bits, width, height, fname));
|
||||||
},
|
},
|
||||||
// Failure
|
// Failure
|
||||||
function(err) {
|
(err) => {
|
||||||
instance.props.onError(err, "err");
|
this.props.onError(err, "err");
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log("File size is OK", file.size, MAX_INBAND_ATTACHMENT_SIZE);
|
|
||||||
// Image can be uploaded as is. No conversion is needed.
|
// Image can be uploaded as is. No conversion is needed.
|
||||||
imageFileToBase64(file,
|
imageFileToBase64(file,
|
||||||
// Success
|
// Success
|
||||||
function(bits, mime, width, height, fname) {
|
(bits, mime, width, height, fname) => {
|
||||||
instance.props.sendMessage(Drafty.insertImage(null,
|
this.props.sendMessage(Drafty.insertImage(null,
|
||||||
0, mime, bits, width, height, fname));
|
0, mime, bits, width, height, fname));
|
||||||
},
|
},
|
||||||
// Failure
|
// Failure
|
||||||
function(err) {
|
(err) => {
|
||||||
instance.props.onError(err, "err");
|
this.props.onError(err, "err");
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Clear the value so the same file can be uploaded again.
|
// Clear the value so the same file can be uploaded again.
|
||||||
@@ -4102,32 +4084,31 @@ class SendMessage extends React.PureComponent {
|
|||||||
|
|
||||||
handleAttachFile(e) {
|
handleAttachFile(e) {
|
||||||
if (e.target.files && e.target.files.length > 0) {
|
if (e.target.files && e.target.files.length > 0) {
|
||||||
var instance = this;
|
|
||||||
var file = e.target.files[0];
|
var file = e.target.files[0];
|
||||||
if (file.size > MAX_EXTERN_ATTACHMENT_SIZE) {
|
if (file.size > MAX_EXTERN_ATTACHMENT_SIZE) {
|
||||||
// Too large.
|
// Too large.
|
||||||
this.props.onError("The file size " + bytesToHumanSize(file.size) +
|
this.props.onError("The file size " + bytesToHumanSize(file.size) +
|
||||||
" exceeds the " + bytesToHumanSize(MAX_EXTERN_ATTACHMENT_SIZE) + " limit.", "err");
|
" exceeds the " + bytesToHumanSize(MAX_EXTERN_ATTACHMENT_SIZE) + " limit.", "err");
|
||||||
} else if (file.size > MAX_INBAND_ATTACHMENT_SIZE) {
|
} else if (file.size > MAX_INBAND_ATTACHMENT_SIZE) {
|
||||||
// To large to send inband - uploading out of band and sending as a link.
|
// Too large to send inband - uploading out of band and sending as a link.
|
||||||
var uploader = Tinode.getLargeFileHelper();
|
let uploader = Tinode.getLargeFileHelper();
|
||||||
if (!uploader) {
|
if (!uploader) {
|
||||||
this.props.onError("Cannot initiate file upload.");
|
this.props.onError("Cannot initiate file upload.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.props.sendMessage(
|
// Format data and initiate upload.
|
||||||
Drafty.attachFile(null, file.type, null, file.name, ctrl.params.url, file.size),
|
let uploadCompletionPromise = uploader.upload(file);
|
||||||
uploader.upload(file, function(progress) {
|
let msg = Drafty.attachFile(null, file.type, null, file.name, file.size, uploadCompletionPromise);
|
||||||
instance.props.onUploadProgress(progress);
|
// Pass data and the uploader to the AppView.
|
||||||
})
|
this.props.sendMessage(msg, uploadCompletionPromise, uploader);
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// Small enough to send inband.
|
// Small enough to send inband.
|
||||||
fileToBase64(file,
|
fileToBase64(file,
|
||||||
function(mime, bits, fname) {
|
(mime, bits, fname) => {
|
||||||
instance.props.sendMessage(Drafty.attachFile(null, mime, bits, fname));
|
this.props.sendMessage(Drafty.attachFile(null, mime, bits, fname));
|
||||||
},
|
},
|
||||||
this.props.onError);
|
this.props.onError
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Clear the value so the same file can be uploaded again.
|
// Clear the value so the same file can be uploaded again.
|
||||||
@@ -4380,7 +4361,7 @@ class AppView extends React.Component {
|
|||||||
Tinode.enableLogging(true, true);
|
Tinode.enableLogging(true, true);
|
||||||
Tinode.onConnect = this.handleConnected;
|
Tinode.onConnect = this.handleConnected;
|
||||||
Tinode.onDisconnect = this.handleDisconnect;
|
Tinode.onDisconnect = this.handleDisconnect;
|
||||||
this.tnSetup(this.state.serverAddress, this.state.transport);
|
AppView.tnSetup(this.state.serverAddress, this.state.transport);
|
||||||
var token;
|
var token;
|
||||||
if (localStorage.getObject("keep-logged-in")) {
|
if (localStorage.getObject("keep-logged-in")) {
|
||||||
token = localStorage.getObject("auth-token");
|
token = localStorage.getObject("auth-token");
|
||||||
@@ -4412,8 +4393,7 @@ class AppView extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup transport (usually websocket) and server address. This will terminate connection with the server.
|
// Setup transport (usually websocket) and server address. This will terminate connection with the server.
|
||||||
// FIXME: make static
|
static tnSetup(serverAddress, transport) {
|
||||||
tnSetup(serverAddress, transport) {
|
|
||||||
Tinode.setup(APP_NAME, serverAddress, API_KEY, transport);
|
Tinode.setup(APP_NAME, serverAddress, API_KEY, transport);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4713,35 +4693,15 @@ class AppView extends React.Component {
|
|||||||
window.location.hash = setUrlTopic(window.location.hash, null);
|
window.location.hash = setUrlTopic(window.location.hash, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// User clicked on a message send button.
|
// User is sending a message, either plain text or a drafty object with attachments.
|
||||||
handleSendMessage(msg, promise) {
|
handleSendMessage(msg, promise, uploader) {
|
||||||
var topic = Tinode.getTopic(this.state.topicSelected);
|
let topic = Tinode.getTopic(this.state.topicSelected);
|
||||||
var instance = this;
|
msg = topic.createMessage(Drafty.parse(msg) || msg);
|
||||||
// Check if the message is formatted.
|
|
||||||
var dft = Drafty.parse(msg) || msg;
|
topic.publishDraft(msg, promise)
|
||||||
if (Drafty.isPlainText(dft)) {
|
.catch((err) => {
|
||||||
// The message is unformatted text. Send if as text/plain.
|
this.handleError(err.message, "err");
|
||||||
topic.publishDraft(topic.createMessage(msg), promise)
|
});
|
||||||
.catch(function(err) {
|
|
||||||
instance.handleError(err.message, "err");
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// The message is a Drafty object.
|
|
||||||
var attachments = [];
|
|
||||||
Drafty.attachments(dft, function(data) {
|
|
||||||
if (data.ref) {
|
|
||||||
attachments.push(data.ref);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (attachments.length < 1) {
|
|
||||||
attachments = null;
|
|
||||||
}
|
|
||||||
// Formatted message. Send it as a Drafty object.
|
|
||||||
topic.publishDraft(topic.createMessage(dft, undefined, Drafty.getContentType(), attachments), promise)
|
|
||||||
.catch(function(err) {
|
|
||||||
instance.handleError(err.message, "err");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// User chose a Sign Up menu item.
|
// User chose a Sign Up menu item.
|
||||||
@@ -4799,7 +4759,7 @@ class AppView extends React.Component {
|
|||||||
transport = transport || this.state.transport;
|
transport = transport || this.state.transport;
|
||||||
serverAddress = serverAddress || this.state.serverAddress;
|
serverAddress = serverAddress || this.state.serverAddress;
|
||||||
this.setState({serverAddress: serverAddress, transport: transport, sidePanelSelected: 'login'});
|
this.setState({serverAddress: serverAddress, transport: transport, sidePanelSelected: 'login'});
|
||||||
this.tnSetup(serverAddress, transport);
|
AppView.tnSetup(serverAddress, transport);
|
||||||
}
|
}
|
||||||
|
|
||||||
// User clicked Cancel button in Setting or Sign Up panel.
|
// User clicked Cancel button in Setting or Sign Up panel.
|
||||||
@@ -4889,7 +4849,7 @@ class AppView extends React.Component {
|
|||||||
handleLogout() {
|
handleLogout() {
|
||||||
localStorage.removeItem("auth-token");
|
localStorage.removeItem("auth-token");
|
||||||
this.setState(this.getInitialState());
|
this.setState(this.getInitialState());
|
||||||
this.tnSetup(this.state.serverAddress, this.state.transport);
|
AppView.tnSetup(this.state.serverAddress, this.state.transport);
|
||||||
window.location.hash = "";
|
window.location.hash = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user