
In some cases, #535 caused comment display to wildly break visible page formatting. The sidebar often moved to bottom of page, and some comments would display in a second column alongside the main one. Root cause was a closing `</div>` left outside of a conditional which was included in rendered markup even when: 1) A comment is invisible for the current browsing user v, e.g. filtered or removed. 2) The subtree rooted at said comment is to be hidden based on the display logic added in #535. Which left a stray `</div>` with no opening tag where those comments should've gone. Most of the testing appears to have been done on reply chains of comments, which behave correctly. It is specifically the zero children (or otherwise not even showing a "Removed" message in the page) which causes the bug.
268 lines
10 KiB
HTML
268 lines
10 KiB
HTML
{%- include "component/comment/usernote_header.html" -%}
|
|
|
|
{# "level" represents the nested level in this call; always starts at 1 #}
|
|
{# this is distinct from "comment.level", which is the global depth of this comment #}
|
|
{% macro single_comment(c, level) %}
|
|
{%- if render_ctx is not defined -%}
|
|
{% set render_ctx = 'comments' %}
|
|
{%- endif -%}
|
|
{%- set ups = c.upvotes_str(render_ctx) -%}
|
|
{%- set score = c.score_str(render_ctx) -%}
|
|
{%- set downs = c.downvotes_str(render_ctx) -%}
|
|
|
|
{% set replies = c.replies(v) %}
|
|
|
|
{% if not c.visibility_state(v)[0] %}
|
|
{% if c.show_descendants(v) %}
|
|
<div id="comment-{{c.id}}" class="comment">
|
|
<div class="comment-collapse-icon" onclick="collapse_comment('{{c.id}}', this.parentElement)"></div>
|
|
<div class="comment-collapse-bar-click" onclick="collapse_comment('{{c.id}}', this.parentElement)">
|
|
<div class="comment-collapse-bar"></div>
|
|
</div>
|
|
|
|
<div class="comment-user-info">
|
|
{% if standalone and c.over_18 %}<span class="badge badge-danger">+18</span>{% endif %}
|
|
{{c.visibility_state(v)[1]}}
|
|
</div>
|
|
|
|
<div class="comment-body">
|
|
<div id="comment-{{c.id}}-only" class="comment-{{c.id}}-only"></div>
|
|
{% if render_replies %}
|
|
{% if level <= RENDER_DEPTH_LIMIT - 1 %}
|
|
<div id="replies-of-{{c.id}}" class="">
|
|
{% set standalone=False %}
|
|
{% for reply in replies %}
|
|
{{single_comment(reply, level=level+1)}}
|
|
{% endfor %}
|
|
</div>
|
|
{% elif replies and is_notification_page %}
|
|
<div id="replies-of-{{c.id}}" class="d-none d-md-block">
|
|
{% set standalone=False %}
|
|
{% for reply in replies %}
|
|
{{single_comment(reply, level=level+1)}}
|
|
{% endfor %}
|
|
</div>
|
|
<div id="morecomment-{{c.id}}" class="d-md-none mt-2 more-comments">
|
|
<a href="{{c.morecomments}}">More comments <i class="fas fa-long-arrow-right ml-1"></i></a>
|
|
</div>
|
|
{% elif replies %}
|
|
<div id="morecomment-{{c.id}}" class="mt-2 more-comments">
|
|
<button id="btn-{{c.id}}" class="d-none d-md-block btn btn-primary" onclick="morecomments('{{c.id}}')">More comments ({{c.descendant_count}})</button>
|
|
<a class="d-md-none" href="{{c.morecomments}}">More comments <i class="fas fa-long-arrow-right ml-1"></i></a>
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% else %}
|
|
|
|
{%- set voted = c.voted_display(v) -%}
|
|
|
|
{% if standalone and level==1 %}
|
|
<div class="post-info post-row-cid-{{c.id}} mb-1 mr-2 {% if is_notification_page %}mt-5{% else %}mt-3{% endif %}">
|
|
{% if c.post and c.post.over_18 %}<span class="badge badge-danger text-small-extra mr-1">+18</span>{% endif %}
|
|
<span class="align-top">
|
|
<span class="font-weight-bold">{{c.header_msg(v, is_notification_page, replies | length) | safe}}</span>
|
|
</span>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% set isreply = not standalone and c.parent_comment and c.parent_comment.sentto %}
|
|
|
|
<div id="comment-{{c.id}}" class="anchor comment {% if standalone and level==1 %} mt-0{% endif %} {% if c.collapse_for_user(v,request.path) %}collapsed{% endif %}">
|
|
{% if not isreply %}
|
|
<div class="comment-collapse-icon" onclick="collapse_comment('{{c.id}}', this.parentElement)"></div>
|
|
<div class="comment-collapse-bar-click" onclick="collapse_comment('{{c.id}}', this.parentElement)">
|
|
<div class="comment-collapse-bar collapse-bar-{{(c.level + 6) % 8 + 1}}"></div>
|
|
</div>
|
|
{% endif %}
|
|
{%- include 'component/comment/user_info.html' -%}
|
|
|
|
<div class="comment-body">
|
|
<div id="{% if comment_info and comment_info.id == c.id %}context{%else%}comment-{{c.id}}-only{% endif %}" class="{% if c.unread %}unread{% endif %} comment-{{c.id}}-only comment-anchor {% if comment_info and comment_info.id == c.id %}context{%endif%}{% if c.is_banned %} banned{% endif %}{% if c.deleted_utc %} deleted{% endif %}">
|
|
{%- include 'component/comment/reports.html'-%}
|
|
{% if c.is_banned and c.ban_reason %} {# TODO: shouldn't be visible. See #359 #}
|
|
<div id="comment-banned-warning" class="comment-text text-removed mb-0">removed by @{{c.ban_reason}}</div>
|
|
{% endif %}
|
|
|
|
<div id="comment-text-{{c.id}}" class="comment-text mb-0">
|
|
{{c.realbody(v) | safe}}
|
|
</div>
|
|
{% if c.parent_submission %}
|
|
{%- include 'component/comment/editbox_comment.html' -%}
|
|
<div id="comment-{{c.id}}-actions" class="comment-actions{% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}">
|
|
<div class="d-md-none mt-2">
|
|
<div class="post-actions">
|
|
<ul class="list-inline text-right d-flex">
|
|
{% if v and v.admin_level >= 2 %}
|
|
<li class="list-inline-item mr-auto">
|
|
<a role="button" data-bs-toggle="modal" data-bs-target="#adminModal-{{c.id}}"> <i class="fas fa-broom"></i></a>
|
|
</li>
|
|
{% endif %}
|
|
{% if v %}
|
|
<a class="list-inline-item mr-3" role="button" onclick="openReplyBox('reply-to-{{c.id}}')"><i class="fas fa-reply" style="margin-top:0.35rem"></i></a>
|
|
{% endif %}
|
|
|
|
<li class="list-inline-item">
|
|
<a role="button" data-bs-toggle="modal" data-bs-target="#actionsModal-{{c.id}}"> <i class="fas fa-ellipsis-h mt-1"></i></a>
|
|
</li>
|
|
{%- include 'component/comment/voting_mobile.html' -%}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<ul class="d-none d-md-flex list-inline text-right text-md-left">
|
|
<li>
|
|
{%- include 'component/comment/voting_desktop.html' -%}
|
|
{%- include 'component/comment/actions_desktop.html' -%}
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
{% if v and v.id != c.author_id and c.body %}
|
|
<textarea autocomplete="off" class="d-none card border my-2 p-3 comment-box form-control rounded" id="markdown-{{c.id}}" readonly>{{c.body.strip()}}</textarea>
|
|
{% endif %}
|
|
|
|
{%- include 'component/comment/replybox_comment.html' -%}
|
|
|
|
{% if render_replies %}
|
|
{% if level <= RENDER_DEPTH_LIMIT - 1 or is_notification_page %}
|
|
<div id="replies-of-{{c.id}}">
|
|
{% for reply in replies %}
|
|
{{single_comment(reply, level=level+1)}}
|
|
{% endfor %}
|
|
</div>
|
|
{% elif replies %}
|
|
<div id="morecomments-{{c.id}}" class="mt-2 more-comments">
|
|
<button id="btn-{{c.id}}" class="d-none d-md-block btn btn-primary" onclick="morecomments('{{c.id}}')">More comments ({{c.descendant_count}})</button>
|
|
<a class="d-md-none" href="{{c.morecomments}}">More comments <i class="fas fa-long-arrow-right ml-1"></i></a>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if is_notification_page and c.level == 1 and c.sentto and not c.parent_submission and c.author_id not in (NOTIFICATIONS_ID, AUTOJANNY_ID) %}
|
|
{%- include 'component/comment/replybox_message.html' -%}
|
|
{% endif %}
|
|
{% else %}
|
|
<div id="replies-of-{{c.id}}"></div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
{%- include 'component/comment/actions_mobile.html' -%}
|
|
|
|
{% if v and v.admin_level >= 2 %}
|
|
{%- include 'component/comment/actions_mobile_admin.html' -%}
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
{% endmacro %}
|
|
|
|
{% for comment in comments %}
|
|
{%- set parent_level = parent_level | int if parent_level else 0 -%}
|
|
{{single_comment(comment, level = parent_level + 1)}}
|
|
{% endfor %}
|
|
|
|
{%- include 'component/comment/view_more_button.html' -%}
|
|
|
|
{% if not ajax %}
|
|
{% if v %}
|
|
{% if v.admin_level >= 2 %}
|
|
{% include "component/modal/ban.html" %}
|
|
{% endif %}
|
|
{%- include 'component/modal/delete_comment.html' -%}
|
|
{%- include 'component/modal/report_comment.html' -%}
|
|
{% endif %}
|
|
|
|
{% if v %}
|
|
<script src="{{ 'js/vendor/purify.min.js' | asset }}"></script>
|
|
<script src="{{ 'js/vendor/marked.min.js' | asset }}"></script>
|
|
<script src="{{ 'js/marked.custom.js' | asset }}"></script>
|
|
<script src="{{ 'js/comments_v.js' | asset }}"></script>
|
|
{% if FEATURES['AWARDS'] %}
|
|
<script src="{{ 'js/award_modal.js' | asset }}"></script>
|
|
{% endif %}
|
|
{% endif %}
|
|
|
|
<script src="{{ 'js/clipboard.js' | asset }}"></script>
|
|
|
|
{% if v %}
|
|
{% if v.admin_level >= 2 %}
|
|
<script src="{{ 'js/comments_admin.js' | asset }}"></script>
|
|
{% endif %}
|
|
{% if v.admin_level >= 2 %}
|
|
<script src="{{ 'js/filter_actions.js' | asset }}"></script>
|
|
{% endif %}
|
|
{% endif %}
|
|
|
|
{% include "component/modal/expanded_image.html" %}
|
|
|
|
<script src="{{ 'js/comments+submission_listing.js' | asset }}"></script>
|
|
<script src="{{ 'js/comments.js' | asset }}"></script>
|
|
|
|
<script>
|
|
{% if p and (not v or v.highlightcomments) %}
|
|
comments = JSON.parse(localStorage.getItem("comment-counts")) || {}
|
|
lastCount = comments['{{p.id}}']
|
|
if (lastCount)
|
|
{
|
|
{% for c in p.comments %}
|
|
{% if not (v and v.id==c.author_id) and not c.voted %}
|
|
if ({{c.created_utc*1000}} > lastCount.t)
|
|
try {document.getElementById("comment-{{c.id}}-only").classList.add('unread')}
|
|
catch(e) {}
|
|
{% endif %}
|
|
{% endfor %}
|
|
}
|
|
{% endif %}
|
|
|
|
{% if p and not (request.values and ('context' in request.values)) %}
|
|
collapsedCommentStorageInit('post_{{p.id}}');
|
|
{% elif is_notification_page or request.path.startswith('/@') %}
|
|
collapsedCommentStorageInit('{{request.path}}');
|
|
{% endif %}
|
|
if (document.readyState === "complete" ||
|
|
(document.readyState !== "loading" && !document.documentElement.doScroll)) {
|
|
collapsedCommentStorageApply();
|
|
} else {
|
|
document.addEventListener("DOMContentLoaded", collapsedCommentStorageApply);
|
|
}
|
|
|
|
function morecomments(cid) {
|
|
btn = document.getElementById(`btn-${cid}`);
|
|
btn.disabled = true;
|
|
btn.innerHTML = "Requesting...";
|
|
var form = new FormData();
|
|
form.append("formkey", formkey());
|
|
const xhr = new XMLHttpRequest();
|
|
xhr.open("get", `/morecomments/${cid}`);
|
|
xhr.setRequestHeader('xhr', 'xhr');
|
|
xhr.onload=function(){
|
|
if (xhr.status==200) {
|
|
let e = document.getElementById(`morecomments-${cid}`)
|
|
e.innerHTML = xhr.response.replace(/data-src/g, 'src').replace(/data-cfsrc/g, 'src').replace(/style="display:none;visibility:hidden;"/g, '');
|
|
bs_trigger(e)
|
|
|
|
{% if p %}
|
|
comments = JSON.parse(localStorage.getItem("old-comment-counts")) || {}
|
|
lastCount = comments['{{p.id}}']
|
|
if (lastCount)
|
|
{
|
|
{% for c in p.comments %}
|
|
{% if not (v and v.id==c.author_id) and not c.voted %}
|
|
if ({{c.created_utc*1000}} > lastCount.t)
|
|
try {document.getElementById("comment-{{c.id}}-only").classList.add('unread')}
|
|
catch(e) {}
|
|
{% endif %}
|
|
{% endfor %}
|
|
}
|
|
{% endif %}
|
|
}
|
|
btn.disabled = false;
|
|
}
|
|
xhr.send(form)
|
|
}
|
|
</script>
|
|
{% endif %}
|