Added collapsed hidden comments to author's article/podcast episode view (#14018)

* Handling hiding/collapsing hidden comments client side

* Updated comment quality text

* Added placeholder for comments against podcast episodes

* Added logic for encompassing co-author-ids in articles

* Removed rspecs validating non-presence of hidden comments in dom

* Fixed hiding flow on comments page for a commentable

* Fixed e2e specs

* Addressed feedback on e2e tests
This commit is contained in:
Akash Srivastava 2021-11-03 09:38:04 +05:30 committed by GitHub
parent 71e90a41f5
commit 4cb48768f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 153 additions and 37 deletions

View file

@ -197,6 +197,8 @@ function initializeCommentsPage() {
}
}
listenForDetailsToggle();
handleHiddenComments(commentableType);
}
function toggleCodeOfConduct() {
@ -554,24 +556,27 @@ function handleImageUpload(event, randomIdNumber) {
}
}
function updateItemSummaryHtml(item) {
var itemSummaryContent = item.getElementsByClassName("js-collapse-comment-content")[0];
var usernames = item.getElementsByClassName("js-comment-username");
var number = "";
if (usernames.length > 1) {
number = " + " + (usernames.length - 1) + " replies"
}
var itemUsername = usernames[0].textContent + number
if (item.open) {
itemSummaryContent.innerHTML = "";
} else {
itemSummaryContent.innerHTML = itemUsername;
}
}
function listenForDetailsToggle() {
var detailItems = document.querySelectorAll(".js-comment-wrapper");
for (var i = 0; i < detailItems.length; i++) {
detailItems[i].addEventListener("toggle", event => {
var item = event.target;
var itemSummaryContent = item.getElementsByClassName("js-collapse-comment-content")[0];
var usernames = item.getElementsByClassName("js-comment-username");
var number = "";
if (usernames.length > 1) {
number = " + " + (usernames.length - 1) + " replies"
}
var itemUsername = usernames[0].textContent + number
if (item.open) {
itemSummaryContent.innerHTML = "";
} else {
itemSummaryContent.innerHTML = itemUsername;
}
item.getElementsByTagName("SUMMARY")[0].blur();
updateItemSummaryHtml(item);
});
}
}
@ -589,3 +594,55 @@ function updateCommentsCount() {
commentsCountDiv.dataset.commentsCount = commentsCountData;
commentsCountDiv.innerHTML = `(${commentsCountData})`
}
function handleHiddenComments(commentableType){
const currentUser = userData();
const commentableAuthorIds = [];
let coAuthorIds = '';
if(commentableType === "Article"){
const articleContainer = document.querySelector('#article-show-container');
if(articleContainer){
commentableAuthorIds.push(articleContainer?.dataset?.authorId);
coAuthorIds = articleContainer?.dataset?.coAuthorIds;
if(coAuthorIds){
coAuthorIds.split(',').forEach(coAuthorId => {
commentableAuthorIds.push(coAuthorId);
});
}
}
else {
const commentsContainer = document.querySelector('#comments-container');
if(commentsContainer){
commentableAuthorIds.push(commentsContainer?.dataset?.commentableAuthorId);
coAuthorIds = commentsContainer?.dataset?.commentableCoAuthorIds;
if(coAuthorIds){
coAuthorIds.split(',').forEach(coAuthorId => {
commentableAuthorIds.push(coAuthorId);
});
}
}
}
} else if(commentableType === "PodcastEpisode"){
const podCastEpisodeContainer = document.querySelector('.podcast-episode-container');
if(podCastEpisodeContainer){
commentableAuthorIds.push(podCastEpisodeContainer.dataset.creatorId);
}
}
if (commentableAuthorIds.includes(currentUser?.id?.toString())){
collapseCommentsHiddenByCommentableUser();
}
else {
document.querySelectorAll('.comment-hidden-by-commentable-user, .details-comment-hidden-by-commentable-user').forEach(element => {
element.classList.add('hidden');
})
}
}
function collapseCommentsHiddenByCommentableUser() {
document.querySelectorAll(".js-comment-wrapper.details-comment-hidden-by-commentable-user").forEach(item => {
if (item.querySelectorAll('.comment-form').length === 0){
item.open = false;
updateItemSummaryHtml(item);
}
})
}

View file

@ -82,6 +82,7 @@
id="article-show-container"
data-article-id="<%= @article.id %>"
data-author-id="<%= @article.user_id %>"
data-co-author-ids="<%= @article.co_author_ids.join(",") %>"
data-path="<%= @article.path %>"
data-published="<%= @article.published? %>"
data-pin-path="<%= stories_feed_pinned_article_path %>"

View file

@ -1,6 +1,6 @@
<% if comment && comment.user && !should_be_hidden?(comment, @root_comment) %>
<% if comment && comment.user %>
<% if comment.depth < 3 %>
<details class="comment-wrapper js-comment-wrapper comment-wrapper--deep-<%= comment.depth %> <%= comment_class(comment, is_view_root: is_view_root) %>" open>
<details class="comment-wrapper js-comment-wrapper comment-wrapper--deep-<%= comment.depth %> <%= comment_class(comment, is_view_root: is_view_root) %> <%= should_be_hidden?(comment, @root_comment) ? "details-comment-hidden-by-commentable-user" : "" %>" open>
<summary>
<span class="<% if comment.depth > 0 %>mx-0<% else %>m:mx-1<% end %> inline-block align-middle">
<%= inline_svg_tag("collapse.svg", aria: true, class: "crayons-icon expanded", title: t("views.comments.collapse")) %>
@ -17,6 +17,7 @@
<%= comment_class(comment, is_view_root: is_view_root) %>
comment--deep-<%= comment.depth %>
<%= "comment--too-deep" if comment.depth > 3 %>
<%= should_be_hidden?(comment, @root_comment) ? "comment-hidden-by-commentable-user" : "" %>
"
data-comment-id="<%= comment.id %>"
data-path="<%= commentable&.path %>/comments/<%= comment.id_code_generated %>"

View file

@ -7,6 +7,10 @@
<% if comment.hidden_by_commentable_user %>
<div class="low-quality-comment-marker comment__quality-marker">
<%= inline_svg_tag("info.svg", aria: true, class: "crayons-icon mr-2", title: t("views.comments.quality.hidden.icon")) %>
<%= t("views.comments.quality.hidden.text") %>
<% if @root_comment %>
<%= t("views.comments.quality.hidden.text.visible_in_permalink") %>
<% else %>
<%= t("views.comments.quality.hidden.text.accessible_via_permalink") %>
<% end %>
</div>
<% end %>

View file

@ -124,7 +124,9 @@
class="crayons-card text-padding min-w-0 z-elevate"
id="comments-container"
data-commentable-id="<%= @commentable&.id %>"
data-commentable-type="<%= @commentable&.class&.name %>">
data-commentable-type="<%= @commentable&.class&.name %>"
data-commentable-author-id="<%= @commentable&.user_id %>"
data-commentable-co-author-ids="<%= @commentable&.co_author_ids&.join(",") %>">
<% unless @root_comment %>
<%= render "form",

View file

@ -28,7 +28,7 @@
<% end %>
<main id="main-content" class="podcast-episode-container" data-meta="<%= @episode.decorate.mobile_player_metadata.to_json %>">
<main id="main-content" class="podcast-episode-container" data-meta="<%= @episode.decorate.mobile_player_metadata.to_json %>" data-creator-id="<%= @podcast.creator_id %>">
<div class="hero">
<div class="title" style="background:#<%= @podcast.main_color_hex %>">
<h2>

View file

@ -72,7 +72,9 @@ en:
conduct: View Code of Conduct
hidden:
icon: Info
text: Comment hidden by post author - thread only visible in this permalink
text:
visible_in_permalink: Comment hidden by post author - thread only visible in this permalink
accessible_via_permalink: Comment hidden by post author - thread only accessible via permalink
write:
errors:
one: '1 error prohibited this comment from being saved:'

View file

@ -0,0 +1,24 @@
describe('Hiding/unhiding comments on an article', () => {
beforeEach(() => {
cy.testSetup();
cy.fixture('users/adminUser.json').as('user');
cy.get('@user').then((user) => {
cy.loginAndVisit(user, '/admin_mcadmin/test-article-slug');
});
});
describe('Admin visits the article authored by them', () => {
it('Hides a comment and then unhides it from the same screen', () => {
cy.findByRole('button', { name: 'Toggle dropdown menu' }).click();
cy.findByRole('link', { name: "Hide Admin McAdmin's comment" }).click();
cy.findByRole('button', { name: 'Toggle dropdown menu' }).should(
'not.be.visible',
);
cy.findByRole('img', { name: 'Expand' }).click();
cy.findByRole('button', { name: 'Toggle dropdown menu' }).click();
cy.findByRole('link', { name: "Unhide Admin McAdmin's comment" }).click();
cy.findByRole('img', { name: 'Expand' }).should('not.exist');
});
});
});

View file

@ -50,4 +50,14 @@ describe('View article discussion', () => {
.first()
.findByRole('button', { name: 'Edit profile' });
});
it('does not see hidden comments on an article not authored by them', () => {
cy.visit('/admin_mcadmin/test-article-with-hidden-comments-slug');
cy.findByText(/Some comments have been hidden by the post's author/).should(
'exist',
);
cy.findByRole('button', { name: 'Toggle dropdown menu' }).should(
'not.exist',
);
});
});

View file

@ -71,12 +71,6 @@ RSpec.describe "Comments", type: :request do
expect(response.body).to include(CGI.escapeHTML(comment.title(150)))
expect(response.body).to include(child.processed_html)
end
it "does not display the comment if it is hidden" do
child.update(hidden_by_commentable_user: true)
get comment.path
expect(response.body).not_to include child.processed_html
end
end
context "when the comment is two levels nested and hidden" do # child of a child
@ -139,23 +133,11 @@ RSpec.describe "Comments", type: :request do
expect(response.body).not_to include(third_level_child.processed_html)
end
it "does not show the hidden comment's children in the article's comments section" do
fourth_level_child
get "#{article.path}/comments"
expect(response.body).not_to include(fourth_level_child.processed_html)
end
it "does not show the hidden comment in its parent's permalink" do
get second_level_child.path
expect(response.body).not_to include(third_level_child.processed_html)
end
it "does not show the hidden comment's child in its parent's permalink" do
fourth_level_child
get second_level_child.path
expect(response.body).not_to include(fourth_level_child.processed_html)
end
it "shows the comment in the permalink" do
get third_level_child.path
expect(response.body).to include(third_level_child.processed_html)

View file

@ -375,6 +375,39 @@ end
##############################################################################
seeder.create_if_doesnt_exist(Article, "slug", "test-article-with-hidden-comments-slug") do
markdown = <<~MARKDOWN
---
title: Test article with hidden comments
published: true
cover_image: #{Faker::Company.logo}
---
#{Faker::Hipster.paragraph(sentence_count: 2)}
#{Faker::Markdown.random}
#{Faker::Hipster.paragraph(sentence_count: 2)}
MARKDOWN
article = Article.create!(
body_markdown: markdown,
featured: true,
show_comments: true,
user_id: admin_user.id,
slug: "test-article-with-hidden-comments-slug",
any_comments_hidden: true,
)
comment_attributes = {
body_markdown: Faker::Hipster.paragraph(sentence_count: 1),
user_id: admin_user.id,
commentable_id: article.id,
commentable_type: "Article",
hidden_by_commentable_user: true
}
Comment.create!(comment_attributes)
end
##############################################################################
seeder.create_if_doesnt_exist(Article, "title", "Organization test article") do
markdown = <<~MARKDOWN
---