From 07bdc6eab01008ace16a323da9311226aed8f231 Mon Sep 17 00:00:00 2001 From: evazion Date: Mon, 18 Jan 2021 05:03:35 -0600 Subject: [PATCH] comments: rework thresholded comments. Previously thresholded comments were hidden completely. You had to click the "Show X hidden comments" button to unhide all hidden comments in a thread. Now it works like this: * When a comment is below your threshold, the comment text is hidden and replaced by a `[hidden]` link, which you can click to unhide the comment. * When a comment is at half your threshold (for example, your threshold is -8 but the comment is at -4), then the comment is greyed out. This means that comments aren't completely hidden, they're just collapsed, so you can see the commenter and the score without unhiding the comment. It also means you don't have to scroll back up to unhide a comment, and threads aren't disrupted by comments being secretly hidden (which is confusing when people are replying to hidden comments, which forces you to go back up and unhide to find). --- app/components/application_component.rb | 3 ++ app/components/comment_component.rb | 19 ++++--- .../comment_component.html.erb | 13 +++-- .../comment_component/comment_component.scss | 7 ++- app/components/comment_section_component.rb | 28 ++++++++++ .../comment_section_component.html.erb | 20 +++++++ app/controllers/posts_controller.rb | 5 -- app/helpers/comments_helper.rb | 9 ---- app/helpers/components_helper.rb | 17 ++++++ app/helpers/posts_helper.rb | 8 --- app/javascript/src/javascripts/comments.js | 8 +++ .../src/styles/specific/comments.scss | 24 ++------- app/models/comment.rb | 15 ------ app/models/post.rb | 2 +- app/views/comments/_index_by_post.html.erb | 16 +++--- app/views/comments/index_for_post.js.erb | 6 +-- .../comments/partials/index/_list.html.erb | 30 ----------- app/views/posts/show.html.erb | 2 +- test/components/comment_component_test.rb | 28 ++++++++++ .../comment_section_component_test.rb | 50 ++++++++++++++++++ test/functional/comments_controller_test.rb | 35 +------------ test/functional/posts_controller_test.rb | 52 ------------------- 22 files changed, 196 insertions(+), 201 deletions(-) create mode 100644 app/components/comment_section_component.rb create mode 100644 app/components/comment_section_component/comment_section_component.html.erb delete mode 100644 app/helpers/comments_helper.rb create mode 100644 app/helpers/components_helper.rb delete mode 100644 app/views/comments/partials/index/_list.html.erb create mode 100644 test/components/comment_section_component_test.rb diff --git a/app/components/application_component.rb b/app/components/application_component.rb index 3db4d0451..98d567fbd 100644 --- a/app/components/application_component.rb +++ b/app/components/application_component.rb @@ -1,2 +1,5 @@ class ApplicationComponent < ViewComponent::Base + def policy(subject) + Pundit.policy!(current_user, subject) + end end diff --git a/app/components/comment_component.rb b/app/components/comment_component.rb index 537bf654f..8dfede7f3 100644 --- a/app/components/comment_component.rb +++ b/app/components/comment_component.rb @@ -2,17 +2,8 @@ class CommentComponent < ApplicationComponent attr_reader :comment, :context, :dtext_data, :show_deleted, :current_user - delegate :link_to_user, :time_ago_in_words_tagged, :format_text, :policy, to: :helpers + delegate :link_to_user, :time_ago_in_words_tagged, :format_text, to: :helpers - def self.with_collection(comments, current_user:, **options) - dtext_data = DText.preprocess(comments.map(&:body)) - # XXX - #comments = comments.includes(:moderation_reports) if Pundit.policy!(current_user, ModerationReport).show? - - super(comments, current_user: current_user, dtext_data: dtext_data, **options) - end - - # XXX calls to pundit policy don't respect current_user. def initialize(comment:, current_user:, context: nil, dtext_data: nil, show_deleted: false) @comment = comment @context = context @@ -25,6 +16,14 @@ class CommentComponent < ApplicationComponent !comment.is_deleted? || show_deleted || current_user.is_moderator? end + def dimmed? + !comment.is_sticky? && comment.score < current_user.comment_threshold/2.0 + end + + def thresholded? + !comment.is_sticky? && comment.score < current_user.comment_threshold + end + def has_moderation_reports? policy(ModerationReport).show? && comment.moderation_reports.present? end diff --git a/app/components/comment_component/comment_component.html.erb b/app/components/comment_component/comment_component.html.erb index 8f5ef5e88..45cb60574 100644 --- a/app/components/comment_component/comment_component.html.erb +++ b/app/components/comment_component/comment_component.html.erb @@ -8,7 +8,8 @@ data-do-not-bump-post="<%= comment.do_not_bump_post? %>" data-is-deleted="<%= comment.is_deleted? %>" data-is-sticky="<%= comment.is_sticky? %>" - data-below-threshold="<%= comment.score < current_user.comment_threshold %>" + data-is-dimmed="<%= dimmed? %>" + data-is-thresholded="<%= thresholded? %>" data-is-reported="<%= has_moderation_reports? %>" data-is-voted="<%= comment.voted_by?(current_user) %>">
@@ -21,10 +22,14 @@ <%= link_to time_ago_in_words_tagged(comment.created_at), post_path(comment.post, anchor: "comment_#{comment.id}"), class: "message-timestamp" %>
-
+ <% if thresholded? %> + <%= link_to "[hidden]", "javascript:void(0)", class: "unhide-comment-link" %> + <% end %> + + <%= tag.div class: "body prose", style: ("display: none;" if thresholded?) do %> <%= format_text(comment.body, data: dtext_data) %> -
- <%= render "application/update_notice", record: comment %> + <%= render "application/update_notice", record: comment %> + <% end %> <% if policy(comment).create? %> diff --git a/app/components/comment_component/comment_component.scss b/app/components/comment_component/comment_component.scss index 442c0f343..edb5ce61f 100644 --- a/app/components/comment_component/comment_component.scss +++ b/app/components/comment_component/comment_component.scss @@ -21,7 +21,7 @@ article.comment { } } - &[data-below-threshold="true"][data-is-sticky="false"] { + &[data-is-dimmed="true"] { opacity: 0.3; &:hover { @@ -29,6 +29,11 @@ article.comment { } } + .unhide-comment-link { + margin-bottom: 1em; + display: block; + } + .moderation-report-notice { font-weight: bold; color: var(--moderation-report-text-color); diff --git a/app/components/comment_section_component.rb b/app/components/comment_section_component.rb new file mode 100644 index 000000000..341ea6c8e --- /dev/null +++ b/app/components/comment_section_component.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class CommentSectionComponent < ApplicationComponent + attr_reader :post, :comments, :current_user, :limit, :dtext_data + + def initialize(post:, current_user:, limit: nil) + @post = post + @current_user = current_user + @limit = limit + + @comments = @post.comments.order(id: :asc) + @comments = @comments.includes(:creator) + @comments = @comments.includes(:votes) if !current_user.is_anonymous? + @comments = @comments.includes(:moderation_reports) if policy(ModerationReport).show? + @comments = @comments.last(limit) if limit.present? + + @dtext_data = DText.preprocess(@comments.map(&:body)) + end + + def has_unloaded_comments? + unloaded_comment_count > 0 + end + + def unloaded_comment_count + return 0 if limit.nil? + [post.comments.size - limit, 0].max + end +end diff --git a/app/components/comment_section_component/comment_section_component.html.erb b/app/components/comment_section_component/comment_section_component.html.erb new file mode 100644 index 000000000..882ab186c --- /dev/null +++ b/app/components/comment_section_component/comment_section_component.html.erb @@ -0,0 +1,20 @@ +
+ <% if has_unloaded_comments? %> + <%= link_to "Show #{pluralize unloaded_comment_count, "more comment"}", comments_path(post_id: post.id), class: "show-all-comments-link", remote: true %> + <% end %> + +
+ <% if comments.present? %> + <%= render CommentComponent.with_collection(comments, current_user: current_user, context: :index_by_post, dtext_data: dtext_data) %> + <% else %> +

There are no comments.

+ <% end %> +
+ + <% if policy(Comment).create? %> +
+

<%= link_to "Post comment", new_comment_path(comment: { post_id: post.id }), class: "expand-comment-response" %>

+ <%= render "comments/form", comment: post.comments.new, hidden: true %> +
+ <% end %> +
diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index ff51ce9bc..891cf061a 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -23,11 +23,6 @@ class PostsController < ApplicationController @post = authorize Post.find(params[:id]) if request.format.html? - @comments = @post.comments - @comments = @comments.includes(:creator) - @comments = @comments.includes(:votes) if CurrentUser.is_member? - @comments = @comments.unhidden(CurrentUser.user) - include_deleted = @post.is_deleted? || (@post.parent_id.present? && @post.parent.is_deleted?) || CurrentUser.user.show_deleted_children? @sibling_posts = @post.parent.present? ? @post.parent.children : Post.none @sibling_posts = @sibling_posts.undeleted unless include_deleted diff --git a/app/helpers/comments_helper.rb b/app/helpers/comments_helper.rb deleted file mode 100644 index be2d52e4e..000000000 --- a/app/helpers/comments_helper.rb +++ /dev/null @@ -1,9 +0,0 @@ -module CommentsHelper - def render_comment(comment, **options) - render CommentComponent.new(comment: comment, **options) - end - - def render_comment_list(comments, **options) - render CommentComponent.with_collection(comments, current_user: CurrentUser.user, **options) - end -end diff --git a/app/helpers/components_helper.rb b/app/helpers/components_helper.rb new file mode 100644 index 000000000..48443a217 --- /dev/null +++ b/app/helpers/components_helper.rb @@ -0,0 +1,17 @@ +module ComponentsHelper + def post_preview(post, **options) + render PostPreviewComponent.new(post: post, **options) + end + + def post_previews_html(posts, **options) + render PostPreviewComponent.with_collection(posts, **options) + end + + def render_comment(comment, **options) + render CommentComponent.new(comment: comment, **options) + end + + def render_comment_section(post, **options) + render CommentSectionComponent.new(post: post, **options) + end +end diff --git a/app/helpers/posts_helper.rb b/app/helpers/posts_helper.rb index 12f4c23aa..d43948dd8 100644 --- a/app/helpers/posts_helper.rb +++ b/app/helpers/posts_helper.rb @@ -1,12 +1,4 @@ module PostsHelper - def post_preview(post, **options) - render PostPreviewComponent.new(post: post, **options) - end - - def post_previews_html(posts, **options) - render PostPreviewComponent.with_collection(posts, **options) - end - def reportbooru_enabled? Danbooru.config.reportbooru_server.present? && Danbooru.config.reportbooru_key.present? end diff --git a/app/javascript/src/javascripts/comments.js b/app/javascript/src/javascripts/comments.js index aad19b7ca..968c7888e 100644 --- a/app/javascript/src/javascripts/comments.js +++ b/app/javascript/src/javascripts/comments.js @@ -4,6 +4,7 @@ Comment.initialize_all = function() { if ($("#c-posts").length || $("#c-comments").length) { $(document).on("click.danbooru.comment", ".edit_comment_link", Comment.show_edit_form); $(document).on("click.danbooru.comment", ".expand-comment-response", Comment.show_new_comment_form); + $(document).on("click.danbooru.comment", ".unhide-comment-link", Comment.unhide_comment); } } @@ -20,6 +21,13 @@ Comment.show_edit_form = function(e) { e.preventDefault(); } +Comment.unhide_comment = function(e) { + let $comment = $(this).closest(".comment"); + $comment.find(".unhide-comment-link").hide(); + $comment.find(".body").show(); + e.preventDefault(); +} + $(document).ready(function() { Comment.initialize_all(); }); diff --git a/app/javascript/src/styles/specific/comments.scss b/app/javascript/src/styles/specific/comments.scss index 47f01878f..6dd2745bd 100644 --- a/app/javascript/src/styles/specific/comments.scss +++ b/app/javascript/src/styles/specific/comments.scss @@ -1,20 +1,10 @@ @import "../base/000_vars.scss"; -div.comments-for-post { - div.moderation-comments-notice { - margin: 1em 0; - font-weight: bold; - color: var(--moderation-report-text-color); - } - - div.hidden-comments-notice { - margin: 1em 0; - } -} - div#c-comments { - div#a-index, div#a-show { + div#a-index { div.header { + margin-bottom: 1em; + span.info { margin-right: 1.5em; } @@ -58,7 +48,7 @@ div#c-comments { text-align: center; } - div.comments-for-post { + div.comment-section { flex: 1; } } @@ -89,12 +79,6 @@ form.edit_comment div.input.boolean { width: auto; height: auto; } - - div.comments-for-post { - div.header div.row span.info { - display: block; - } - } } } } diff --git a/app/models/comment.rb b/app/models/comment.rb index e18f27276..041b47ee5 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -118,21 +118,6 @@ class Comment < ApplicationRecord user.id.in?(votes.map(&:user_id)) end - def visibility(user) - return :invisible if is_deleted? && !user.is_moderator? - return :hidden if is_deleted? && user.is_moderator? - return :hidden if score < user.comment_threshold && !is_sticky? - return :visible - end - - def self.hidden(user) - select { |comment| comment.visibility(user) == :hidden } - end - - def self.unhidden(user) - select { |comment| comment.visibility(user) == :visible } - end - def quoted_response DText.quote(body, creator.name) end diff --git a/app/models/post.rb b/app/models/post.rb index 53092b64f..0640bad28 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -49,7 +49,7 @@ class Post < ApplicationRecord has_many :appeals, :class_name => "PostAppeal", :dependent => :destroy has_many :votes, :class_name => "PostVote", :dependent => :destroy has_many :notes, :dependent => :destroy - has_many :comments, -> {order("comments.id")}, :dependent => :destroy + has_many :comments, :dependent => :destroy has_many :children, -> {order("posts.id")}, :class_name => "Post", :foreign_key => "parent_id" has_many :approvals, :class_name => "PostApproval", :dependent => :destroy has_many :disapprovals, :class_name => "PostDisapproval", :dependent => :destroy diff --git a/app/views/comments/_index_by_post.html.erb b/app/views/comments/_index_by_post.html.erb index d04d9c175..1e976ab28 100644 --- a/app/views/comments/_index_by_post.html.erb +++ b/app/views/comments/_index_by_post.html.erb @@ -4,13 +4,15 @@ <% end %> <% @posts.select(&:visible?).each do |post| %> - <% if post.comments.unhidden(CurrentUser.user).any? || post.comments.hidden(CurrentUser.user).any? %> - <%= tag.div id: "post_#{post.id}", **PostPreviewComponent.new(post: post).article_attrs("post") do %> -
- <%= link_to(image_tag(post.preview_file_url), post_path(post)) %> -
- <%= render "comments/partials/index/list", post: post, comments: post.comments.unhidden(CurrentUser.user).last(6), page: :comments %> - <% end %> + <%= tag.div id: "post_#{post.id}", **PostPreviewComponent.new(post: post).article_attrs("post") do %> +
+ <%= link_to(image_tag(post.preview_file_url), post_path(post)) %> +
+ +
+ <%= render "comments/partials/index/header", post: post %> + <%= render_comment_section(post, limit: 6, current_user: CurrentUser.user) %> +
<% end %> <% end %>
diff --git a/app/views/comments/index_for_post.js.erb b/app/views/comments/index_for_post.js.erb index e3fbbf04b..6f6a80c1a 100644 --- a/app/views/comments/index_for_post.js.erb +++ b/app/views/comments/index_for_post.js.erb @@ -1,5 +1,3 @@ -$("#threshold-comments-notice-for-<%= @post.id %>").hide(); - -var current_comment_section = $("div.comments-for-post[data-post-id=<%= @post.id %>] div.list-of-comments"); -current_comment_section.html("<%= j render_comment_list(@comments, context: :index_by_post) %>"); +var current_comment_section = $("div.comments-for-post[data-post-id=<%= @post.id %>]"); +current_comment_section.replaceWith("<%= j render_comment_section(@post, limit: nil, current_user: CurrentUser.user) %>"); $(window).trigger("danbooru:index_for_post", [<%= @post.id %>]); diff --git a/app/views/comments/partials/index/_list.html.erb b/app/views/comments/partials/index/_list.html.erb deleted file mode 100644 index 8b0311e3d..000000000 --- a/app/views/comments/partials/index/_list.html.erb +++ /dev/null @@ -1,30 +0,0 @@ -
- <% if page == :comments %> - <%= render "comments/partials/index/header", :post => post %> - <% end %> - - <% if post.comments.hidden(CurrentUser.user).any? || (page == :comments && post.comments.size > 6) %> -
- - <%= link_to "Show #{pluralize post.comments.hidden(CurrentUser.user).size, "hidden comment"}", comments_path(post_id: post.id), id: "show-all-comments-link", remote: true %> - -
- <% end %> - -
- <% if comments.present? %> - <%= render_comment_list(comments, context: :index_by_post) %> - <% elsif post.last_commented_at.present? %> -

There are no visible comments.

- <% else %> -

There are no comments.

- <% end %> -
- - <% if policy(Comment).create? %> -
-

<%= link_to "Post comment", new_comment_path(comment: { post_id: post.id }), :class => "expand-comment-response" %>

- <%= render "comments/form", comment: post.comments.new, hidden: true %> -
- <% end %> -
diff --git a/app/views/posts/show.html.erb b/app/views/posts/show.html.erb index 7e7edfb14..0a6d50aae 100644 --- a/app/views/posts/show.html.erb +++ b/app/views/posts/show.html.erb @@ -105,7 +105,7 @@ <% end %>
- <%= render "comments/partials/index/list", comments: @comments, post: @post, page: :post %> + <%= render_comment_section(@post, current_user: CurrentUser.user) %>