diff options
-rw-r--r-- | ui/src/components/comment-node.tsx | 19 | ||||
-rw-r--r-- | ui/src/components/post-listing.tsx | 200 | ||||
-rw-r--r-- | ui/src/translations/en.ts | 1 |
3 files changed, 129 insertions, 91 deletions
diff --git a/ui/src/components/comment-node.tsx b/ui/src/components/comment-node.tsx index 7dbaafdc..a4e398f1 100644 --- a/ui/src/components/comment-node.tsx +++ b/ui/src/components/comment-node.tsx @@ -22,6 +22,7 @@ interface CommentNodeState { showConfirmTransferSite: boolean; showConfirmTransferCommunity: boolean; collapsed: boolean; + viewSource: boolean; } interface CommentNodeProps { @@ -46,6 +47,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { banExpires: null, banType: BanType.Community, collapsed: false, + viewSource: false, showConfirmTransferSite: false, showConfirmTransferCommunity: false, } @@ -106,7 +108,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { {this.state.showEdit && <CommentForm node={node} edit onReplyCancel={this.handleReplyCancel} disabled={this.props.locked} />} {!this.state.showEdit && !this.state.collapsed && <div> - <div className="md-div" dangerouslySetInnerHTML={mdToHtml(node.comment.removed ? `*${i18n.t('removed')}*` : node.comment.deleted ? `*${i18n.t('deleted')}*` : node.comment.content)} /> + {this.state.viewSource ? <div>{this.commentUnlessRemoved}</div> : + <div className="md-div" dangerouslySetInnerHTML={mdToHtml(this.commentUnlessRemoved)} /> + } <ul class="list-inline mb-1 text-muted small font-weight-bold"> {UserService.Instance.user && !this.props.viewOnly && <> @@ -202,6 +206,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { </> } <li className="list-inline-item"> + <span className="pointer" onClick={linkEvent(this, this.handleViewSource)}><T i18nKey="view_source">#</T></span> + </li> + <li className="list-inline-item"> <Link className="text-muted" to={`/post/${node.comment.post_id}/comment/${node.comment.id}`}><T i18nKey="link">#</T></Link> </li> {this.props.markable && @@ -297,6 +304,11 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { (this.props.node.comment.creator_id != UserService.Instance.user.id) && (UserService.Instance.user.id == this.props.admins[0].id); } + + get commentUnlessRemoved(): string { + let node = this.props.node; + return node.comment.removed ? `*${i18n.t('removed')}*` : node.comment.deleted ? `*${i18n.t('deleted')}*` : node.comment.content; + } handleReplyClick(i: CommentNode) { i.state.showReply = true; @@ -527,4 +539,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { i.state.collapsed = !i.state.collapsed; i.setState(i.state); } + + handleViewSource(i: CommentNode) { + i.state.viewSource = !i.state.viewSource; + i.setState(i.state); + } } diff --git a/ui/src/components/post-listing.tsx b/ui/src/components/post-listing.tsx index 5b83c74e..8234cc8a 100644 --- a/ui/src/components/post-listing.tsx +++ b/ui/src/components/post-listing.tsx @@ -19,6 +19,7 @@ interface PostListingState { showConfirmTransferSite: boolean; showConfirmTransferCommunity: boolean; imageExpanded: boolean; + viewSource: boolean; } interface PostListingProps { @@ -44,6 +45,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> { showConfirmTransferSite: false, showConfirmTransferCommunity: false, imageExpanded: false, + viewSource: false, } constructor(props: any, context: any) { @@ -168,103 +170,110 @@ export class PostListing extends Component<PostListingProps, PostListingState> { <Link className="text-muted" to={`/post/${post.id}`}><T i18nKey="number_of_comments" interpolation={{count: post.number_of_comments}}>#</T></Link> </li> </ul> - {UserService.Instance.user && this.props.editable && - <ul class="list-inline mb-1 text-muted small font-weight-bold"> - <li className="list-inline-item mr-2"> - <span class="pointer" onClick={linkEvent(this, this.handleSavePostClick)}>{post.saved ? i18n.t('unsave') : i18n.t('save')}</span> - </li> - <li className="list-inline-item mr-2"> - <Link className="text-muted" to={`/create_post${this.crossPostParams}`}><T i18nKey="cross_post">#</T></Link> - </li> - {this.myPost && - <> - <li className="list-inline-item"> - <span class="pointer" onClick={linkEvent(this, this.handleEditClick)}><T i18nKey="edit">#</T></span> - </li> - <li className="list-inline-item mr-2"> - <span class="pointer" onClick={linkEvent(this, this.handleDeleteClick)}> - {!post.deleted ? i18n.t('delete') : i18n.t('restore')} - </span> - </li> - </> - } - {this.canMod && - <> - <li className="list-inline-item"> - {!post.removed ? - <span class="pointer" onClick={linkEvent(this, this.handleModRemoveShow)}><T i18nKey="remove">#</T></span> : - <span class="pointer" onClick={linkEvent(this, this.handleModRemoveSubmit)}><T i18nKey="restore">#</T></span> - } - </li> - <li className="list-inline-item"> - <span class="pointer" onClick={linkEvent(this, this.handleModLock)}>{post.locked ? i18n.t('unlock') : i18n.t('lock')}</span> - </li> - </> - } - {/* Mods can ban from community, and appoint as mods to community */} - {this.canMod && - <> - {!this.isMod && + <ul class="list-inline mb-1 text-muted small font-weight-bold"> + {UserService.Instance.user && this.props.editable && + <> + <li className="list-inline-item mr-2"> + <span class="pointer" onClick={linkEvent(this, this.handleSavePostClick)}>{post.saved ? i18n.t('unsave') : i18n.t('save')}</span> + </li> + <li className="list-inline-item mr-2"> + <Link className="text-muted" to={`/create_post${this.crossPostParams}`}><T i18nKey="cross_post">#</T></Link> + </li> + {this.myPost && + <> <li className="list-inline-item"> - {!post.banned_from_community ? - <span class="pointer" onClick={linkEvent(this, this.handleModBanFromCommunityShow)}><T i18nKey="ban">#</T></span> : - <span class="pointer" onClick={linkEvent(this, this.handleModBanFromCommunitySubmit)}><T i18nKey="unban">#</T></span> - } + <span class="pointer" onClick={linkEvent(this, this.handleEditClick)}><T i18nKey="edit">#</T></span> </li> - } - {!post.banned_from_community && - <li className="list-inline-item"> - <span class="pointer" onClick={linkEvent(this, this.handleAddModToCommunity)}>{this.isMod ? i18n.t('remove_as_mod') : i18n.t('appoint_as_mod')}</span> + <li className="list-inline-item mr-2"> + <span class="pointer" onClick={linkEvent(this, this.handleDeleteClick)}> + {!post.deleted ? i18n.t('delete') : i18n.t('restore')} + </span> </li> - } - </> - } - {/* Community creators and admins can transfer community to another mod */} - {(this.amCommunityCreator || this.canAdmin) && this.isMod && - <li className="list-inline-item"> - {!this.state.showConfirmTransferCommunity ? - <span class="pointer" onClick={linkEvent(this, this.handleShowConfirmTransferCommunity)}><T i18nKey="transfer_community">#</T> - </span> : <> - <span class="d-inline-block mr-1"><T i18nKey="are_you_sure">#</T></span> - <span class="pointer d-inline-block mr-1" onClick={linkEvent(this, this.handleTransferCommunity)}><T i18nKey="yes">#</T></span> - <span class="pointer d-inline-block" onClick={linkEvent(this, this.handleCancelShowConfirmTransferCommunity)}><T i18nKey="no">#</T></span> - </> - } - </li> - } - {/* Admins can ban from all, and appoint other admins */} - {this.canAdmin && - <> - {!this.isAdmin && + </> + } + {this.canMod && + <> <li className="list-inline-item"> - {!post.banned ? - <span class="pointer" onClick={linkEvent(this, this.handleModBanShow)}><T i18nKey="ban_from_site">#</T></span> : - <span class="pointer" onClick={linkEvent(this, this.handleModBanSubmit)}><T i18nKey="unban_from_site">#</T></span> + {!post.removed ? + <span class="pointer" onClick={linkEvent(this, this.handleModRemoveShow)}><T i18nKey="remove">#</T></span> : + <span class="pointer" onClick={linkEvent(this, this.handleModRemoveSubmit)}><T i18nKey="restore">#</T></span> } </li> - } - {!post.banned && <li className="list-inline-item"> - <span class="pointer" onClick={linkEvent(this, this.handleAddAdmin)}>{this.isAdmin ? i18n.t('remove_as_admin') : i18n.t('appoint_as_admin')}</span> + <span class="pointer" onClick={linkEvent(this, this.handleModLock)}>{post.locked ? i18n.t('unlock') : i18n.t('lock')}</span> </li> - } - </> - } - {/* Site Creator can transfer to another admin */} - {this.amSiteCreator && this.isAdmin && - <li className="list-inline-item"> - {!this.state.showConfirmTransferSite ? - <span class="pointer" onClick={linkEvent(this, this.handleShowConfirmTransferSite)}><T i18nKey="transfer_site">#</T> - </span> : <> - <span class="d-inline-block mr-1"><T i18nKey="are_you_sure">#</T></span> - <span class="pointer d-inline-block mr-1" onClick={linkEvent(this, this.handleTransferSite)}><T i18nKey="yes">#</T></span> - <span class="pointer d-inline-block" onClick={linkEvent(this, this.handleCancelShowConfirmTransferSite)}><T i18nKey="no">#</T></span> - </> - } - </li> - } - </ul> - } + </> + } + {/* Mods can ban from community, and appoint as mods to community */} + {this.canMod && + <> + {!this.isMod && + <li className="list-inline-item"> + {!post.banned_from_community ? + <span class="pointer" onClick={linkEvent(this, this.handleModBanFromCommunityShow)}><T i18nKey="ban">#</T></span> : + <span class="pointer" onClick={linkEvent(this, this.handleModBanFromCommunitySubmit)}><T i18nKey="unban">#</T></span> + } + </li> + } + {!post.banned_from_community && + <li className="list-inline-item"> + <span class="pointer" onClick={linkEvent(this, this.handleAddModToCommunity)}>{this.isMod ? i18n.t('remove_as_mod') : i18n.t('appoint_as_mod')}</span> + </li> + } + </> + } + {/* Community creators and admins can transfer community to another mod */} + {(this.amCommunityCreator || this.canAdmin) && this.isMod && + <li className="list-inline-item"> + {!this.state.showConfirmTransferCommunity ? + <span class="pointer" onClick={linkEvent(this, this.handleShowConfirmTransferCommunity)}><T i18nKey="transfer_community">#</T> + </span> : <> + <span class="d-inline-block mr-1"><T i18nKey="are_you_sure">#</T></span> + <span class="pointer d-inline-block mr-1" onClick={linkEvent(this, this.handleTransferCommunity)}><T i18nKey="yes">#</T></span> + <span class="pointer d-inline-block" onClick={linkEvent(this, this.handleCancelShowConfirmTransferCommunity)}><T i18nKey="no">#</T></span> + </> + } + </li> + } + {/* Admins can ban from all, and appoint other admins */} + {this.canAdmin && + <> + {!this.isAdmin && + <li className="list-inline-item"> + {!post.banned ? + <span class="pointer" onClick={linkEvent(this, this.handleModBanShow)}><T i18nKey="ban_from_site">#</T></span> : + <span class="pointer" onClick={linkEvent(this, this.handleModBanSubmit)}><T i18nKey="unban_from_site">#</T></span> + } + </li> + } + {!post.banned && + <li className="list-inline-item"> + <span class="pointer" onClick={linkEvent(this, this.handleAddAdmin)}>{this.isAdmin ? i18n.t('remove_as_admin') : i18n.t('appoint_as_admin')}</span> + </li> + } + </> + } + {/* Site Creator can transfer to another admin */} + {this.amSiteCreator && this.isAdmin && + <li className="list-inline-item"> + {!this.state.showConfirmTransferSite ? + <span class="pointer" onClick={linkEvent(this, this.handleShowConfirmTransferSite)}><T i18nKey="transfer_site">#</T> + </span> : <> + <span class="d-inline-block mr-1"><T i18nKey="are_you_sure">#</T></span> + <span class="pointer d-inline-block mr-1" onClick={linkEvent(this, this.handleTransferSite)}><T i18nKey="yes">#</T></span> + <span class="pointer d-inline-block" onClick={linkEvent(this, this.handleCancelShowConfirmTransferSite)}><T i18nKey="no">#</T></span> + </> + } + </li> + } + </> + } + {this.props.showBody && post.body && + <li className="list-inline-item"> + <span className="pointer" onClick={linkEvent(this, this.handleViewSource)}><T i18nKey="view_source">#</T></span> + </li> + } + </ul> {this.state.showRemoveDialog && <form class="form-inline" onSubmit={linkEvent(this, this.handleModRemoveSubmit)}> <input type="text" class="form-control mr-2" placeholder={i18n.t('reason')} value={this.state.removeReason} onInput={linkEvent(this, this.handleModRemoveReasonChange)} /> @@ -287,7 +296,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> { </div> </form> } - {this.props.showBody && post.body && <div className="md-div" dangerouslySetInnerHTML={mdToHtml(post.body)} />} + {this.props.showBody && post.body && + <> + {this.state.viewSource ? <div>{post.body}</div> : + <div className="md-div" dangerouslySetInnerHTML={mdToHtml(post.body)} /> + } + </> + } </div> </div> ) @@ -566,5 +581,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> { i.state.imageExpanded = !i.state.imageExpanded; i.setState(i.state); } + + handleViewSource(i: PostListing) { + i.state.viewSource = !i.state.viewSource; + i.setState(i.state); + } } diff --git a/ui/src/translations/en.ts b/ui/src/translations/en.ts index 2d3523e9..f89a9879 100644 --- a/ui/src/translations/en.ts +++ b/ui/src/translations/en.ts @@ -29,6 +29,7 @@ export const en = { preview: 'Preview', upload_image: 'upload image', formatting_help: 'formatting help', + view_source: 'view source', unlock: 'unlock', lock: 'lock', link: 'link', |