mirror of
https://github.com/renbaoshuo/S2OJ.git
synced 2024-11-08 12:18:43 +00:00
feat(blog): markdown comment support
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
4582a6b947
commit
c98a893fb6
@ -9,20 +9,46 @@ UOJBlog::cur()->belongsToUserBlog() || UOJResponse::page404();
|
|||||||
UOJBlog::cur()->userCanView(Auth::user()) || UOJResponse::page403();
|
UOJBlog::cur()->userCanView(Auth::user()) || UOJResponse::page403();
|
||||||
|
|
||||||
$blog = UOJBlog::info();
|
$blog = UOJBlog::info();
|
||||||
|
$purifier = HTML::purifier();
|
||||||
|
$parsedown = HTML::parsedown([
|
||||||
|
'username_with_color' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
function getCommentContentToDisplay($comment) {
|
function getCommentContentToDisplay($comment) {
|
||||||
if (!$comment['is_hidden']) {
|
global $purifier, $parsedown;
|
||||||
return $comment['content'];
|
|
||||||
} else if (UOJUserBlog::userHasManagePermission(Auth::user())) {
|
$rendered = $purifier->purify($parsedown->text($comment['content']));
|
||||||
return '<span class="text-muted mb-3">【' . HTML::escape($comment['reason_to_hide']) . '】</span>' . $comment['content'];
|
|
||||||
} else {
|
if ($comment['is_hidden']) {
|
||||||
return '<span class="text-muted">【' . HTML::escape($comment['reason_to_hide']) . '】</span>';
|
$esc_hide_reason = $comment['reason_to_hide'];
|
||||||
|
$res = <<<EOD
|
||||||
|
<div class="alert alert-warning d-flex align-items-center my-0" role="alert">
|
||||||
|
<div class="flex-shrink-0 me-3">
|
||||||
|
<i class="fs-4 bi bi-exclamation-triangle-fill"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="fw-bold mb-2">该评论被隐藏</div>
|
||||||
|
<div class="small">{$esc_hide_reason}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
EOD;
|
||||||
|
|
||||||
|
if (UOJUserBlog::userHasManagePermission(Auth::user())) {
|
||||||
|
$res .= <<<EOD
|
||||||
|
<div class="mt-2">{$rendered}</div>
|
||||||
|
EOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $rendered;
|
||||||
}
|
}
|
||||||
|
|
||||||
$comment_form = new UOJForm('comment');
|
$comment_form = new UOJForm('comment');
|
||||||
$comment_form->addTextArea('comment', [
|
$comment_form->addTextArea('comment', [
|
||||||
'label' => '内容',
|
'label' => '内容',
|
||||||
|
'help' => '评论支持 Markdown 语法。可以用 <code>@mike</code> 来提到 <code>mike</code> 这个用户,<code>mike</code> 会被高亮显示。如果你真的想打 <code>@</code> 这个字符,请用 <code>@@</code>。',
|
||||||
'validator_php' => function ($comment) {
|
'validator_php' => function ($comment) {
|
||||||
if (!Auth::check()) {
|
if (!Auth::check()) {
|
||||||
return '请先登录';
|
return '请先登录';
|
||||||
@ -257,22 +283,24 @@ $comments_pag = new Paginator([
|
|||||||
$asrc = HTML::avatar_addr($poster, 80);
|
$asrc = HTML::avatar_addr($poster, 80);
|
||||||
|
|
||||||
$replies = DB::selectAll([
|
$replies = DB::selectAll([
|
||||||
"select id, poster, content, post_time, is_hidden, reason_to_hide from blogs_comments",
|
"select id, poster, content, post_time, is_hidden, reason_to_hide, zan from blogs_comments",
|
||||||
"where", ["reply_id" => $comment['id']],
|
"where", ["reply_id" => $comment['id']],
|
||||||
"order by id"
|
"order by id"
|
||||||
]);
|
]);
|
||||||
foreach ($replies as $idx => $reply) {
|
foreach ($replies as $idx => $reply) {
|
||||||
$reply_user = UOJUser::query($reply['poster']);
|
$reply_user = UOJUser::query($reply['poster']);
|
||||||
|
$replies[$idx]['poster_avatar'] = HTML::avatar_addr($reply_user, 80);
|
||||||
$replies[$idx]['poster_realname'] = $reply_user['realname'];
|
$replies[$idx]['poster_realname'] = $reply_user['realname'];
|
||||||
$replies[$idx]['poster_username_color'] = UOJUser::getUserColor($reply_user);
|
$replies[$idx]['poster_username_color'] = UOJUser::getUserColor($reply_user);
|
||||||
$replies[$idx]['content'] = getCommentContentToDisplay($reply);
|
$replies[$idx]['content'] = getCommentContentToDisplay($reply);
|
||||||
|
$replies[$idx]['click_zan_block'] = ClickZans::getBlock('BC', $reply['id'], $reply['zan']);
|
||||||
}
|
}
|
||||||
$replies_json = json_encode($replies);
|
$replies_json = json_encode($replies);
|
||||||
?>
|
?>
|
||||||
<div id="comment-<?= $comment['id'] ?>" class="list-group-item">
|
<div id="comment-<?= $comment['id'] ?>" class="list-group-item">
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<div class="mr-3 flex-shrink-0">
|
<div class="d-none d-sm-block mr-3 flex-shrink-0">
|
||||||
<a href="<?= HTML::url('/user/' . $poster['username']) ?>" class="d-none d-sm-block text-decoration-none">
|
<a href="<?= HTML::url('/user/' . $poster['username']) ?>">
|
||||||
<img class="rounded uoj-user-avatar" src="<?= $asrc ?>" alt="Avatar of <?= $poster['username'] ?>" width="64" height="64" />
|
<img class="rounded uoj-user-avatar" src="<?= $asrc ?>" alt="Avatar of <?= $poster['username'] ?>" width="64" height="64" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -285,7 +313,7 @@ $comments_pag = new Paginator([
|
|||||||
<?= ClickZans::getBlock('BC', $comment['id'], $comment['zan']) ?>
|
<?= ClickZans::getBlock('BC', $comment['id'], $comment['zan']) ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="comment-content my-2" id="comment-content-<?= $comment['id'] ?>"><?= getCommentContentToDisplay($comment) ?></div>
|
<div class="comment-content markdown-body my-2" id="comment-content-<?= $comment['id'] ?>"><?= getCommentContentToDisplay($comment) ?></div>
|
||||||
<ul class="list-inline mb-0 text-end">
|
<ul class="list-inline mb-0 text-end">
|
||||||
<li class="list-inline-item small text-muted">
|
<li class="list-inline-item small text-muted">
|
||||||
<?= $comment['post_time'] ?>
|
<?= $comment['post_time'] ?>
|
||||||
@ -304,11 +332,11 @@ $comments_pag = new Paginator([
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<?php if ($replies) : ?>
|
<?php if ($replies) : ?>
|
||||||
<div id="replies-<?= $comment['id'] ?>" class="rounded bg-secondary bg-opacity-10 border"></div>
|
<div id="replies-<?= $comment['id'] ?>" class="rounded bg-secondary-subtle mt-2 border"></div>
|
||||||
|
<script>
|
||||||
|
showCommentReplies('<?= $comment['id'] ?>', <?= $replies_json ?>);
|
||||||
|
</script>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<script type="text/javascript">
|
|
||||||
showCommentReplies('<?= $comment['id'] ?>', <?= $replies_json ?>);
|
|
||||||
</script>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -318,7 +346,6 @@ $comments_pag = new Paginator([
|
|||||||
<?= $comments_pag->pagination() ?>
|
<?= $comments_pag->pagination() ?>
|
||||||
|
|
||||||
<h3 class="mt-4">发表评论</h3>
|
<h3 class="mt-4">发表评论</h3>
|
||||||
<p>可以用 @mike 来提到 mike 这个用户,mike 会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。</p>
|
|
||||||
<?php $comment_form->printHTML() ?>
|
<?php $comment_form->printHTML() ?>
|
||||||
|
|
||||||
<div id="div-form-reply" style="display:none">
|
<div id="div-form-reply" style="display:none">
|
||||||
@ -329,7 +356,7 @@ $comments_pag = new Paginator([
|
|||||||
$('.uoj-blog-hide-comment-btn').each(function() {
|
$('.uoj-blog-hide-comment-btn').each(function() {
|
||||||
$(this).click(function(event) {
|
$(this).click(function(event) {
|
||||||
var comment_id = $(this).data('comment-id');
|
var comment_id = $(this).data('comment-id');
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
toggleModalHideComment(comment_id, $('#comment-content-' + comment_id).html());
|
toggleModalHideComment(comment_id, $('#comment-content-' + comment_id).html());
|
||||||
});
|
});
|
||||||
|
@ -62,7 +62,7 @@ class UOJMarkdown extends ParsedownMath {
|
|||||||
$mentioned_user = UOJUser::query($matches[1]);
|
$mentioned_user = UOJUser::query($matches[1]);
|
||||||
|
|
||||||
if ($mentioned_user) {
|
if ($mentioned_user) {
|
||||||
$color = '#0d6efd';
|
$color = 'blue';
|
||||||
|
|
||||||
if ($this->options['username_with_color']) {
|
if ($this->options['username_with_color']) {
|
||||||
$color = UOJUser::getUserColor($mentioned_user);
|
$color = UOJUser::getUserColor($mentioned_user);
|
||||||
@ -74,7 +74,7 @@ class UOJMarkdown extends ParsedownMath {
|
|||||||
'name' => 'span',
|
'name' => 'span',
|
||||||
'text' => '@' . $mentioned_user['username'],
|
'text' => '@' . $mentioned_user['username'],
|
||||||
'attributes' => [
|
'attributes' => [
|
||||||
'class' => 'uoj-username',
|
'class' => "uoj-username uoj-username-{$color}",
|
||||||
'data-realname' => UOJUser::getRealname($mentioned_user),
|
'data-realname' => UOJUser::getRealname($mentioned_user),
|
||||||
'data-color' => $color,
|
'data-color' => $color,
|
||||||
],
|
],
|
||||||
|
@ -395,9 +395,6 @@ form.form-horizontal {
|
|||||||
/* Comments */
|
/* Comments */
|
||||||
|
|
||||||
.comment-content {
|
.comment-content {
|
||||||
white-space: pre-wrap;
|
|
||||||
word-break: break-all;
|
|
||||||
|
|
||||||
min-height: 50px;
|
min-height: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,6 +176,10 @@ $.fn.uoj_honor = function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getClickZanBlock(type, id, cnt, val) {
|
||||||
|
return '<div class="uoj-click-zan-block" data-id="' + id + '" data-type="' + type + '" data-val="' + val + '" data-cnt="' + cnt + '"></div>';
|
||||||
|
}
|
||||||
|
|
||||||
function showErrorHelp(name, err) {
|
function showErrorHelp(name, err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
$('#div-' + name).addClass('has-validation has-error');
|
$('#div-' + name).addClass('has-validation has-error');
|
||||||
@ -291,6 +295,11 @@ $.fn.click_zan_block = function() {
|
|||||||
var type = $(this).data('type');
|
var type = $(this).data('type');
|
||||||
var val = parseInt($(this).data('val'));
|
var val = parseInt($(this).data('val'));
|
||||||
var cnt = parseInt($(this).data('cnt'));
|
var cnt = parseInt($(this).data('cnt'));
|
||||||
|
var rendered = $(this).attr('data-click-zan-rendered');
|
||||||
|
|
||||||
|
if (rendered == 'true') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (isNaN(cnt)) {
|
if (isNaN(cnt)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -330,8 +339,9 @@ $.fn.click_zan_block = function() {
|
|||||||
var display_cnt = cnt > 0 ? '+' + cnt : cnt;
|
var display_cnt = cnt > 0 ? '+' + cnt : cnt;
|
||||||
|
|
||||||
if (cnt < 0) display_cnt = '-?';
|
if (cnt < 0) display_cnt = '-?';
|
||||||
|
|
||||||
$(this)
|
$(this)
|
||||||
|
.attr('data-click-zan-rendered', 'true')
|
||||||
.append(up_node)
|
.append(up_node)
|
||||||
.append(down_node)
|
.append(down_node)
|
||||||
.append($('<span class="uoj-click-zan-cnt" title="' + cnt + '">[<strong>' + display_cnt + '</strong>]</span>'));
|
.append($('<span class="uoj-click-zan-cnt" title="' + cnt + '">[<strong>' + display_cnt + '</strong>]</span>'));
|
||||||
@ -1707,25 +1717,41 @@ function showCommentReplies(id, replies) {
|
|||||||
function(reply) {
|
function(reply) {
|
||||||
return $('<tr id="' + 'comment-' + reply.id + '" />').append(
|
return $('<tr id="' + 'comment-' + reply.id + '" />').append(
|
||||||
$('<td />').append(
|
$('<td />').append(
|
||||||
$('<div class="comment-content">' + getUserLink(reply.poster, reply.poster_realname, reply.poster_username_color) + ':' + reply.content + '</div>')
|
$('<div class="d-flex" />').append(
|
||||||
).append(
|
$('<div class="d-none d-sm-block mr-3 flex-shrink-0" />').append(
|
||||||
$('<ul class="text-end mb-0 list-inline" />').append(
|
$('<a />').append(
|
||||||
'<li class="list-inline-item small text-muted">' + reply.post_time + '</li>'
|
$('<img class="rounded uoj-user-avatar" width="64" height="64" />').attr('src', reply.poster_avatar)
|
||||||
|
).attr('href', uojHome + '/user/' + reply.poster)
|
||||||
|
)
|
||||||
).append(
|
).append(
|
||||||
user_can_hide_comment
|
$('<div id="comment-body-' + reply.id + '" class="flex-grow-1 ms-3" />').append(
|
||||||
? $('<li class="list-inline-item" />').append(
|
$('<div class="row justify-content-between flex-wrap g-0" />').append(
|
||||||
$('<a href="#" class="text-warning-emphasis text-decoration-none p-0" />').data('comment-id', reply.id).text('隐藏').click(function(event) {
|
$('<div class="col-auto" />').append(getUserLink(reply.poster, reply.poster_realname, reply.poster_username_color))
|
||||||
event.preventDefault();
|
).append(
|
||||||
toggleModalHideComment(reply.id, reply.content);
|
$('<div class="col-auto" />').append(reply.click_zan_block)
|
||||||
})
|
)
|
||||||
|
).append(
|
||||||
|
$('<div class="comment-content markdown-body my-2" />').attr('id', 'comment-content-' + reply.id).html(reply.content)
|
||||||
|
).append(
|
||||||
|
$('<ul class="text-end mb-0 list-inline" />').append(
|
||||||
|
'<li class="list-inline-item small text-muted">' + reply.post_time + '</li>'
|
||||||
|
).append(
|
||||||
|
user_can_hide_comment
|
||||||
|
? $('<li class="list-inline-item" />').append(
|
||||||
|
$('<a href="#" class="text-warning-emphasis text-decoration-none p-0" />').data('comment-id', reply.id).text('隐藏').click(function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
toggleModalHideComment(reply.id, reply.content);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
: ''
|
||||||
|
).append(
|
||||||
|
$('<li class="list-inline-item" />').append(
|
||||||
|
$('<a href="#">回复</a>').click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
toggleFormReply(reply.id, '回复 @' + reply.poster + ':');
|
||||||
|
})
|
||||||
|
)
|
||||||
)
|
)
|
||||||
: ''
|
|
||||||
).append(
|
|
||||||
$('<li class="list-inline-item" />').append(
|
|
||||||
$('<a href="#">回复</a>').click(function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
toggleFormReply(reply.id, '回复 @' + reply.poster + ':');
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user