change comment style
This commit is contained in:
parent
2bd0e41653
commit
d7672cf81b
9 changed files with 272 additions and 124 deletions
|
@ -1,5 +1,6 @@
|
|||
import chat_box.views as chat
|
||||
|
||||
from django.urls import include, path
|
||||
from django.conf import settings
|
||||
from django.conf.urls import include, url
|
||||
from django.contrib import admin
|
||||
|
@ -468,6 +469,8 @@ urlpatterns = [
|
|||
url(r"^comments/upvote/$", comment.upvote_comment, name="comment_upvote"),
|
||||
url(r"^comments/downvote/$", comment.downvote_comment, name="comment_downvote"),
|
||||
url(r"^comments/hide/$", comment.comment_hide, name="comment_hide"),
|
||||
url(r"^comments/reply/$", comment.get_reply, name="comment_reply"),
|
||||
url(r"^comments/showmore/$", comment.get_showmore, name="comment_show_more"),
|
||||
url(
|
||||
r"^comments/(?P<id>\d+)/",
|
||||
include(
|
||||
|
|
|
@ -162,14 +162,14 @@ class CommentedDetailView(TemplateResponseMixin, SingleObjectMixin, View):
|
|||
def get_context_data(self, **kwargs):
|
||||
context = super(CommentedDetailView, self).get_context_data(**kwargs)
|
||||
queryset = self.object.comments
|
||||
context["replies"] = len(queryset.filter(parent=None))
|
||||
queryset = (
|
||||
queryset.filter(parent=None)[:10].select_related("author__user")
|
||||
.defer("author__about")
|
||||
.annotate(revisions=Count("versions")).annotate(count_replies=Count("replies"))
|
||||
)
|
||||
context["has_comments"] = queryset.exists()
|
||||
context["comment_lock"] = self.is_comment_locked()
|
||||
queryset = (
|
||||
queryset.select_related("author__user")
|
||||
.defer("author__about")
|
||||
.annotate(revisions=Count("versions"))
|
||||
)
|
||||
|
||||
if self.request.user.is_authenticated:
|
||||
profile = self.request.profile
|
||||
queryset = queryset.annotate(
|
||||
|
@ -184,6 +184,10 @@ class CommentedDetailView(TemplateResponseMixin, SingleObjectMixin, View):
|
|||
).exists()
|
||||
)
|
||||
context["comment_list"] = queryset
|
||||
context["comment_count"] = len(queryset)
|
||||
# context["comment_count"] = len(queryset)
|
||||
context["vote_hide_threshold"] = settings.DMOJ_COMMENT_VOTE_HIDE_THRESHOLD
|
||||
context["comment_root_id"] = 0
|
||||
context["offset"] = 10
|
||||
context["limit"] = 10
|
||||
|
||||
return context
|
||||
|
|
|
@ -56,6 +56,7 @@ class Comment(MPTTModel):
|
|||
related_name="replies",
|
||||
on_delete=CASCADE,
|
||||
)
|
||||
|
||||
versions = VersionRelation()
|
||||
|
||||
class Meta:
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
from django.conf import settings
|
||||
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
|
||||
from django.contrib.auth.context_processors import PermWrapper
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db import IntegrityError, transaction
|
||||
from django.db.models import F
|
||||
from django.db.models import Q, F, Count, FilteredRelation
|
||||
from django.db.models.functions import Coalesce
|
||||
from django.db.models.expressions import F, Value
|
||||
from django.forms.models import ModelForm
|
||||
from django.http import (
|
||||
Http404,
|
||||
|
@ -15,11 +20,12 @@ from django.utils.translation import gettext as _
|
|||
from django.views.decorators.http import require_POST
|
||||
from django.views.generic import DetailView, UpdateView
|
||||
from django.urls import reverse_lazy
|
||||
from django.template import loader
|
||||
from reversion import revisions
|
||||
from reversion.models import Version
|
||||
|
||||
from judge.dblock import LockModel
|
||||
from judge.models import Comment, CommentVote, Notification
|
||||
from judge.models import Comment, CommentVote, Notification, BlogPost
|
||||
from judge.utils.views import TitleMixin
|
||||
from judge.widgets import MathJaxPagedownWidget, HeavyPreviewPageDownWidget
|
||||
from judge.comments import add_mention_notifications, del_mention_notifications
|
||||
|
@ -34,6 +40,11 @@ __all__ = [
|
|||
|
||||
|
||||
@login_required
|
||||
|
||||
# def get_more_reply(request, id):
|
||||
# queryset = Comment.get_pk(id)
|
||||
|
||||
|
||||
def vote_comment(request, delta):
|
||||
if abs(delta) != 1:
|
||||
return HttpResponseBadRequest(
|
||||
|
@ -97,10 +108,67 @@ def vote_comment(request, delta):
|
|||
def upvote_comment(request):
|
||||
return vote_comment(request, 1)
|
||||
|
||||
|
||||
def downvote_comment(request):
|
||||
return vote_comment(request, -1)
|
||||
|
||||
def get_comment(request, limit=10):
|
||||
try:
|
||||
comment_id = int(request.GET["id"])
|
||||
page_id = int(request.GET["page"])
|
||||
except ValueError:
|
||||
return HttpResponseBadRequest()
|
||||
else:
|
||||
if comment_id and not Comment.objects.filter(id=comment_id).exists():
|
||||
raise Http404()
|
||||
if not BlogPost.objects.filter(id=page_id).exists():
|
||||
raise Http404()
|
||||
offset = 0
|
||||
if "offset" in request.GET:
|
||||
offset = int(request.GET["offset"])
|
||||
comment_root_id = 0
|
||||
if (comment_id):
|
||||
comment_obj = Comment.objects.get(pk=comment_id)
|
||||
comment_root_id = comment_obj.id
|
||||
else:
|
||||
comment_obj = None
|
||||
page_obj = BlogPost.objects.get(pk=page_id)
|
||||
queryset = page_obj.comments
|
||||
replies = len(queryset.filter(parent=comment_obj))
|
||||
queryset = (
|
||||
queryset.filter(parent=comment_obj)[offset:offset+limit].select_related("author__user")
|
||||
.defer("author__about")
|
||||
.annotate(revisions=Count("versions")).annotate(count_replies=Count("replies"))
|
||||
)
|
||||
if request.user.is_authenticated:
|
||||
profile = request.profile
|
||||
queryset = queryset.annotate(
|
||||
my_vote=FilteredRelation(
|
||||
"votes", condition=Q(votes__voter_id=profile.id)
|
||||
),
|
||||
).annotate(vote_score=Coalesce(F("my_vote__score"), Value(0)))
|
||||
|
||||
comment_html = loader.render_to_string(
|
||||
"comments/content-list.html",
|
||||
{
|
||||
"request": request,
|
||||
"comment_root_id": comment_root_id,
|
||||
"comment_list": queryset,
|
||||
"vote_hide_threshold" : settings.DMOJ_COMMENT_VOTE_HIDE_THRESHOLD,
|
||||
"perms": PermWrapper(request.user),
|
||||
"object": page_obj,
|
||||
"offset": offset + min(len(queryset), limit),
|
||||
"replies": replies,
|
||||
"limit": limit
|
||||
}
|
||||
)
|
||||
|
||||
return HttpResponse(comment_html)
|
||||
|
||||
def get_showmore(request):
|
||||
return get_comment(request)
|
||||
|
||||
def get_reply(request):
|
||||
return get_comment(request)
|
||||
|
||||
class CommentMixin(object):
|
||||
model = Comment
|
||||
|
|
|
@ -121,6 +121,18 @@ a {
|
|||
margin: -50px 23px 10px -40px;
|
||||
padding-top: 50px;
|
||||
}
|
||||
|
||||
.show_more_reply {
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
margin: 16px 40px;
|
||||
}
|
||||
|
||||
.show_more_comment {
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
margin: 0 -40px;
|
||||
}
|
||||
}
|
||||
|
||||
.no-comments-message {
|
||||
|
|
|
@ -27,9 +27,9 @@
|
|||
<span class="actionbar-text">
|
||||
{{_("Comment")}}
|
||||
</span>
|
||||
{% if comment_count %}
|
||||
{% if replies %}
|
||||
<span style="margin-left: 0.2em">
|
||||
({{comment_count}})
|
||||
({{replies}})
|
||||
</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
|
|
121
templates/comments/content-list.html
Normal file
121
templates/comments/content-list.html
Normal file
|
@ -0,0 +1,121 @@
|
|||
{% set logged_in = request.user.is_authenticated %}
|
||||
{% set profile = request.profile if logged_in else None %}
|
||||
{% for node in mptt_tree(comment_list) recursive %}
|
||||
<li id="comment-{{ node.id }}" data-revision="{{ node.revisions - 1 }}" data-max-revision="{{ node.revisions - 1 }}"
|
||||
data-revision-ajax="{{ url('comment_revision_ajax', node.id) }}" class="comment">
|
||||
<div class="comment-display{% if node.score <= vote_hide_threshold %} bad-comment{% endif %}">
|
||||
<div class="info">
|
||||
<div class="vote">
|
||||
{% if logged_in %}
|
||||
<a href="javascript:comment_upvote({{ node.id }})"
|
||||
class="upvote-link fa fa-chevron-up fa-fw{% if node.vote_score == 1 %} voted{% endif %}"></a>
|
||||
{% else %}
|
||||
<a href="javascript:alert('{{ _('Please login to vote')|escapejs }}')"
|
||||
title="{{ _('Please login to vote') }}" class="upvote-link fa fa-chevron-up fa-fw"></a>
|
||||
{% endif %}
|
||||
<br>
|
||||
<div class="comment-score">{{ node.score }}</div>
|
||||
{% if logged_in %}
|
||||
<a href="javascript:comment_downvote({{ node.id }})"
|
||||
class="downvote-link fa fa-chevron-down fa-fw{% if node.vote_score == -1 %} voted{% endif %}"></a>
|
||||
{% else %}
|
||||
<a href="javascript:alert('{{ _('Please login to vote')|escapejs }}')"
|
||||
title="{{ _('Please login to vote') }}" class="downvote-link fa fa-chevron-down fa-fw"></a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% with author=node.author, user=node.author.user %}
|
||||
<a href="{{ url('user_page', user.username) }}" class="user">
|
||||
<img src="{{ gravatar(author, 135) }}" class="gravatar">
|
||||
</a>
|
||||
{% endwith %}
|
||||
</div>
|
||||
<div class="detail">
|
||||
<div class="header">
|
||||
{{ link_user(node.author) }}
|
||||
{{ relative_time(node.time, abs=_('commented on {time}'), rel=_('commented {time}')) }}
|
||||
<span class="comment-spacer"></span>
|
||||
<span class="comment-operation">
|
||||
{% if node.revisions > 1 %}
|
||||
<span class="comment-edits">
|
||||
<a href="javascript:show_revision({{ node.id }}, -1)" class="previous-revision">←</a>
|
||||
<span class="comment-edit-text">
|
||||
{% if node.revisions > 2 %}
|
||||
{% trans edits=node.revisions - 1 %}edit {{ edits }}{% endtrans %}
|
||||
{% else %}
|
||||
{{ _('edited') }}
|
||||
{% endif %}
|
||||
</span>
|
||||
<a href="javascript:show_revision({{ node.id }}, 1)" style="visibility: hidden"
|
||||
class="next-revision">→</a>
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="comment-edits"></span>
|
||||
{% endif %}
|
||||
<a href="#comment-{{ node.id }}" title="{{ _('Link') }}" class="comment-link">
|
||||
<i class="fa fa-link fa-fw"></i>
|
||||
</a>
|
||||
{% if logged_in and not comment_lock %}
|
||||
{% set can_edit = node.author.id == profile.id and not profile.mute %}
|
||||
{% if can_edit %}
|
||||
<a data-featherlight="{{ url('comment_edit_ajax', node.id) }}"
|
||||
href="{{ url('comment_edit', node.id) }}" title="{{ _('Edit') }}" class="edit-link">
|
||||
<i class="fa fa-pencil fa-fw"></i>
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="javascript:reply_comment({{ node.id }})" title="{{ _('Reply') }}">
|
||||
<i class="fa fa-reply fa-fw"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if perms.judge.change_comment %}
|
||||
{% if can_edit %}
|
||||
<a href="javascript:reply_comment({{ node.id }})" title="{{ _('Reply') }}"><i
|
||||
class="fa fa-reply fa-fw"></i></a>
|
||||
{% else %}
|
||||
<a data-featherlight="{{ url('comment_edit_ajax', node.id) }}"
|
||||
href="{{ url('comment_edit', node.id) }}" title="{{ _('Edit') }}" class="edit-link"><i
|
||||
class="fa fa-pencil fa-fw"></i></a>
|
||||
{% endif %}
|
||||
<a href="javascript:" title="{{ _('Hide') }}" data-id="{{ node.id }}" class="hide-comment"><i
|
||||
class="fa fa-trash fa-fw"></i></a>
|
||||
<a href="{{ url('admin:judge_comment_change', node.id) }}" title="{{ _('Admin') }}"><i
|
||||
class="fa fa-cog fa-fw"></i></a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
<div class="content content-description">
|
||||
<div class="comment-body" {% if node.score <=vote_hide_threshold %} style="display:none" {% endif %}>
|
||||
{{ node.body|markdown(lazy_load=True)|reference|str|safe }}
|
||||
</div>
|
||||
{% if node.score <= vote_hide_threshold %} <div class="comment-body bad-comment-body">
|
||||
<p>
|
||||
{% trans id=node.id %}This comment is hidden due to too much negative feedback. Click <a
|
||||
href="javascript:comment_show_content({{ id }})">here</a> to view it.{% endtrans %}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- {{ node.count_replies }}
|
||||
{{node.revisions - 1}} -->
|
||||
{% if node.revisions == 1 %}
|
||||
{% set real_replies = node.count_replies - node.revisions + 1 %}
|
||||
{% else %}
|
||||
{% set real_replies = node.count_replies - node.revisions + 2 %}
|
||||
{% endif %}
|
||||
|
||||
{% if real_replies > 1 %}
|
||||
<a href="javascript:comment_reply({{ node.id }}, {{ object.id }})" class="show_more_reply"> {{ real_replies }} {{ _(' Replies ') }} </a>
|
||||
{% elif real_replies %}
|
||||
<a href="javascript:comment_reply({{ node.id }}, {{ object.id }})" class="show_more_reply"> {{ real_replies }} {{ _(' Reply ') }} </a>
|
||||
{% endif %}
|
||||
</li>
|
||||
<ul id="comment-{{ node.id }}-reply" class="reply-comment" hidden></ul>
|
||||
<ul id="comment-{{ node.id }}-children" class="comments"> </ul>
|
||||
{% endfor %}
|
||||
|
||||
{% if replies - offset > 0 %}
|
||||
<a href="javascript:comment_show_more({{ comment_root_id }}, {{ object.id }}, {{ offset }} )" class="show_more_comment"> {{ replies - offset }} Replies More</a>
|
||||
{% endif %}
|
|
@ -37,118 +37,8 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
{% if has_comments %}
|
||||
<ul class="comments top-level-comments new-comments">
|
||||
{% set logged_in = request.user.is_authenticated %}
|
||||
{% set profile = request.profile if logged_in else None %}
|
||||
{% for node in mptt_tree(comment_list) recursive %}
|
||||
<li id="comment-{{ node.id }}" data-revision="{{ node.revisions - 1 }}"
|
||||
data-max-revision="{{ node.revisions - 1 }}"
|
||||
data-revision-ajax="{{ url('comment_revision_ajax', node.id) }}" class="comment">
|
||||
<div class="comment-display{% if node.score <= vote_hide_threshold %} bad-comment{% endif %}">
|
||||
<div class="info">
|
||||
<div class="vote">
|
||||
{% if logged_in %}
|
||||
<a href="javascript:comment_upvote({{ node.id }})"
|
||||
class="upvote-link fa fa-chevron-up fa-fw{% if node.vote_score == 1 %} voted{% endif %}"></a>
|
||||
{% else %}
|
||||
<a href="javascript:alert('{{ _('Please login to vote')|escapejs }}')" title="{{ _('Please login to vote') }}"
|
||||
class="upvote-link fa fa-chevron-up fa-fw"></a>
|
||||
{% endif %}
|
||||
<br>
|
||||
<div class="comment-score">{{ node.score }}</div>
|
||||
{% if logged_in %}
|
||||
<a href="javascript:comment_downvote({{ node.id }})"
|
||||
class="downvote-link fa fa-chevron-down fa-fw{% if node.vote_score == -1 %} voted{% endif %}"></a>
|
||||
{% else %}
|
||||
<a href="javascript:alert('{{ _('Please login to vote')|escapejs }}')" title="{{ _('Please login to vote') }}"
|
||||
class="downvote-link fa fa-chevron-down fa-fw"></a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% with author=node.author, user=node.author.user %}
|
||||
<a href="{{ url('user_page', user.username) }}" class="user">
|
||||
<img src="{{ gravatar(author, 135) }}" class="gravatar">
|
||||
</a>
|
||||
{% endwith %}
|
||||
</div>
|
||||
<div class="detail">
|
||||
<div class="header">
|
||||
{{ link_user(node.author) }}
|
||||
{{ relative_time(node.time, abs=_('commented on {time}'), rel=_('commented {time}')) }}
|
||||
<span class="comment-spacer"></span>
|
||||
<span class="comment-operation">
|
||||
{% if node.revisions > 1 %}
|
||||
<span class="comment-edits">
|
||||
<a href="javascript:show_revision({{ node.id }}, -1)"
|
||||
class="previous-revision">←</a>
|
||||
<span class="comment-edit-text">
|
||||
{% if node.revisions > 2 %}
|
||||
{% trans edits=node.revisions - 1 %}edit {{ edits }}{% endtrans %}
|
||||
{% else %}
|
||||
{{ _('edited') }}
|
||||
{% endif %}
|
||||
</span>
|
||||
<a href="javascript:show_revision({{ node.id }}, 1)" style="visibility: hidden"
|
||||
class="next-revision">→</a>
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="comment-edits"></span>
|
||||
{% endif %}
|
||||
<a href="#comment-{{ node.id }}" title="{{ _('Link') }}" class="comment-link">
|
||||
<i class="fa fa-link fa-fw"></i>
|
||||
</a>
|
||||
{% if logged_in and not comment_lock %}
|
||||
{% set can_edit = node.author.id == profile.id and not profile.mute %}
|
||||
{% if can_edit %}
|
||||
<a data-featherlight="{{ url('comment_edit_ajax', node.id) }}"
|
||||
href="{{ url('comment_edit', node.id) }}"
|
||||
title="{{ _('Edit') }}" class="edit-link">
|
||||
<i class="fa fa-pencil fa-fw"></i>
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="javascript:reply_comment({{ node.id }})"
|
||||
title="{{ _('Reply') }}">
|
||||
<i class="fa fa-reply fa-fw"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if perms.judge.change_comment %}
|
||||
{% if can_edit %}
|
||||
<a href="javascript:reply_comment({{ node.id }})"
|
||||
title="{{ _('Reply') }}"><i class="fa fa-reply fa-fw"></i></a>
|
||||
{% else %}
|
||||
<a data-featherlight="{{ url('comment_edit_ajax', node.id) }}"
|
||||
href="{{ url('comment_edit', node.id) }}" title="{{ _('Edit') }}"
|
||||
class="edit-link"><i class="fa fa-pencil fa-fw"></i></a>
|
||||
{% endif %}
|
||||
<a href="javascript:" title="{{ _('Hide') }}" data-id="{{ node.id }}"
|
||||
class="hide-comment"><i class="fa fa-trash fa-fw"></i></a>
|
||||
<a href="{{ url('admin:judge_comment_change', node.id) }}"
|
||||
title="{{ _('Admin') }}"><i class="fa fa-cog fa-fw"></i></a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
<div class="content content-description">
|
||||
<div class="comment-body"{% if node.score <= vote_hide_threshold %} style="display:none"{% endif %}>
|
||||
{{ node.body|markdown(lazy_load=True)|reference|str|safe }}
|
||||
</div>
|
||||
{% if node.score <= vote_hide_threshold %}
|
||||
<div class="comment-body bad-comment-body">
|
||||
<p>
|
||||
{% trans id=node.id %}This comment is hidden due to too much negative feedback. Click <a href="javascript:comment_show_content({{ id }})">here</a> to view it.{% endtrans %}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<ul id="comment-{{ node.id }}-reply" class="reply-comment" hidden></ul>
|
||||
{% with children=node.get_children() %}
|
||||
{% if children %}
|
||||
<ul id="comment-{{ node.id }}-children" class="comments">{{ loop(children) }}</ul>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
<ul class="comments top-level-comments new-comments" id="comment-0">
|
||||
{% include "comments/content-list.html" %}
|
||||
</ul>
|
||||
{% elif not comment_lock %}
|
||||
<p class="no-comments-message">{{ _('There are no comments at the moment.') }}</p>
|
||||
|
|
|
@ -120,6 +120,55 @@
|
|||
});
|
||||
}
|
||||
|
||||
window.comment_reply = function (id, page) {
|
||||
ajax_get_reply('{{ url('comment_reply') }}', id, page);
|
||||
}
|
||||
|
||||
function ajax_get_reply(url, id, page) {
|
||||
return $.ajax({
|
||||
url: url,
|
||||
type: 'GET',
|
||||
data: {
|
||||
id: id,
|
||||
page: page,
|
||||
},
|
||||
success: function(data) {
|
||||
var $comment = $("#comment-" + id + "-children");
|
||||
var $comment_show_btn = $("#comment-" + id + " .show_more_reply");
|
||||
console.log($comment_show_btn);
|
||||
$comment_show_btn.hide();
|
||||
$comment.append(data);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
window.comment_show_more = function (id, page, offset) {
|
||||
ajax_comment_show_more('{{ url('comment_show_more') }}', id, page, offset);
|
||||
}
|
||||
|
||||
function ajax_comment_show_more(url, id, page, offset) {
|
||||
return $.ajax({
|
||||
url: url,
|
||||
type: 'GET',
|
||||
data: {
|
||||
id: id,
|
||||
page: page,
|
||||
offset: offset,
|
||||
},
|
||||
success: function(data) {
|
||||
var $comment_show_btn = $("#comment-" + id + " .show_more_comment");
|
||||
$comment_show_btn.hide();
|
||||
if (id == 0) {
|
||||
var $comment = $("#comment-" + id);
|
||||
$comment.append(data);
|
||||
} else {
|
||||
var $comment = $("#comment-" + id + "-children");
|
||||
$comment.append(data);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var get_$votes = function (id) {
|
||||
var $comment = $('#comment-' + id);
|
||||
return {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue