|
@@ -15,6 +15,7 @@ import { createSubscribedElement } from '../UnstatedUtils';
|
|
|
import RevisionBody from '../Page/RevisionBody';
|
|
import RevisionBody from '../Page/RevisionBody';
|
|
|
import UserPicture from '../User/UserPicture';
|
|
import UserPicture from '../User/UserPicture';
|
|
|
import Username from '../User/Username';
|
|
import Username from '../User/Username';
|
|
|
|
|
+import CommentEditor from './CommentEditor';
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
*
|
|
*
|
|
@@ -32,8 +33,11 @@ class Comment extends React.Component {
|
|
|
this.state = {
|
|
this.state = {
|
|
|
html: '',
|
|
html: '',
|
|
|
isOlderRepliesShown: false,
|
|
isOlderRepliesShown: false,
|
|
|
|
|
+ showReEditorIds: new Set(),
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+ this.growiRenderer = this.props.appContainer.getRenderer('comment');
|
|
|
|
|
+
|
|
|
this.isCurrentUserIsAuthor = this.isCurrentUserEqualsToAuthor.bind(this);
|
|
this.isCurrentUserIsAuthor = this.isCurrentUserEqualsToAuthor.bind(this);
|
|
|
this.isCurrentRevision = this.isCurrentRevision.bind(this);
|
|
this.isCurrentRevision = this.isCurrentRevision.bind(this);
|
|
|
this.getRootClassName = this.getRootClassName.bind(this);
|
|
this.getRootClassName = this.getRootClassName.bind(this);
|
|
@@ -41,6 +45,7 @@ class Comment extends React.Component {
|
|
|
this.deleteBtnClickedHandler = this.deleteBtnClickedHandler.bind(this);
|
|
this.deleteBtnClickedHandler = this.deleteBtnClickedHandler.bind(this);
|
|
|
this.renderText = this.renderText.bind(this);
|
|
this.renderText = this.renderText.bind(this);
|
|
|
this.renderHtml = this.renderHtml.bind(this);
|
|
this.renderHtml = this.renderHtml.bind(this);
|
|
|
|
|
+ this.commentButtonClickedHandler = this.commentButtonClickedHandler.bind(this);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
componentWillMount() {
|
|
componentWillMount() {
|
|
@@ -56,6 +61,10 @@ class Comment extends React.Component {
|
|
|
this.renderHtml(markdown);
|
|
this.renderHtml(markdown);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ checkPermissionToControlComment() {
|
|
|
|
|
+ return this.props.appContainer.isAdmin || this.isCurrentUserEqualsToAuthor();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
isCurrentUserEqualsToAuthor() {
|
|
isCurrentUserEqualsToAuthor() {
|
|
|
return this.props.comment.creator.username === this.props.appContainer.me;
|
|
return this.props.comment.creator.username === this.props.appContainer.me;
|
|
|
}
|
|
}
|
|
@@ -90,6 +99,20 @@ class Comment extends React.Component {
|
|
|
this.isCurrentRevision() ? 'label-primary' : 'label-default'}`;
|
|
this.isCurrentRevision() ? 'label-primary' : 'label-default'}`;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ editBtnClickedHandler(commentId) {
|
|
|
|
|
+ const ids = this.state.showReEditorIds.add(commentId);
|
|
|
|
|
+ this.setState({ showReEditorIds: ids });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ commentButtonClickedHandler(commentId) {
|
|
|
|
|
+ this.setState((prevState) => {
|
|
|
|
|
+ prevState.showReEditorIds.delete(commentId);
|
|
|
|
|
+ return {
|
|
|
|
|
+ showReEditorIds: prevState.showReEditorIds,
|
|
|
|
|
+ };
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
deleteBtnClickedHandler() {
|
|
deleteBtnClickedHandler() {
|
|
|
this.props.deleteBtnClicked(this.props.comment);
|
|
this.props.deleteBtnClicked(this.props.comment);
|
|
|
}
|
|
}
|
|
@@ -214,11 +237,29 @@ class Comment extends React.Component {
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ renderCommentControl(comment) {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div className="page-comment-control">
|
|
|
|
|
+ <button type="button" className="btn btn-link p-2" onClick={() => { this.editBtnClickedHandler(comment._id) }}>
|
|
|
|
|
+ <i className="ti-pencil"></i>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <button type="button" className="btn btn-link p-2 mr-2" onClick={this.deleteBtnClickedHandler}>
|
|
|
|
|
+ <i className="ti-close"></i>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
render() {
|
|
render() {
|
|
|
const comment = this.props.comment;
|
|
const comment = this.props.comment;
|
|
|
|
|
+ const commentId = comment._id;
|
|
|
const creator = comment.creator;
|
|
const creator = comment.creator;
|
|
|
const isMarkdown = comment.isMarkdown;
|
|
const isMarkdown = comment.isMarkdown;
|
|
|
const createdAt = new Date(comment.createdAt);
|
|
const createdAt = new Date(comment.createdAt);
|
|
|
|
|
+ const updatedAt = new Date(comment.updatedAt);
|
|
|
|
|
+ const isEdited = createdAt < updatedAt;
|
|
|
|
|
+
|
|
|
|
|
+ const showReEditor = this.state.showReEditorIds.has(commentId);
|
|
|
|
|
|
|
|
const rootClassName = this.getRootClassName(comment);
|
|
const rootClassName = this.getRootClassName(comment);
|
|
|
const commentDate = formatDistanceStrict(createdAt, new Date());
|
|
const commentDate = formatDistanceStrict(createdAt, new Date());
|
|
@@ -232,31 +273,49 @@ class Comment extends React.Component {
|
|
|
{format(createdAt, 'yyyy/MM/dd HH:mm')}
|
|
{format(createdAt, 'yyyy/MM/dd HH:mm')}
|
|
|
</Tooltip>
|
|
</Tooltip>
|
|
|
);
|
|
);
|
|
|
|
|
+ const editedDateTooltip = isEdited
|
|
|
|
|
+ ? (
|
|
|
|
|
+ <Tooltip id={`editedDateTooltip-${comment._id}`}>
|
|
|
|
|
+ {format(updatedAt, 'yyyy/MM/dd HH:mm')}
|
|
|
|
|
+ </Tooltip>
|
|
|
|
|
+ )
|
|
|
|
|
+ : null;
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
<React.Fragment>
|
|
<React.Fragment>
|
|
|
|
|
|
|
|
- <div className={rootClassName}>
|
|
|
|
|
- <UserPicture user={creator} />
|
|
|
|
|
- <div className="page-comment-main">
|
|
|
|
|
- <div className="page-comment-creator">
|
|
|
|
|
- <Username user={creator} />
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className="page-comment-body">{commentBody}</div>
|
|
|
|
|
- <div className="page-comment-meta">
|
|
|
|
|
- <OverlayTrigger overlay={commentDateTooltip} placement="bottom">
|
|
|
|
|
- <span>{commentDate}</span>
|
|
|
|
|
- </OverlayTrigger>
|
|
|
|
|
- <span className="ml-2"><a className={revisionLavelClassName} href={revHref}>{revFirst8Letters}</a></span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className="page-comment-control">
|
|
|
|
|
- <button type="button" className="btn btn-link" onClick={this.deleteBtnClickedHandler}>
|
|
|
|
|
- <i className="ti-close"></i>
|
|
|
|
|
- </button>
|
|
|
|
|
|
|
+ {showReEditor ? (
|
|
|
|
|
+ <CommentEditor
|
|
|
|
|
+ growiRenderer={this.growiRenderer}
|
|
|
|
|
+ currentCommentId={commentId}
|
|
|
|
|
+ commentBody={comment.comment}
|
|
|
|
|
+ replyTo={undefined}
|
|
|
|
|
+ commentButtonClickedHandler={this.commentButtonClickedHandler}
|
|
|
|
|
+ />
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <div className={rootClassName}>
|
|
|
|
|
+ <UserPicture user={creator} />
|
|
|
|
|
+ <div className="page-comment-main">
|
|
|
|
|
+ <div className="page-comment-creator">
|
|
|
|
|
+ <Username user={creator} />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div className="page-comment-body">{commentBody}</div>
|
|
|
|
|
+ <div className="page-comment-meta">
|
|
|
|
|
+ <OverlayTrigger overlay={commentDateTooltip} placement="bottom">
|
|
|
|
|
+ <span>{commentDate}</span>
|
|
|
|
|
+ </OverlayTrigger>
|
|
|
|
|
+ { isEdited && (
|
|
|
|
|
+ <OverlayTrigger overlay={editedDateTooltip} placement="bottom">
|
|
|
|
|
+ <span> (edited)</span>
|
|
|
|
|
+ </OverlayTrigger>
|
|
|
|
|
+ ) }
|
|
|
|
|
+ <span className="ml-2"><a className={revisionLavelClassName} href={revHref}>{revFirst8Letters}</a></span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ { this.checkPermissionToControlComment() && this.renderCommentControl(comment) }
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
{this.renderReplies()}
|
|
{this.renderReplies()}
|
|
|
|
|
|
|
|
</React.Fragment>
|
|
</React.Fragment>
|