Display all newer comments after current comment (#5981)

* Display all newer comments after current comment

* Implement links to display previous and next comments

* Fix sub-comments display of the current parent comment

* Improve styles for sub-comments of current comment

Co-authored-by: Lucas Bartholemy <luke-@users.noreply.github.com>
This commit is contained in:
Yuriy Bakhtin 2023-01-20 18:24:33 +04:00 committed by GitHub
parent 9d88da246a
commit 9ac30de56f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 174 additions and 121 deletions

View File

@ -11,3 +11,4 @@ HumHub Changelog (DEVELOP)
- Ehn #6017: Hide Password Tab in administration for LDAP users - Ehn #6017: Hide Password Tab in administration for LDAP users
- Enh #6031: On users list grid, show Auth mode badge only for sys admins - Enh #6031: On users list grid, show Auth mode badge only for sys admins
- Enh #6035: Added Estonian language - Enh #6035: Added Estonian language
- Fix #5956: Display all newer comments after current comment

View File

@ -23,8 +23,6 @@ use humhub\modules\comment\widgets\ShowMore;
use humhub\modules\content\components\ContentActiveRecord; use humhub\modules\content\components\ContentActiveRecord;
use humhub\modules\file\handler\FileHandlerCollection; use humhub\modules\file\handler\FileHandlerCollection;
use Yii; use Yii;
use yii\base\BaseObject;
use yii\data\Pagination;
use yii\helpers\Url; use yii\helpers\Url;
use yii\web\BadRequestHttpException; use yii\web\BadRequestHttpException;
use yii\web\ForbiddenHttpException; use yii\web\ForbiddenHttpException;
@ -89,31 +87,35 @@ class CommentController extends Controller
*/ */
public function actionShow() public function actionShow()
{ {
//TODO: Dont use query logic in controller layer... $commentId = (int) Yii::$app->request->get('commentId');
$type = Yii::$app->request->get('type', ShowMore::TYPE_PREVIOUS);
$query = Comment::find(); $pageSize = (int) Yii::$app->request->get('pageSize', $this->module->commentsBlockLoadSize);
$query->orderBy('created_at DESC'); if ($pageSize > $this->module->commentsBlockLoadSize) {
$query->where(['object_model' => get_class($this->target), 'object_id' => $this->target->getPrimaryKey()]); $pageSize = $this->module->commentsBlockLoadSize;
$pagination = new Pagination([
'totalCount' => Comment::GetCommentCount(get_class($this->target), $this->target->getPrimaryKey()),
'pageSize' => Yii::$app->request->get('pageSize', $this->module->commentsBlockLoadSize)
]);
// If need to load more than 1 page per request
$pageNum = Yii::$app->request->get('pageNum', 1);
$query->offset($pagination->offset)->limit($pagination->limit * $pageNum);
$comments = array_reverse($query->all());
if ($pageNum > 1) {
$pagination->setPage($pagination->page + $pageNum - 1);
} }
$output = ShowMore::widget(['pagination' => $pagination, 'object' => $this->target]); $comments = Comment::getMoreComments($this->target, $commentId, $type, $pageSize);
$output = '';
if ($type === ShowMore::TYPE_PREVIOUS) {
$output .= ShowMore::widget([
'object' => $this->target,
'pageSize' => $pageSize,
'commentId' => isset($comments[0]) ? $comments[0]->id : null,
'type' => $type,
]);
}
foreach ($comments as $comment) { foreach ($comments as $comment) {
$output .= CommentWidget::widget(['comment' => $comment]); $output .= CommentWidget::widget(['comment' => $comment]);
} }
if ($type === ShowMore::TYPE_NEXT && count($comments) > 1) {
$output .= ShowMore::widget([
'object' => $this->target,
'pageSize' => $pageSize,
'commentId' => $comments[count($comments)-1]->id,
'type' => $type,
]);
}
if (Yii::$app->request->get('mode') === 'popup') { if (Yii::$app->request->get('mode') === 'popup') {
return $this->renderAjax('showPopup', ['object' => $this->target, 'output' => $output, 'id' => $this->target->content->getUniqueId()]); return $this->renderAjax('showPopup', ['object' => $this->target, 'output' => $output, 'id' => $this->target->content->getUniqueId()]);

View File

@ -13,6 +13,7 @@ use humhub\modules\comment\activities\NewComment;
use humhub\modules\comment\live\NewComment as NewCommentLive; use humhub\modules\comment\live\NewComment as NewCommentLive;
use humhub\modules\comment\Module; use humhub\modules\comment\Module;
use humhub\modules\comment\notifications\NewComment as NewCommentNotification; use humhub\modules\comment\notifications\NewComment as NewCommentNotification;
use humhub\modules\comment\widgets\ShowMore;
use humhub\modules\content\components\ContentActiveRecord; use humhub\modules\content\components\ContentActiveRecord;
use humhub\modules\content\components\ContentAddonActiveRecord; use humhub\modules\content\components\ContentAddonActiveRecord;
use humhub\modules\content\interfaces\ContentOwner; use humhub\modules\content\interfaces\ContentOwner;
@ -217,6 +218,10 @@ class Comment extends ContentAddonActiveRecord implements ContentOwner
$limit = $module->commentsPreviewMax; $limit = $module->commentsPreviewMax;
} }
if ($model === self::class && $currentCommentId == $id) {
// No need to find current comment in sub-comments when parent comment is the current
$currentCommentId = null;
}
$currentCommentId = intval($currentCommentId); $currentCommentId = intval($currentCommentId);
$useCaching = empty($currentCommentId);// No need to cache comments for deep single comment view $useCaching = empty($currentCommentId);// No need to cache comments for deep single comment view
@ -230,6 +235,7 @@ class Comment extends ContentAddonActiveRecord implements ContentOwner
$objectCondition = ['object_model' => $model, 'object_id' => $id]; $objectCondition = ['object_model' => $model, 'object_id' => $id];
$query = Comment::find(); $query = Comment::find();
if ($currentCommentId && Comment::findOne(['id' => $currentCommentId])) { if ($currentCommentId && Comment::findOne(['id' => $currentCommentId])) {
// Get the current and one previous comment
$nearCommentIds = Comment::find() $nearCommentIds = Comment::find()
->select('id') ->select('id')
->where($objectCondition) ->where($objectCondition)
@ -237,16 +243,15 @@ class Comment extends ContentAddonActiveRecord implements ContentOwner
->orderBy('created_at DESC') ->orderBy('created_at DESC')
->limit($limit) ->limit($limit)
->column(); ->column();
if (count($nearCommentIds) < $limit) { // Get 1 newer comment after the current comment
$newerCommentIds = Comment::find() $newerCommentIds = Comment::find()
->select('id') ->select('id')
->where($objectCondition) ->where($objectCondition)
->andWhere(['>', 'id', $currentCommentId]) ->andWhere(['>', 'id', $currentCommentId])
->orderBy('created_at ASC') ->orderBy('created_at ASC')
->limit($limit - count($nearCommentIds)) ->limit(1)
->column(); ->column();
$nearCommentIds = array_merge($nearCommentIds, $newerCommentIds); $nearCommentIds = array_merge($nearCommentIds, $newerCommentIds);
}
$query->where(['IN', 'id', $nearCommentIds]); $query->where(['IN', 'id', $nearCommentIds]);
} else { } else {
$query->where($objectCondition); $query->where($objectCondition);
@ -284,6 +289,44 @@ class Comment extends ContentAddonActiveRecord implements ContentOwner
return $commentCount; return $commentCount;
} }
/**
* Find more comments before or after a requested comment
*
* @param int|null $commentId ID of the latest comment from previous query
* @param string|null $type
* @param int|null $pageSize
* @param Comment|ContentActiveRecord
* @return Comment[]
*/
public static function getMoreComments($object, ?int $commentId = null, ?string $type = null, ?int $pageSize = null): array
{
if (!$pageSize) {
/** @var Module $module */
$module = Yii::$app->getModule('comment');
$pageSize = $module->commentsBlockLoadSize;
}
$query = Comment::find()
->where(['object_model' => get_class($object), 'object_id' => $object->getPrimaryKey()])
->limit($pageSize);
if ($type === ShowMore::TYPE_NEXT) {
$query->orderBy(['created_at' => SORT_ASC]);
if ($commentId) {
$query->andWhere(['>', 'id', $commentId]);
}
$comments = $query->all();
} else {
$query->orderBy(['created_at' => SORT_DESC]);
if ($commentId) {
$query->andWhere(['<', 'id', $commentId]);
}
$comments = array_reverse($query->all());
}
return $comments;
}
/** /**
* @inheritdoc * @inheritdoc
*/ */

View File

@ -235,16 +235,6 @@ humhub.module('comment', function (module, require, $) {
}); });
}; };
var showAll = function (evt) {
client.post(evt, {dataType: 'html'}).then(function (response) {
var $container = evt.$trigger.parent();
$container.html(response.html);
additions.applyTo($container);
}).catch(function (err) {
module.log.error(err, true);
});
};
var showMore = function (evt) { var showMore = function (evt) {
loader.set(evt.$trigger, { loader.set(evt.$trigger, {
'size': '8px', 'size': '8px',
@ -256,7 +246,9 @@ humhub.module('comment', function (module, require, $) {
client.post(evt, {dataType: 'html'}).then(function (response) { client.post(evt, {dataType: 'html'}).then(function (response) {
var $container = evt.$trigger.closest('.comment'); var $container = evt.$trigger.closest('.comment');
var $html = $(response.html); var $html = $(response.html);
$container.prepend($html); evt.$trigger.data('type') === 'previous'
? $container.prepend($html)
: $container.append($html);
evt.$trigger.closest('.showMore').remove(); evt.$trigger.closest('.showMore').remove();
additions.applyTo($html); additions.applyTo($html);
}).catch(function (err) { }).catch(function (err) {
@ -345,7 +337,6 @@ humhub.module('comment', function (module, require, $) {
Form: Form, Form: Form,
scrollActive: scrollActive, scrollActive: scrollActive,
scrollInactive: scrollInactive, scrollInactive: scrollInactive,
showAll: showAll,
showMore: showMore, showMore: showMore,
toggleComment: toggleCommentHandler toggleComment: toggleCommentHandler
}); });

View File

@ -9,7 +9,6 @@ use humhub\components\Widget;
use humhub\modules\content\widgets\stream\StreamEntryOptions; use humhub\modules\content\widgets\stream\StreamEntryOptions;
use humhub\modules\content\widgets\stream\WallStreamEntryOptions; use humhub\modules\content\widgets\stream\WallStreamEntryOptions;
use Yii; use Yii;
use yii\helpers\Url;
/** /**
* This widget is used include the comments functionality to a wall entry. * This widget is used include the comments functionality to a wall entry.
@ -81,9 +80,6 @@ class Comments extends Widget
'comments' => $comments, 'comments' => $comments,
'currentCommentId' => $currentCommentId, 'currentCommentId' => $currentCommentId,
'id' => $this->object->getUniqueId(), 'id' => $this->object->getUniqueId(),
'isLimited' => $commentCount > $this->limit,
'total' => $commentCount,
'showMoreUrl' => $this->getShowMoreUrl(),
]); ]);
} }
@ -102,20 +98,4 @@ class Comments extends Widget
{ {
return $this->isFullViewMode() ? $this->module->commentsBlockLoadSizeViewMode : $this->module->commentsBlockLoadSize; return $this->isFullViewMode() ? $this->module->commentsBlockLoadSizeViewMode : $this->module->commentsBlockLoadSize;
} }
private function getShowMoreUrl(): string
{
$urlParams = ['/comment/comment/show',
'objectModel' => get_class($this->object),
'objectId' => $this->object->getPrimaryKey(),
'pageSize' => $this->pageSize,
];
if ($this->pageSize <= $this->limit) {
// We should load second page together with first because on init page we already see the first page
$urlParams['pageNum'] = 2;
}
return Url::to($urlParams);
}
} }

View File

@ -2,16 +2,23 @@
namespace humhub\modules\comment\widgets; namespace humhub\modules\comment\widgets;
use humhub\modules\comment\models\Comment;
use Yii;
use yii\base\Widget;
use yii\helpers\Url; use yii\helpers\Url;
/** /**
* CommentsShowMoreWidget * CommentsShowMoreWidget
* *
* @property-read int $count
*
* @since 0.11 * @since 0.11
* @author luke * @author luke
*/ */
class ShowMore extends \yii\base\Widget class ShowMore extends Widget
{ {
const TYPE_PREVIOUS = 'previous';
const TYPE_NEXT = 'next';
/** /**
* Content Object * Content Object
@ -19,40 +26,61 @@ class ShowMore extends \yii\base\Widget
public $object; public $object;
/** /**
* @var \yii\data\Pagination; * @var int
*/ */
public $pagination; public $pageSize;
/**
* @var string Type of loaded comments: 'previous', 'next'
*/
public $type = self::TYPE_PREVIOUS;
/**
* @var int|null ID of the latest comment from previous query
*/
public $commentId;
/**
* @var int Cached count of the next/previous comments
*/
private $_count;
/** /**
* Executes the widget. * Executes the widget.
*/ */
public function run() public function run()
{ {
if (!$this->count) {
if (!$this->pagination->totalCount || $this->pagination->pageCount == $this->pagination->page + 1) {
return ''; return '';
} }
$showMoreUrl = Url::to([
'/comment/comment/show',
'objectModel' => get_class($this->object),
'objectId' => $this->object->getPrimaryKey(),
'pageSize' => $this->pagination->pageSize,
'page' => $this->pagination->page + 2
]);
$moreCount = $this->pagination->pageSize;
if ($this->pagination->pageCount == $this->pagination->page + 2) {
$moreCount = $this->pagination->totalCount - $this->pagination->pageSize - $this->pagination->offset;
}
return $this->render('showMore', [ return $this->render('showMore', [
'object' => $this->object, 'text' => $this->getText(),
'pagination' => $this->pagination, 'showMoreUrl' => Url::to(['/comment/comment/show',
'id' => $this->object->getUniqueId(), 'objectModel' => get_class($this->object),
'showMoreUrl' => $showMoreUrl, 'objectId' => $this->object->getPrimaryKey(),
'moreCount' => $moreCount 'pageSize' => $this->pageSize,
'commentId' => $this->commentId,
'type' => $this->type,
]),
'type' => $this->type,
]); ]);
} }
private function getText(): string
{
return $this->type === self::TYPE_PREVIOUS
? Yii::t('CommentModule.base', "Show previous {count} comments", ['{count}' => $this->count])
: Yii::t('CommentModule.base', "Show next {count} comments", ['{count}' => $this->count]);
}
public function getCount(): int
{
if ($this->_count === null) {
$this->_count = count(Comment::getMoreComments($this->object, $this->commentId, $this->type, $this->pageSize));
}
return $this->_count;
}
} }

View File

@ -1,30 +1,26 @@
<?php <?php
use humhub\modules\comment\widgets\Form;
use humhub\modules\comment\widgets\Comment;
use humhub\libs\Html; use humhub\libs\Html;
use humhub\modules\comment\models\Comment as CommentModel;
use humhub\modules\comment\widgets\Comment;
use humhub\modules\comment\widgets\Form;
use humhub\modules\comment\widgets\ShowMore;
use humhub\modules\content\components\ContentActiveRecord;
/* @var $this \humhub\modules\ui\view\components\View */ /* @var $object ContentActiveRecord|CommentModel */
/* @var $object \humhub\modules\content\components\ContentActiveRecord */ /* @var $comments CommentModel[] */
/* @var $comments \humhub\modules\comment\models\Comment[] */
/* @var $currentCommentId int */ /* @var $currentCommentId int */
/* @var $id string unqiue object id */ /* @var $id string unqiue object id */
/* @var $isLimited boolean */
/* @var $total int */
/* @var $showMoreUrl string */
?> ?>
<div class="well well-small comment-container" style="display:none;" id="comment_<?= $id; ?>"> <div class="well well-small comment-container" style="display:none;" id="comment_<?= $id; ?>">
<div class="comment <?php if (Yii::$app->user->isGuest): ?>guest-mode<?php endif; ?>" <div class="comment <?php if (Yii::$app->user->isGuest): ?>guest-mode<?php endif; ?>"
id="comments_area_<?= $id; ?>"> id="comments_area_<?= $id; ?>">
<?php if ($isLimited): ?> <?= ShowMore::widget([
<a href="#" class="show show-all-link" data-ui-loader data-action-click="comment.showAll" 'object' => $object,
data-action-url="<?= $showMoreUrl ?>"> 'commentId' => isset($comments[0]) ? $comments[0]->id : null,
<?= Yii::t('CommentModule.base', 'Show all {total} comments', ['{total}' => $total]) ?> 'type' => ShowMore::TYPE_PREVIOUS,
</a> ]); ?>
<hr class="comments-start-separator">
<?php endif; ?>
<?php foreach ($comments as $comment) : ?> <?php foreach ($comments as $comment) : ?>
<?= Comment::widget([ <?= Comment::widget([
@ -32,6 +28,14 @@ use humhub\libs\Html;
'additionalClass' => ($currentCommentId == $comment->id ? 'comment-current' : ''), 'additionalClass' => ($currentCommentId == $comment->id ? 'comment-current' : ''),
]); ?> ]); ?>
<?php endforeach; ?> <?php endforeach; ?>
<?php if ($currentCommentId && count($comments) > 1) : ?>
<?= ShowMore::widget([
'object' => $object,
'commentId' => $comments[count($comments)-1]->id,
'type' => ShowMore::TYPE_NEXT,
]); ?>
<?php endif; ?>
</div> </div>
<?= Form::widget(['object' => $object]); ?> <?= Form::widget(['object' => $object]); ?>

View File

@ -1,12 +1,15 @@
<?php <?php
/* @var $this \humhub\modules\ui\view\components\View */ use humhub\modules\comment\widgets\ShowMore;
/* @var $moreCount int */ use humhub\widgets\Link;
/* @var $showMoreUrl string */
/* @var $text string */
/* @var $showMoreUrl string */
/* @var $type string */
?> ?>
<div class="showMore"> <div class="showMore">
<a href="#" data-action-click="comment.showMore" data-action-url="<?= $showMoreUrl ?>"> <?php if ($type == ShowMore::TYPE_NEXT) : ?>
<?= Yii::t('CommentModule.base', "Show {count} more comments", ['{count}' => $moreCount]) ?> <hr class="comment-separator">
</a> <?php endif; ?>
<?= Link::withAction($text, 'comment.showMore', $showMoreUrl)->options(['data-type' => $type]) ?>
</div> </div>

View File

@ -50,6 +50,16 @@
> .nav.preferences { > .nav.preferences {
margin-right: 10px; margin-right: 10px;
} }
.nested-comments-root {
.comment-container {
margin-top: 5px;
padding-bottom: 10px;
.showMore {
margin-top: 0;
padding-top: 5px;
}
}
}
} }
} }
@ -190,10 +200,6 @@ div.comment > div.media:first-of-type {
} }
} }
hr.comments-start-separator {
margin-top: 10px;
}
div.nested-comments-root { div.nested-comments-root {
margin-left: 28px; margin-left: 28px;
@ -205,11 +211,7 @@ div.nested-comments-root {
display: inherit !important; display: inherit !important;
} }
hr.comments-start-separator { .showMore {
display: none;
}
a.show-all-link {
margin-top: 10px; margin-top: 10px;
} }

View File

@ -226,9 +226,8 @@
margin-bottom: 0; margin-bottom: 0;
.comment { .comment {
.show-all-link { .showMore a {
font-size: 12px; font-size: 12px;
cursor: pointer;
} }
} }
} }

File diff suppressed because one or more lines are too long