comments: add scores, rework comment menu.
* Add comment scores. * Rework voting buttons so that you can click the upvote/downvote buttons to toggle votes. * Hide the edit, delete, undelete, and report buttons behind a popup menu. * Show the upvote/downvote/reply buttons to logged out users. Redirect them to the login page instead.
This commit is contained in:
@@ -15,6 +15,8 @@
|
|||||||
* You can now see the list of comments and forum posts you've reported to
|
* You can now see the list of comments and forum posts you've reported to
|
||||||
the moderators at <https://danbooru.donmai.us/moderation_reports>.
|
the moderators at <https://danbooru.donmai.us/moderation_reports>.
|
||||||
|
|
||||||
|
* Comment scores are now visible and the vote buttons have been reworked.
|
||||||
|
|
||||||
* You can now see when a post has deleted comments. Deleted comments are now
|
* You can now see when a post has deleted comments. Deleted comments are now
|
||||||
replaced with the word `[deleted]`, instead of being completely hidden.
|
replaced with the word `[deleted]`, instead of being completely hidden.
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,21 @@ class CommentComponent < ApplicationComponent
|
|||||||
comment.is_deleted? && !policy(comment).can_see_deleted?
|
comment.is_deleted? && !policy(comment).can_see_deleted?
|
||||||
end
|
end
|
||||||
|
|
||||||
def has_moderation_reports?
|
def votable?
|
||||||
|
!comment.is_deleted? || current_user.is_moderator?
|
||||||
|
end
|
||||||
|
|
||||||
|
def upvoted?
|
||||||
|
return false if current_user.is_anonymous?
|
||||||
|
comment.votes.select(&:is_positive?).map(&:user_id).include?(current_user.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def downvoted?
|
||||||
|
return false if current_user.is_anonymous?
|
||||||
|
comment.votes.select(&:is_negative?).map(&:user_id).include?(current_user.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def reported?
|
||||||
policy(ModerationReport).can_see_moderation_reports? && comment.moderation_reports.present?
|
policy(ModerationReport).can_see_moderation_reports? && comment.moderation_reports.present?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,8 +10,10 @@
|
|||||||
data-is-sticky="<%= comment.is_sticky? %>"
|
data-is-sticky="<%= comment.is_sticky? %>"
|
||||||
data-is-dimmed="<%= dimmed? %>"
|
data-is-dimmed="<%= dimmed? %>"
|
||||||
data-is-thresholded="<%= thresholded? %>"
|
data-is-thresholded="<%= thresholded? %>"
|
||||||
data-is-reported="<%= has_moderation_reports? %>"
|
data-is-reported="<%= reported? %>"
|
||||||
data-is-voted="<%= comment.voted_by?(current_user) %>">
|
data-is-upvoted="<%= upvoted? %>"
|
||||||
|
data-is-downvoted="<%= downvoted? %>">
|
||||||
|
|
||||||
<div class="author">
|
<div class="author">
|
||||||
<div class="author-name">
|
<div class="author-name">
|
||||||
<% if redact_deleted? %>
|
<% if redact_deleted? %>
|
||||||
@@ -25,6 +27,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<%= link_to time_ago_in_words_tagged(comment.created_at), post_path(comment.post, anchor: "comment_#{comment.id}"), class: "message-timestamp" %>
|
<%= link_to time_ago_in_words_tagged(comment.created_at), post_path(comment.post, anchor: "comment_#{comment.id}"), class: "message-timestamp" %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<% if thresholded? %>
|
<% if thresholded? %>
|
||||||
<%= link_to "[hidden]", "javascript:void(0)", class: "unhide-comment-link" %>
|
<%= link_to "[hidden]", "javascript:void(0)", class: "unhide-comment-link" %>
|
||||||
@@ -41,42 +44,81 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<menu>
|
<menu>
|
||||||
|
<% if votable? %>
|
||||||
|
<li class="comment-votes">
|
||||||
|
<% if current_user.is_anonymous? %>
|
||||||
|
<%= link_to "🡹", login_path(url: request.fullpath), class: "comment-upvote-link" %>
|
||||||
|
<% elsif upvoted? %>
|
||||||
|
<%= link_to "🡹", comment_comment_votes_path(comment_id: comment.id), class: "comment-upvote-link comment-unvote-link", method: :delete, remote: true %>
|
||||||
|
<% else %>
|
||||||
|
<%= link_to "🡹", comment_comment_votes_path(comment_id: comment.id, score: "up"), class: "comment-upvote-link", method: :post, remote: true %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<span class="comment-score"><%= comment.score %></span>
|
||||||
|
|
||||||
|
<% if current_user.is_anonymous? %>
|
||||||
|
<%= link_to "🡻", login_path(url: request.fullpath), class: "comment-downvote-link" %>
|
||||||
|
<% elsif downvoted? %>
|
||||||
|
<%= link_to "🡻", comment_comment_votes_path(comment_id: comment.id), class: "comment-downvote-link comment-unvote-link", method: :delete, remote: true %>
|
||||||
|
<% else %>
|
||||||
|
<%= link_to "🡻", comment_comment_votes_path(comment_id: comment.id, score: "down"), class: "comment-downvote-link", method: :post, remote: true %>
|
||||||
|
<% end %>
|
||||||
|
</li>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<% if policy(comment).reply? %>
|
<% if policy(comment).reply? %>
|
||||||
<% if context == :index_by_comment %>
|
<li class="comment-reply">
|
||||||
<li><%= link_to "Reply", new_comment_path(id: comment, comment: { post_id: comment.post_id }), class: "reply-link" %></li>
|
<% if current_user.is_anonymous? %>
|
||||||
<% else %>
|
<%= link_to "Reply", login_path(url: request.fullpath) %>
|
||||||
<li><%= link_to "Reply", new_comment_path(id: comment, comment: { post_id: comment.post_id }), class: "reply-link", remote: true %></li>
|
<% elsif context == :index_by_comment %>
|
||||||
|
<%= link_to "Reply", new_comment_path(id: comment, comment: { post_id: comment.post_id }) %>
|
||||||
|
<% else %>
|
||||||
|
<%= link_to "Reply", new_comment_path(id: comment, comment: { post_id: comment.post_id }), remote: true %>
|
||||||
|
<% end %>
|
||||||
|
</li>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if reported? %>
|
||||||
|
<li class="moderation-report-notice">
|
||||||
|
Reported (<%= link_to pluralize(comment.moderation_reports.length, "report"), moderation_reports_path(search: { model_type: "Comment", model_id: comment.id }) %>)
|
||||||
|
</li>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if policy(comment).update? || policy(comment).reportable? %>
|
||||||
|
<%= render PopupMenuComponent.new do |menu| %>
|
||||||
|
<% if policy(comment).update? %>
|
||||||
|
<%= menu.item do %>
|
||||||
|
<%= link_to edit_comment_path(comment.id), id: "edit_comment_link_#{comment.id}", class: "edit_comment_link" do %>
|
||||||
|
<i class="icon fas fa-edit"></i>
|
||||||
|
Edit
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= menu.item do %>
|
||||||
|
<% if comment.is_deleted? %>
|
||||||
|
<%= link_to undelete_comment_path(comment.id), method: :post, remote: true do %>
|
||||||
|
<i class="icon fas fa-trash-restore-alt"></i>
|
||||||
|
Undelete
|
||||||
|
<% end %>
|
||||||
|
<% else %>
|
||||||
|
<%= link_to comment_path(comment.id), "data-confirm": "Are you sure you want to delete this comment?", method: :delete, remote: true do %>
|
||||||
|
<i class="icon fas fa-trash-alt"></i>
|
||||||
|
Delete
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if policy(comment).reportable? %>
|
||||||
|
<%= menu.item do %>
|
||||||
|
<%= link_to new_moderation_report_path(moderation_report: { model_type: "Comment", model_id: comment.id }), remote: true do %>
|
||||||
|
<i class="icon fas fa-flag"></i>
|
||||||
|
Report
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% if policy(comment).update? %>
|
|
||||||
<% if comment.is_deleted? %>
|
|
||||||
<li><%= link_to "Undelete", undelete_comment_path(comment.id), method: :post, remote: true %></li>
|
|
||||||
<% else %>
|
|
||||||
<li><%= link_to "Delete", comment_path(comment.id), "data-confirm": "Are you sure you want to delete this comment?", method: :delete, remote: true %></li>
|
|
||||||
<% end %>
|
|
||||||
<li><%= link_to "Edit", edit_comment_path(comment.id), id: "edit_comment_link_#{comment.id}", class: "edit_comment_link" %></li>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% if policy(comment).vote? %>
|
|
||||||
<li class="comment-vote-up-link">
|
|
||||||
<%= link_to "Vote up", comment_comment_votes_path(comment_id: comment.id, score: "up"), method: :post, remote: true %>
|
|
||||||
</li>
|
|
||||||
<li class="comment-vote-down-link">
|
|
||||||
<%= link_to "Vote down", comment_comment_votes_path(comment_id: comment.id, score: "down"), method: :post, remote: true %>
|
|
||||||
</li>
|
|
||||||
<li class="comment-unvote-link">
|
|
||||||
<%= link_to "Unvote", comment_comment_votes_path(comment_id: comment.id), method: :delete, remote: true %>
|
|
||||||
</li>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% if policy(comment).reportable? %>
|
|
||||||
<li><%= link_to "Report", new_moderation_report_path(moderation_report: { model_type: "Comment", model_id: comment.id }), remote: true %></li>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% if has_moderation_reports? %>
|
|
||||||
<li class="moderation-report-notice">This comment has been reported! (<%= link_to pluralize(comment.moderation_reports.length, "report"), moderation_reports_path(search: { model_type: "Comment", model_id: comment.id }) %>)</li>
|
|
||||||
<% end %>
|
|
||||||
</menu>
|
</menu>
|
||||||
|
|
||||||
<% if policy(comment).update? %>
|
<% if policy(comment).update? %>
|
||||||
|
|||||||
@@ -9,15 +9,15 @@ article.comment {
|
|||||||
background-color: var(--moderation-report-background-color);
|
background-color: var(--moderation-report-background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
&[data-is-voted="true"] {
|
&[data-is-upvoted="true"] {
|
||||||
.comment-vote-up-link, .comment-vote-down-link {
|
a.comment-upvote-link {
|
||||||
display: none;
|
color: var(--link-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&[data-is-voted="false"] {
|
&[data-is-downvoted="true"] {
|
||||||
.comment-unvote-link {
|
a.comment-downvote-link {
|
||||||
display: none;
|
color: var(--link-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,4 +38,21 @@ article.comment {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: var(--moderation-report-text-color);
|
color: var(--moderation-report-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comment-votes {
|
||||||
|
color: var(--muted-text-color);
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--muted-text-color);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--link-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-menu {
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class CommentSectionComponent < ApplicationComponent
|
|||||||
@comments = @post.comments.order(id: :asc)
|
@comments = @post.comments.order(id: :asc)
|
||||||
@comments = @comments.includes(:creator)
|
@comments = @comments.includes(:creator)
|
||||||
@comments = @comments.includes(:votes) if !current_user.is_anonymous?
|
@comments = @comments.includes(:votes) if !current_user.is_anonymous?
|
||||||
@comments = @comments.includes(:moderation_reports) if policy(ModerationReport).show?
|
@comments = @comments.includes(:moderation_reports) if policy(ModerationReport).can_see_moderation_reports?
|
||||||
@comments = @comments.last(limit) if limit.present?
|
@comments = @comments.last(limit) if limit.present?
|
||||||
|
|
||||||
@dtext_data = DText.preprocess(@comments.map(&:body))
|
@dtext_data = DText.preprocess(@comments.map(&:body))
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
<li><%= link_to "Report", new_moderation_report_path(moderation_report: { model_type: "ForumPost", model_id: forum_post.id }), remote: true, title: "Report this forum post to the moderators" %></li>
|
<li><%= link_to "Report", new_moderation_report_path(moderation_report: { model_type: "ForumPost", model_id: forum_post.id }), remote: true, title: "Report this forum post to the moderators" %></li>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if has_moderation_reports? %>
|
<% if has_moderation_reports? %>
|
||||||
<li class="moderation-report-notice">This post has been reported! (<%= link_to pluralize(forum_post.moderation_reports.length, "report"), moderation_reports_path(search: { model_type: "ForumPost", model_id: forum_post.id }) %>)</li>
|
<li class="moderation-report-notice">Reported (<%= link_to pluralize(forum_post.moderation_reports.length, "report"), moderation_reports_path(search: { model_type: "ForumPost", model_id: forum_post.id }) %>)</li>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if forum_post.bulk_update_request.present? %>
|
<% if forum_post.bulk_update_request.present? %>
|
||||||
<ul class="votes" id="forum-post-votes-for-<%= forum_post.id %>">
|
<ul class="votes" id="forum-post-votes-for-<%= forum_post.id %>">
|
||||||
|
|||||||
@@ -10,8 +10,11 @@ class PopupMenuComponent {
|
|||||||
target: "a.popup-menu-button",
|
target: "a.popup-menu-button",
|
||||||
placement: "bottom-start",
|
placement: "bottom-start",
|
||||||
trigger: "click",
|
trigger: "click",
|
||||||
|
animation: null,
|
||||||
content: PopupMenuComponent.content,
|
content: PopupMenuComponent.content,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(document).on("click.danbooru", ".popup-menu-content", PopupMenuComponent.onMenuItemClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
static content(element) {
|
static content(element) {
|
||||||
@@ -19,6 +22,12 @@ class PopupMenuComponent {
|
|||||||
$content.show();
|
$content.show();
|
||||||
return $content.get(0);
|
return $content.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hides the menu when a menu item is clicked.
|
||||||
|
static onMenuItemClicked(event) {
|
||||||
|
let tippy = $(event.target).parents("[data-tippy-root]").get(0)._tippy;
|
||||||
|
tippy.hide();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(PopupMenuComponent.initialize);
|
$(document).ready(PopupMenuComponent.initialize);
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
div.popup-menu {
|
div.popup-menu {
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
a.popup-menu-button {
|
a.popup-menu-button {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -8,7 +10,8 @@ div.popup-menu {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
color: var(--muted-text-color);
|
color: var(--muted-text-color);
|
||||||
|
|
||||||
&:hover {
|
&:focus, &:hover {
|
||||||
|
color: var(--link-color);
|
||||||
background-color: var(--subnav-menu-background-color);
|
background-color: var(--subnav-menu-background-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,8 +19,12 @@ div.popup-menu {
|
|||||||
ul.popup-menu-content {
|
ul.popup-menu-content {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
||||||
.icon {
|
li {
|
||||||
width: 1.5em;
|
margin: 0 2em 0.25em 0;
|
||||||
|
|
||||||
|
i.icon {
|
||||||
|
width: 2em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import Rails from '@rails/ujs';
|
import Rails from '@rails/ujs';
|
||||||
|
import { hideAll } from 'tippy.js';
|
||||||
|
|
||||||
let Utility = {};
|
let Utility = {};
|
||||||
|
|
||||||
@@ -70,6 +71,9 @@ Utility.dialog = function(title, html) {
|
|||||||
$dialog.find("form").on("submit.danbooru", function() {
|
$dialog.find("form").on("submit.danbooru", function() {
|
||||||
$dialog.dialog("close");
|
$dialog.dialog("close");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// XXX hides the popup menu when the Report comment button is clicked.
|
||||||
|
hideAll({ duration: 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
Utility.keydown = function(keys, namespace, handler, selector = document) {
|
Utility.keydown = function(keys, namespace, handler, selector = document) {
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ menu {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
li {
|
> li {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 0.2em;
|
padding: 0 0.2em;
|
||||||
display: inline;
|
display: inline;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ div.list-of-messages {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
menu {
|
menu {
|
||||||
li {
|
> li {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-right: 1.5em;
|
margin-right: 1.5em;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,11 +113,6 @@ class Comment < ApplicationRecord
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def voted_by?(user)
|
|
||||||
return false if user.is_anonymous?
|
|
||||||
user.id.in?(votes.map(&:user_id))
|
|
||||||
end
|
|
||||||
|
|
||||||
def quoted_response
|
def quoted_response
|
||||||
DText.quote(body, creator.name)
|
DText.quote(body, creator.name)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -20,12 +20,7 @@ class CommentPolicy < ApplicationPolicy
|
|||||||
end
|
end
|
||||||
|
|
||||||
def reply?
|
def reply?
|
||||||
create? && !record.is_deleted?
|
!record.is_deleted?
|
||||||
end
|
|
||||||
|
|
||||||
def vote?
|
|
||||||
# XXX should use CommentVotePolicy
|
|
||||||
unbanned? && !record.is_deleted?
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def permitted_attributes_for_create
|
def permitted_attributes_for_create
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
Danbooru.Utility.notice("Vote saved");
|
var $comment = $("article#comment_<%= @comment.id %>");
|
||||||
$(".comment[data-id=<%= @comment.id %>]").attr("data-is-voted", "true");
|
$comment.replaceWith("<%= j render_comment(@comment, current_user: CurrentUser.user) %>");
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
Danbooru.Utility.notice("Removed vote");
|
var $comment = $("article#comment_<%= @comment.id %>");
|
||||||
$(".comment[data-id=<%= @comment.id %>]").attr("data-is-voted", "false");
|
$comment.replaceWith("<%= j render_comment(@comment, current_user: CurrentUser.user) %>");
|
||||||
|
|||||||
Reference in New Issue
Block a user