diff --git a/api/file.go b/api/file.go index bf1c594220..558f9357e7 100644 --- a/api/file.go +++ b/api/file.go @@ -71,7 +71,9 @@ func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) { files := m.File["files"] resStruct := &model.FileUploadResponse{ - Filenames: []string{}} + Filenames: []string{}, + ClientIds: []string{}, + } imageNameList := []string{} imageDataList := [][]byte{} @@ -113,6 +115,10 @@ func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) { resStruct.Filenames = append(resStruct.Filenames, fileUrl) } + for _, clientId := range props["client_ids"] { + resStruct.ClientIds = append(resStruct.ClientIds, clientId) + } + fireAndForgetHandleImages(imageNameList, imageDataList, c.Session.TeamId, channelId, c.Session.UserId) w.Write([]byte(resStruct.ToJson())) diff --git a/model/file.go b/model/file.go index 7f5a3f9162..3d38ddbd15 100644 --- a/model/file.go +++ b/model/file.go @@ -19,6 +19,7 @@ var ( type FileUploadResponse struct { Filenames []string `json:"filenames"` + ClientIds []string `json:"client_ids"` } func FileUploadResponseFromJson(data io.Reader) *FileUploadResponse { diff --git a/web/react/components/create_comment.jsx b/web/react/components/create_comment.jsx index 88c01c586b..78e06c5320 100644 --- a/web/react/components/create_comment.jsx +++ b/web/react/components/create_comment.jsx @@ -18,20 +18,24 @@ module.exports = React.createClass({ handleSubmit: function(e) { e.preventDefault(); - if (this.state.uploadsInProgress > 0) return; + if (this.state.uploadsInProgress.length > 0) { + return; + } - if (this.state.submitting) return; + if (this.state.submitting) { + return; + } - var post = {} + var post = {}; post.filenames = []; - post.message = this.state.messageText; + if (post.message.trim().length === 0 && this.state.previews.length === 0) { return; } if (post.message.length > Constants.CHARACTER_LIMIT) { - this.setState({ post_error: 'Comment length must be less than '+Constants.CHARACTER_LIMIT+' characters.' }); + this.setState({postError: 'Comment length must be less than ' + Constants.CHARACTER_LIMIT + ' characters.'}); return; } @@ -40,163 +44,154 @@ module.exports = React.createClass({ post.parent_id = this.props.parentId; post.filenames = this.state.previews; - this.setState({ submitting: true, limit_error: null }); + this.setState({submitting: true, serverError: null}); client.createPost(post, ChannelStore.getCurrent(), function(data) { PostStore.storeCommentDraft(this.props.rootId, null); - this.setState({ messageText: '', submitting: false, post_error: null, server_error: null }); + this.setState({messageText: '', submitting: false, postError: null, serverError: null}); this.clearPreviews(); AsyncClient.getPosts(true, this.props.channelId); var channel = ChannelStore.get(this.props.channelId); var member = ChannelStore.getMember(this.props.channelId); member.msg_count = channel.total_msg_count; - member.last_viewed_at = (new Date).getTime(); + member.last_viewed_at = Date.now(); ChannelStore.setChannelMember(member); - }.bind(this), function(err) { var state = {}; - state.server_error = err.message; + state.serverError = err.message; state.submitting = false; - if (err.message === "Invalid RootId parameter") { - if ($('#post_deleted').length > 0) $('#post_deleted').modal('show'); - } - else { + if (err.message === 'Invalid RootId parameter') { + if ($('#post_deleted').length > 0) { + $('#post_deleted').modal('show'); + } + } else { this.setState(state); } }.bind(this) ); }, commentMsgKeyPress: function(e) { - if (e.which == 13 && !e.shiftKey && !e.altKey) { + if (e.which === 13 && !e.shiftKey && !e.altKey) { e.preventDefault(); this.refs.textbox.getDOMNode().blur(); this.handleSubmit(e); } - var t = new Date().getTime(); + var t = Date.now(); if ((t - this.lastTime) > 5000) { - SocketStore.sendMessage({channel_id: this.props.channelId, action: "typing", props: {"parent_id": this.props.rootId} }); + SocketStore.sendMessage({channel_id: this.props.channelId, action: 'typing', props: {'parent_id': this.props.rootId}}); this.lastTime = t; } }, handleUserInput: function(messageText) { var draft = PostStore.getCommentDraft(this.props.rootId); - if (!draft) { - draft = { previews: [], uploadsInProgress: 0}; - } draft.message = messageText; PostStore.storeCommentDraft(this.props.rootId, draft); - $(".post-right__scroll").scrollTop($(".post-right__scroll")[0].scrollHeight); - $(".post-right__scroll").perfectScrollbar('update'); + $('.post-right__scroll').scrollTop($('.post-right__scroll')[0].scrollHeight); + $('.post-right__scroll').perfectScrollbar('update'); this.setState({messageText: messageText}); }, - handleFileUpload: function(newPreviews) { + handleUploadStart: function(clientIds, channelId) { var draft = PostStore.getCommentDraft(this.props.rootId); - if (!draft) { - draft = { message: '', uploadsInProgress: 0, previews: []} - } - $(".post-right__scroll").scrollTop($(".post-right__scroll")[0].scrollHeight); - $(".post-right__scroll").perfectScrollbar('update'); - var previews = this.state.previews.concat(newPreviews); - var num = this.state.uploadsInProgress; - - draft.previews = previews; - draft.uploadsInProgress = num-1; + draft['uploadsInProgress'] = draft['uploadsInProgress'].concat(clientIds); PostStore.storeCommentDraft(this.props.rootId, draft); - this.setState({previews: previews, uploadsInProgress: num-1}); + this.setState({uploadsInProgress: draft['uploadsInProgress']}); }, - handleUploadError: function(err) { - this.setState({ server_error: err }); + handleFileUploadComplete: function(filenames, clientIds, channelId) { + var draft = PostStore.getCommentDraft(this.props.rootId); + + // remove each finished file from uploads + for (var i = 0; i < clientIds.length; i++) { + var index = draft['uploadsInProgress'].indexOf(clientIds[i]); + + if (index !== -1) { + draft['uploadsInProgress'].splice(index, 1); + } + } + + draft['previews'] = draft['previews'].concat(filenames); + PostStore.storeCommentDraft(this.props.rootId, draft); + + this.setState({uploadsInProgress: draft['uploadsInProgress'], previews: draft['previews']}); + }, + handleUploadError: function(err, clientId) { + var draft = PostStore.getCommentDraft(this.props.rootId); + + var index = draft['uploadsInProgress'].indexOf(clientId); + if (index !== -1) { + draft['uploadsInProgress'].splice(index, 1); + } + + PostStore.storeCommentDraft(this.props.rootId, draft); + + this.setState({uploadsInProgress: draft['uploadsInProgress'], serverError: err}); }, clearPreviews: function() { this.setState({previews: []}); }, - removePreview: function(filename) { + removePreview: function(id) { var previews = this.state.previews; - for (var i = 0; i < previews.length; i++) { - if (previews[i] === filename) { - previews.splice(i, 1); - break; + var uploadsInProgress = this.state.uploadsInProgress; + + // id can either be the path of an uploaded file or the client id of an in progress upload + var index = previews.indexOf(id); + if (index !== -1) { + previews.splice(index, 1); + } else { + index = uploadsInProgress.indexOf(id); + + if (index !== -1) { + uploadsInProgress.splice(index, 1); + this.refs.fileUpload.cancelUpload(id); } } - var draft = PostStore.getCommentDraft(); - if (!draft) { - draft = { message: '', uploadsInProgress: 0}; - } + var draft = PostStore.getCommentDraft(this.props.rootId); draft.previews = previews; - PostStore.storeCommentDraft(draft); + draft.uploadsInProgress = uploadsInProgress; + PostStore.storeCommentDraft(this.props.rootId, draft); - this.setState({previews: previews}); + this.setState({previews: previews, uploadsInProgress: uploadsInProgress}); }, getInitialState: function() { PostStore.clearCommentDraftUploads(); var draft = PostStore.getCommentDraft(this.props.rootId); - messageText = ''; - uploadsInProgress = 0; - previews = []; - if (draft) { - messageText = draft.message; - uploadsInProgress = draft.uploadsInProgress; - previews = draft.previews - } - return { messageText: messageText, uploadsInProgress: uploadsInProgress, previews: previews, submitting: false }; + return {messageText: draft['message'], uploadsInProgress: draft['uploadsInProgress'], previews: draft['previews'], submitting: false}; }, componentWillReceiveProps: function(newProps) { - if(newProps.rootId !== this.props.rootId) { + if (newProps.rootId !== this.props.rootId) { var draft = PostStore.getCommentDraft(newProps.rootId); - messageText = ''; - uploadsInProgress = 0; - previews = []; - if (draft) { - messageText = draft.message; - uploadsInProgress = draft.uploadsInProgress; - previews = draft.previews - } - this.setState({ messageText: messageText, uploadsInProgress: uploadsInProgress, previews: previews }); + this.setState({messageText: draft['message'], uploadsInProgress: draft['uploadsInProgress'], previews: draft['previews']}); } }, - setUploads: function(val) { - var oldInProgress = this.state.uploadsInProgress - var newInProgress = oldInProgress + val; - - if (newInProgress + this.state.previews.length > Constants.MAX_UPLOAD_FILES) { - newInProgress = Constants.MAX_UPLOAD_FILES - this.state.previews.length; - this.setState({limit_error: "Uploads limited to " + Constants.MAX_UPLOAD_FILES + " files maximum. Please use additional comments for more files."}); - } else { - this.setState({limit_error: null}); - } - - var numToUpload = newInProgress - oldInProgress; - if (numToUpload <= 0) return 0; - - var draft = PostStore.getCommentDraft(this.props.rootId); - if (!draft) { - draft = { message: '', previews: []}; - } - draft.uploadsInProgress = newInProgress; - PostStore.storeCommentDraft(this.props.rootId, draft); - - this.setState({uploadsInProgress: newInProgress}); - - return numToUpload; + getFileCount: function(channelId) { + return this.state.previews.length + this.state.uploadsInProgress.length; }, render: function() { + var serverError = null; + if (this.state.serverError) { + serverError = ( +