#495 comments pagination
This commit is contained in:
parent
4007f93cc4
commit
1e4527591c
@ -34,6 +34,8 @@
|
||||
btshmr(@Model.GanjoorPage.Id);
|
||||
}
|
||||
checkIfBookmarked(@Model.GanjoorPage.Id);
|
||||
paginateComments();
|
||||
revealCommentFromUrlHash();
|
||||
});
|
||||
</script>
|
||||
}
|
||||
|
||||
@ -130,6 +130,67 @@ namespace GanjooRazor.Pages
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// re-fetch a poem's comments sorted by rating or by date (AJAX, called from sortComments() in bk.js)
|
||||
/// </summary>
|
||||
public async Task<IActionResult> OnGetCommentsPartialAsync(int poemId, bool sortByRanking = true)
|
||||
{
|
||||
var response = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poem/{poemId}/comments?sortByRanking={sortByRanking}");
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
return BadRequest(await ReadErrorMessageAsync(response));
|
||||
}
|
||||
var comments = JArray.Parse(await response.Content.ReadAsStringAsync()).ToObject<GanjoorCommentSummaryViewModel[]>();
|
||||
|
||||
LoggedIn = !string.IsNullOrEmpty(Request.Cookies["Token"]);
|
||||
|
||||
if (!string.IsNullOrEmpty(Request.Cookies["UserId"])
|
||||
&& Guid.TryParse(Request.Cookies["UserId"], out Guid userId)
|
||||
&& userId != Guid.Empty)
|
||||
{
|
||||
using (HttpClient secureClient = new HttpClient())
|
||||
{
|
||||
if (await GanjoorSessionChecker.PrepareClient(secureClient, Request, Response))
|
||||
{
|
||||
GanjoorUserBookmarkViewModel[] bookmarks = Array.Empty<GanjoorUserBookmarkViewModel>();
|
||||
HttpResponseMessage bookmarksResponse = await secureClient.GetAsync($"{APIRoot.Url}/api/ganjoor/bookmark/{poemId}");
|
||||
if (bookmarksResponse.IsSuccessStatusCode)
|
||||
{
|
||||
bookmarks = JsonConvert.DeserializeObject<GanjoorUserBookmarkViewModel[]>(await bookmarksResponse.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
foreach (GanjoorCommentSummaryViewModel comment in comments)
|
||||
{
|
||||
comment.MyComment = comment.UserId == userId;
|
||||
comment.IsBookmarked = bookmarks.Where(b => b.CoupletIndex == -comment.Id).Any();
|
||||
_markMyReplies(comment, userId, bookmarks);
|
||||
}
|
||||
|
||||
HttpResponseMessage ratingsResponse = await secureClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poem/{poemId}/comments/myratings");
|
||||
if (ratingsResponse.IsSuccessStatusCode)
|
||||
{
|
||||
var ratings = JsonConvert.DeserializeObject<GanjoorCommentUserRatingViewModel[]>(await ratingsResponse.Content.ReadAsStringAsync());
|
||||
if (ratings.Length > 0)
|
||||
{
|
||||
var ratingsDic = ratings.ToDictionary(r => r.CommentId, r => r.Value);
|
||||
foreach (GanjoorCommentSummaryViewModel comment in comments)
|
||||
{
|
||||
_applyCommentRatings(comment, ratingsDic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Partial("~/Pages/Partials/GanjoorPage/_CommentsListPartial.cshtml", new _CommentsListPartialModel()
|
||||
{
|
||||
Comments = comments,
|
||||
PoemId = poemId,
|
||||
LoggedIn = LoggedIn,
|
||||
});
|
||||
}
|
||||
|
||||
public Task<IActionResult> OnPostReply(string replyCommentText, int refPoemId, int refCommentId)
|
||||
{
|
||||
return OnPostComment(replyCommentText, refPoemId, refCommentId, -1);
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
font-family: 'Vazirmatn'
|
||||
}
|
||||
</style>
|
||||
<script src="/js/bk.js?version=83"></script>
|
||||
<script src="/js/bk.js?version=86"></script>
|
||||
<script src="~/js/jquery-1.10.2.min.js"></script>
|
||||
<script src="~/js/leaflet.js"></script>
|
||||
<script src="~/js/leaflet-providers.js"></script>
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
<link rel="shortcut icon" href="/favicon.ico?version=1" type="image/x-icon" />
|
||||
<link rel="search" type="application/opensearchdescription+xml" title="گنجور" href="https://ganjoor.net/search.xml" />
|
||||
<script src="/lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="/js/bk.js?version=83"></script>
|
||||
<script src="/js/bk.js?version=86"></script>
|
||||
<script>
|
||||
var cookieValue = getCookie("playerScrollLock");
|
||||
var playerScrollLock = cookieValue === "true";
|
||||
|
||||
@ -872,30 +872,16 @@
|
||||
</div>
|
||||
<div class="related-images-frame poemtabcontent">
|
||||
<div id="comments-section">
|
||||
@switch (Model.GanjoorPage.Poem.Comments.Length)
|
||||
@if (Model.GanjoorPage.Poem.Comments.Length > 1)
|
||||
{
|
||||
case 0:
|
||||
<p>
|
||||
تا به حال حاشیهای برای این شعر نوشته نشده است. <a href="#commentform" class="comments-link" title="من حاشیه بگذارم ...">💬 من حاشیه بگذارم ...</a>
|
||||
</p>
|
||||
break;
|
||||
case 1:
|
||||
<p>
|
||||
تا به حال یک حاشیه برای این شعر نوشته شده است. <a href="#commentform" class="comments-link" title="من حاشیه بگذارم ...">💬 من حاشیه بگذارم ...</a>
|
||||
</p>
|
||||
break;
|
||||
default:
|
||||
<p>
|
||||
تا به حال @Html.Raw(Model.GanjoorPage.Poem.Comments.Length.ToPersianNumbers()) حاشیه برای این شعر نوشته شده است. <a href="#commentform" class="comments-link" title="من حاشیه بگذارم ...">💬 من حاشیه بگذارم ...</a>
|
||||
</p>
|
||||
break;
|
||||
<p class="comments-sort-toggle">
|
||||
مرتبسازی حاشیهها:
|
||||
<a role="button" class="cursor-pointer" onclick="sortComments(@Model.GanjoorPage.Id, true)">محبوبترین</a> |
|
||||
<a role="button" class="cursor-pointer" onclick="sortComments(@Model.GanjoorPage.Id, false)">تازهترین</a>
|
||||
</p>
|
||||
}
|
||||
|
||||
<div id="comments-block">
|
||||
@foreach (var comment in Model.GanjoorPage.Poem.Comments)
|
||||
{
|
||||
<partial name="~/Pages/Partials/GanjoorPage/_CommentPartial.cshtml" model=@Model.GetCommentModel(comment, Model.GanjoorPage.Id) />
|
||||
}
|
||||
<div id="comments-list-wrapper">
|
||||
<partial name="~/Pages/Partials/GanjoorPage/_CommentsListPartial.cshtml" model=@(new GanjooRazor.Pages._CommentsListPartialModel() { Comments = Model.GanjoorPage.Poem.Comments, PoemId = Model.GanjoorPage.Id, LoggedIn = Model.LoggedIn }) />
|
||||
</div>
|
||||
|
||||
@if (Model.LoggedIn)
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
@model GanjooRazor.Pages._CommentsListPartialModel
|
||||
@using DNTPersianUtils.Core
|
||||
@{
|
||||
Layout = null;
|
||||
}
|
||||
|
||||
@switch (Model.Comments.Length)
|
||||
{
|
||||
case 0:
|
||||
<p>
|
||||
تا به حال حاشیهای برای این شعر نوشته نشده است. <a href="#commentform" class="comments-link" title="من حاشیه بگذارم ...">💬 من حاشیه بگذارم ...</a>
|
||||
</p>
|
||||
break;
|
||||
case 1:
|
||||
<p>
|
||||
تا به حال یک حاشیه برای این شعر نوشته شده است. <a href="#commentform" class="comments-link" title="من حاشیه بگذارم ...">💬 من حاشیه بگذارم ...</a>
|
||||
</p>
|
||||
break;
|
||||
default:
|
||||
<p>
|
||||
تا به حال @Html.Raw(Model.Comments.Length.ToPersianNumbers()) حاشیه برای این شعر نوشته شده است. <a href="#commentform" class="comments-link" title="من حاشیه بگذارم ...">💬 من حاشیه بگذارم ...</a>
|
||||
</p>
|
||||
break;
|
||||
}
|
||||
|
||||
<div id="comments-block">
|
||||
@foreach (var comment in Model.Comments)
|
||||
{
|
||||
<partial name="~/Pages/Partials/GanjoorPage/_CommentPartial.cshtml" model=Model.GetCommentModel(comment) />
|
||||
}
|
||||
</div>
|
||||
@ -0,0 +1,29 @@
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using RMuseum.Models.Ganjoor.ViewModels;
|
||||
|
||||
namespace GanjooRazor.Pages
|
||||
{
|
||||
/// <summary>
|
||||
/// Model for the comments list + count message shared between the initial page render
|
||||
/// (_PoemPagePartial.cshtml) and the AJAX sort-toggle refresh (OnGetCommentsPartialAsync).
|
||||
/// </summary>
|
||||
public class _CommentsListPartialModel : PageModel
|
||||
{
|
||||
public GanjoorCommentSummaryViewModel[] Comments { get; set; }
|
||||
public int PoemId { get; set; }
|
||||
public bool LoggedIn { get; set; }
|
||||
|
||||
public _CommentPartialModel GetCommentModel(GanjoorCommentSummaryViewModel comment)
|
||||
{
|
||||
return new _CommentPartialModel()
|
||||
{
|
||||
Comment = comment,
|
||||
Error = "",
|
||||
InReplyTo = null,
|
||||
LoggedIn = LoggedIn,
|
||||
DivSuffix = "",
|
||||
PoemId = PoemId,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -150,7 +150,7 @@
|
||||
</p>
|
||||
|
||||
<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="~/js/bk.js?version=83"></script>
|
||||
<script src="~/js/bk.js?version=86"></script>
|
||||
<script src="~/js/jplayersupport.js"></script>
|
||||
<script src="~/js/vaabd.js?version=10"></script>
|
||||
<script src="~/dist/jplayer/jquery.jplayer.min.js"></script>
|
||||
|
||||
@ -238,7 +238,7 @@
|
||||
|
||||
|
||||
|
||||
<script src="~/js/bk.js?version=83"></script>
|
||||
<script src="~/js/bk.js?version=86"></script>
|
||||
<script src="~/js/jplayersupport.js"></script>
|
||||
<script src="~/js/vaabd.js?version=10"></script>
|
||||
<script src="~/dist/jplayer/jquery.jplayer.min.js"></script>
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<script src="/js/bk.js?version=83"></script>
|
||||
<script src="/js/bk.js?version=86"></script>
|
||||
<script>
|
||||
function editBanner(bannerId) {
|
||||
var url = '?handler=Edit';
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
<link rel="shortcut icon" href="/favicon.ico?version=1" type="image/x-icon" />
|
||||
<link rel="search" type="application/opensearchdescription+xml" title="گنجور" href="https://ganjoor.net/search.xml" />
|
||||
<script src="/lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="/js/bk.js?version=83"></script>
|
||||
<script src="/js/bk.js?version=86"></script>
|
||||
<script>
|
||||
var cookieValue = getCookie("playerScrollLock");
|
||||
var playerScrollLock = cookieValue === "true";
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
});
|
||||
</script>
|
||||
<script src="/lib/diff.js"></script>
|
||||
<script src="/js/bk.js?version=83"></script>
|
||||
<script src="/js/bk.js?version=86"></script>
|
||||
<script>
|
||||
function compareCorrectionBlocks(originalElemenyId, editedElementId, resultElementId) {
|
||||
var a = document.getElementById(originalElemenyId);
|
||||
|
||||
@ -504,6 +504,98 @@ function switchBookmarkInternal(poemId, coupletIndex, divSuffix) {
|
||||
});
|
||||
}
|
||||
|
||||
function sortComments(poemId, sortByRanking) {
|
||||
var wrapper = document.getElementById('comments-list-wrapper');
|
||||
if (wrapper == null) return;
|
||||
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: '?handler=CommentsPartial&poemId=' + String(poemId) + '&sortByRanking=' + String(sortByRanking),
|
||||
error: function (err) {
|
||||
alert('خطا در بارگذاری حاشیهها: ' + err.responseText);
|
||||
},
|
||||
success: function (html) {
|
||||
wrapper.innerHTML = html;
|
||||
paginateComments();
|
||||
revealCommentFromUrlHash();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
var COMMENTS_PAGE_SIZE = 15;
|
||||
|
||||
function paginateComments() {
|
||||
var block = document.getElementById('comments-block');
|
||||
if (block == null) return;
|
||||
|
||||
var existingButton = document.getElementById('comments-show-more');
|
||||
if (existingButton != null) existingButton.remove();
|
||||
|
||||
// only direct children: root comments. Replies live nested inside each root's
|
||||
// own div, so they're never touched by pagination - a full reply thread always
|
||||
// stays together with its root.
|
||||
var roots = Array.prototype.filter.call(block.children, function (el) {
|
||||
return el.classList.contains('ganjoor-comment');
|
||||
});
|
||||
|
||||
for (var i = 0; i < roots.length; i++) {
|
||||
roots[i].style.display = '';
|
||||
}
|
||||
|
||||
if (roots.length <= COMMENTS_PAGE_SIZE) return;
|
||||
|
||||
var shown = COMMENTS_PAGE_SIZE;
|
||||
for (var i = shown; i < roots.length; i++) {
|
||||
roots[i].style.display = 'none';
|
||||
}
|
||||
|
||||
var button = document.createElement('a');
|
||||
button.id = 'comments-show-more';
|
||||
button.setAttribute('role', 'button');
|
||||
button.className = 'cursor-pointer comments-link';
|
||||
button.innerText = 'نمایش حاشیههای بیشتر (' + toPersianNumber(roots.length - shown) + ' مورد دیگر)';
|
||||
button.onclick = function () {
|
||||
var nextShown = shown + COMMENTS_PAGE_SIZE;
|
||||
for (var i = shown; i < Math.min(nextShown, roots.length); i++) {
|
||||
roots[i].style.display = '';
|
||||
}
|
||||
shown = nextShown;
|
||||
if (shown >= roots.length) {
|
||||
button.remove();
|
||||
} else {
|
||||
button.innerText = 'نمایش حاشیههای بیشتر (' + toPersianNumber(roots.length - shown) + ' مورد دیگر)';
|
||||
}
|
||||
};
|
||||
block.parentNode.insertBefore(button, block.nextSibling);
|
||||
}
|
||||
|
||||
// Hashieha.cshtml, MyComments.cshtml, and copyCommentUrl() all link straight to
|
||||
// #comment-<id>. Pagination can hide that target (or, if it's a reply, hide its whole
|
||||
// parent thread, since only root comments get display:none) - the browser's native
|
||||
// anchor-scroll runs before paginateComments() and silently fails against a hidden
|
||||
// element, so this reveals the right root and scrolls to it explicitly afterwards.
|
||||
function revealCommentFromUrlHash() {
|
||||
if (!/^#comment-\d/.test(location.hash)) return;
|
||||
|
||||
var target = document.querySelector(location.hash);
|
||||
if (target == null) return;
|
||||
|
||||
var block = document.getElementById('comments-block');
|
||||
if (block != null) {
|
||||
var el = target;
|
||||
while (el != null && el.parentElement !== block) {
|
||||
el = el.parentElement;
|
||||
}
|
||||
if (el != null) {
|
||||
el.style.display = '';
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
target.scrollIntoView();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function rateComment(commentId, value, loggedIn, divSuffix) {
|
||||
if (!loggedIn) {
|
||||
alert('برای رأی دادن به حاشیهها لازم است با نام کاربری خود وارد گنجور شوید.');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user