added client predictive commenting
Этот коммит содержится в:
@@ -5,12 +5,13 @@ var client = require('../utils/client.jsx');
|
|||||||
var AsyncClient = require('../utils/async_client.jsx');
|
var AsyncClient = require('../utils/async_client.jsx');
|
||||||
var SocketStore = require('../stores/socket_store.jsx');
|
var SocketStore = require('../stores/socket_store.jsx');
|
||||||
var ChannelStore = require('../stores/channel_store.jsx');
|
var ChannelStore = require('../stores/channel_store.jsx');
|
||||||
|
var UserStore = require('../stores/user_store.jsx');
|
||||||
var PostStore = require('../stores/post_store.jsx');
|
var PostStore = require('../stores/post_store.jsx');
|
||||||
var Textbox = require('./textbox.jsx');
|
var Textbox = require('./textbox.jsx');
|
||||||
var MsgTyping = require('./msg_typing.jsx');
|
var MsgTyping = require('./msg_typing.jsx');
|
||||||
var FileUpload = require('./file_upload.jsx');
|
var FileUpload = require('./file_upload.jsx');
|
||||||
var FilePreview = require('./file_preview.jsx');
|
var FilePreview = require('./file_preview.jsx');
|
||||||
|
var utils = require('../utils/utils.jsx');
|
||||||
var Constants = require('../utils/constants.jsx');
|
var Constants = require('../utils/constants.jsx');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
@@ -39,10 +40,16 @@ module.exports = React.createClass({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var user_id = UserStore.getCurrentId();
|
||||||
|
|
||||||
post.channel_id = this.props.channelId;
|
post.channel_id = this.props.channelId;
|
||||||
post.root_id = this.props.rootId;
|
post.root_id = this.props.rootId;
|
||||||
post.parent_id = this.props.parentId;
|
post.parent_id = this.props.rootId;
|
||||||
post.filenames = this.state.previews;
|
post.filenames = this.state.previews;
|
||||||
|
var time = utils.getTimestamp();
|
||||||
|
post.pending_post_id = user_id + ":"+ time;
|
||||||
|
post.user_id = user_id;
|
||||||
|
post.create_at = time;
|
||||||
|
|
||||||
this.setState({submitting: true, serverError: null});
|
this.setState({submitting: true, serverError: null});
|
||||||
|
|
||||||
@@ -69,10 +76,19 @@ module.exports = React.createClass({
|
|||||||
$('#post_deleted').modal('show');
|
$('#post_deleted').modal('show');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.setState(state);
|
post.did_fail = true;
|
||||||
|
PostStore.updatePendingPost(post);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.submitting = false;
|
||||||
|
this.setState(state);
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
post.is_loading = true;
|
||||||
|
PostStore.storePendingPost(post);
|
||||||
|
PostStore.storeCommentDraft(this.props.rootId, null);
|
||||||
|
this.setState({ messageText: '', submitting: false, post_error: null, previews: [], server_error: null, limit_error: null });
|
||||||
},
|
},
|
||||||
commentMsgKeyPress: function(e) {
|
commentMsgKeyPress: function(e) {
|
||||||
if (e.which === 13 && !e.shiftKey && !e.altKey) {
|
if (e.which === 13 && !e.shiftKey && !e.altKey) {
|
||||||
|
|||||||
@@ -214,20 +214,34 @@ module.exports = React.createClass({
|
|||||||
var channelId = ChannelStore.getCurrentId();
|
var channelId = ChannelStore.getCurrentId();
|
||||||
if (this.state.channelId !== channelId) {
|
if (this.state.channelId !== channelId) {
|
||||||
var draft = PostStore.getCurrentDraft();
|
var draft = PostStore.getCurrentDraft();
|
||||||
this.setState({
|
|
||||||
channelId: channelId, messageText: draft['message'], initialText: draft['message'], submitting: false,
|
var previews = [];
|
||||||
serverError: null, postError: null, previews: draft['previews'], uploadsInProgress: draft['uploadsInProgress']
|
var messageText = '';
|
||||||
});
|
var uploadsInProgress = 0;
|
||||||
|
if (draft && draft['previews'] && draft['message']) {
|
||||||
|
previews = draft['previews'];
|
||||||
|
messageText = draft['message'];
|
||||||
|
uploadsInProgress = draft['uploadsInProgress'];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({channelId: channelId, messageText: messageText, initialText: messageText, submitting: false, serverError: null, postError: null, previews: previews, uploadsInProgress: uploadsInProgress});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
PostStore.clearDraftUploads();
|
PostStore.clearDraftUploads();
|
||||||
|
PostStore.clearPendingPosts(ChannelStore.getCurrentId());
|
||||||
|
|
||||||
var draft = PostStore.getCurrentDraft();
|
var draft = PostStore.getCurrentDraft();
|
||||||
return {
|
var previews = [];
|
||||||
channelId: ChannelStore.getCurrentId(), messageText: draft['message'], uploadsInProgress: draft['uploadsInProgress'],
|
var messageText = '';
|
||||||
previews: draft['previews'], submitting: false, initialText: draft['message']
|
var uploadsInProgress = 0;
|
||||||
};
|
if (draft && draft["previews"] && draft["message"]) {
|
||||||
|
previews = draft['previews'];
|
||||||
|
messageText = draft['message'];
|
||||||
|
uploadsInProgress = draft['uploadsInProgress'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return { channelId: ChannelStore.getCurrentId(), messageText: messageText, uploadsInProgress: uploadsInProgress, previews: previews, submitting: false, initialText: messageText};
|
||||||
},
|
},
|
||||||
getFileCount: function(channelId) {
|
getFileCount: function(channelId) {
|
||||||
if (channelId === this.state.channelId) {
|
if (channelId === this.state.channelId) {
|
||||||
|
|||||||
@@ -22,16 +22,19 @@ module.exports = React.createClass({
|
|||||||
|
|
||||||
var comments = "";
|
var comments = "";
|
||||||
var lastCommentClass = this.props.isLastComment ? " comment-icon__container__show" : " comment-icon__container__hide";
|
var lastCommentClass = this.props.isLastComment ? " comment-icon__container__show" : " comment-icon__container__hide";
|
||||||
if (this.props.commentCount >= 1) {
|
if (this.props.commentCount >= 1 && !post.did_fail && !post.is_loading) {
|
||||||
comments = <a href="#" className={"comment-icon__container theme" + lastCommentClass} onClick={this.props.handleCommentClick}><span className="comment-icon" dangerouslySetInnerHTML={{__html: Constants.COMMENT_ICON }} />{this.props.commentCount}</a>;
|
comments = <a href="#" className={"comment-icon__container theme" + lastCommentClass} onClick={this.props.handleCommentClick}><span className="comment-icon" dangerouslySetInnerHTML={{__html: Constants.COMMENT_ICON }} />{this.props.commentCount}</a>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var show_dropdown = isOwner || (this.props.allowReply === "true" && type != "Comment");
|
||||||
|
if (post.did_fail || post.is_loading) show_dropdown = false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ul className="post-header post-info">
|
<ul className="post-header post-info">
|
||||||
<li className="post-header-col"><time className="post-profile-time">{ utils.displayDateTime(post.create_at) }</time></li>
|
<li className="post-header-col"><time className="post-profile-time">{ utils.displayDateTime(post.create_at) }</time></li>
|
||||||
<li className="post-header-col post-header__reply">
|
<li className="post-header-col post-header__reply">
|
||||||
<div className="dropdown">
|
<div className="dropdown">
|
||||||
{ isOwner || (this.props.allowReply === "true" && type != "Comment") ?
|
{ show_dropdown ?
|
||||||
<div>
|
<div>
|
||||||
<a href="#" className="dropdown-toggle theme" type="button" data-toggle="dropdown" aria-expanded="false" />
|
<a href="#" className="dropdown-toggle theme" type="button" data-toggle="dropdown" aria-expanded="false" />
|
||||||
<ul className="dropdown-menu" role="menu">
|
<ul className="dropdown-menu" role="menu">
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ var CreateComment = require( './create_comment.jsx' );
|
|||||||
var Constants = require('../utils/constants.jsx');
|
var Constants = require('../utils/constants.jsx');
|
||||||
var FileAttachmentList = require('./file_attachment_list.jsx');
|
var FileAttachmentList = require('./file_attachment_list.jsx');
|
||||||
var FileUploadOverlay = require('./file_upload_overlay.jsx');
|
var FileUploadOverlay = require('./file_upload_overlay.jsx');
|
||||||
|
var client = require('../utils/client.jsx');
|
||||||
var ActionTypes = Constants.ActionTypes;
|
var ActionTypes = Constants.ActionTypes;
|
||||||
|
|
||||||
RhsHeaderPost = React.createClass({
|
RhsHeaderPost = React.createClass({
|
||||||
@@ -119,10 +120,36 @@ RootPost = React.createClass({
|
|||||||
});
|
});
|
||||||
|
|
||||||
CommentPost = React.createClass({
|
CommentPost = React.createClass({
|
||||||
|
retryComment: function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var post = this.props.post;
|
||||||
|
client.createPost(post, post.channel_id,
|
||||||
|
function(data) {
|
||||||
|
AsyncClient.getPosts(true);
|
||||||
|
|
||||||
|
var member = ChannelStore.getMember(post.channel_id);
|
||||||
|
member.msg_count = channel.total_msg_count;
|
||||||
|
member.last_viewed_at = (new Date).getTime();
|
||||||
|
ChannelStore.setChannelMember(member);
|
||||||
|
}.bind(this),
|
||||||
|
function(err) {
|
||||||
|
post.did_fail = true;
|
||||||
|
PostStore.updatePendingPost(post);
|
||||||
|
this.forceUpdate();
|
||||||
|
}.bind(this)
|
||||||
|
);
|
||||||
|
|
||||||
|
post.did_fail = false;
|
||||||
|
post.is_loading = true;
|
||||||
|
PostStore.updatePendingPost(post);
|
||||||
|
this.forceUpdate();
|
||||||
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
var post = this.props.post;
|
var post = this.props.post;
|
||||||
|
|
||||||
var commentClass = "post";
|
var commentClass = "post";
|
||||||
|
var post = this.props.post;
|
||||||
|
|
||||||
var currentUserCss = "";
|
var currentUserCss = "";
|
||||||
if (UserStore.getCurrentId() === post.user_id) {
|
if (UserStore.getCurrentId() === post.user_id) {
|
||||||
@@ -139,6 +166,16 @@ CommentPost = React.createClass({
|
|||||||
var message = utils.textToJsx(post.message);
|
var message = utils.textToJsx(post.message);
|
||||||
var timestamp = UserStore.getCurrentUser().update_at;
|
var timestamp = UserStore.getCurrentUser().update_at;
|
||||||
|
|
||||||
|
var loading;
|
||||||
|
var postClass = "";
|
||||||
|
if (post.did_fail) {
|
||||||
|
postClass += " post-fail";
|
||||||
|
loading = <a className="post-retry pull-right" href="#" onClick={this.retryComment}>Retry</a>;
|
||||||
|
} else if (post.is_loading) {
|
||||||
|
postClass += " post-waiting";
|
||||||
|
loading = <img className="post-loading-gif pull-right" src="/static/images/load.gif"/>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={commentClass + " " + currentUserCss}>
|
<div className={commentClass + " " + currentUserCss}>
|
||||||
<div className="post-profile-img__container">
|
<div className="post-profile-img__container">
|
||||||
@@ -149,7 +186,7 @@ CommentPost = React.createClass({
|
|||||||
<li className="post-header-col"><strong><UserProfile userId={post.user_id} /></strong></li>
|
<li className="post-header-col"><strong><UserProfile userId={post.user_id} /></strong></li>
|
||||||
<li className="post-header-col"><time className="post-right-comment-time">{ utils.displayDateTime(post.create_at) }</time></li>
|
<li className="post-header-col"><time className="post-right-comment-time">{ utils.displayDateTime(post.create_at) }</time></li>
|
||||||
<li className="post-header-col post-header__reply">
|
<li className="post-header-col post-header__reply">
|
||||||
{ isOwner ?
|
{ isOwner && !post.did_fail && !post.is_loading ?
|
||||||
<div className="dropdown" onClick={function(e){$('.post-list-holder-by-time').scrollTop($(".post-list-holder-by-time").scrollTop() + 50);}}>
|
<div className="dropdown" onClick={function(e){$('.post-list-holder-by-time').scrollTop($(".post-list-holder-by-time").scrollTop() + 50);}}>
|
||||||
<a href="#" className="dropdown-toggle theme" type="button" data-toggle="dropdown" aria-expanded="false" />
|
<a href="#" className="dropdown-toggle theme" type="button" data-toggle="dropdown" aria-expanded="false" />
|
||||||
<ul className="dropdown-menu" role="menu">
|
<ul className="dropdown-menu" role="menu">
|
||||||
@@ -161,7 +198,7 @@ CommentPost = React.createClass({
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div className="post-body">
|
<div className="post-body">
|
||||||
<p>{message}</p>
|
<p className={postClass}>{loading}{message}</p>
|
||||||
{ post.filenames && post.filenames.length > 0 ?
|
{ post.filenames && post.filenames.length > 0 ?
|
||||||
<FileAttachmentList
|
<FileAttachmentList
|
||||||
filenames={post.filenames}
|
filenames={post.filenames}
|
||||||
@@ -177,7 +214,17 @@ CommentPost = React.createClass({
|
|||||||
});
|
});
|
||||||
|
|
||||||
function getStateFromStores() {
|
function getStateFromStores() {
|
||||||
return { post_list: PostStore.getSelectedPost() };
|
var post_list = PostStore.getSelectedPost();
|
||||||
|
if (!post_list || post_list.order.length < 1) return { post_list: {} };
|
||||||
|
|
||||||
|
var channel_id = post_list.posts[post_list.order[0]].channel_id;
|
||||||
|
var pending_post_list = PostStore.getPendingPosts(channel_id);
|
||||||
|
|
||||||
|
if (pending_post_list) {
|
||||||
|
for (var pid in pending_post_list.posts) { post_list.posts[pid] = pending_post_list.posts[pid] };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { post_list: post_list };
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user