decidim-comments 0.27.10 → 0.28.0.rc4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/comments/comment/actions.erb +13 -7
  3. data/app/cells/decidim/comments/comment/alignment_badge.erb +1 -4
  4. data/app/cells/decidim/comments/comment/deletion_data.erb +9 -1
  5. data/app/cells/decidim/comments/comment/moderation_data.erb +1 -1
  6. data/app/cells/decidim/comments/comment/replies.erb +3 -0
  7. data/app/cells/decidim/comments/comment/show.erb +72 -35
  8. data/app/cells/decidim/comments/comment/votes.erb +14 -14
  9. data/app/cells/decidim/comments/comment_activity_cell.rb +11 -7
  10. data/app/cells/decidim/comments/comment_card_cell.rb +2 -2
  11. data/app/cells/decidim/comments/comment_cell.rb +9 -21
  12. data/app/cells/decidim/comments/comment_form/comment_as.erb +3 -3
  13. data/app/cells/decidim/comments/comment_form/opinion.erb +18 -0
  14. data/app/cells/decidim/comments/comment_form/show.erb +33 -16
  15. data/app/cells/decidim/comments/comment_form_cell.rb +9 -1
  16. data/app/cells/decidim/comments/comment_metadata_cell.rb +27 -0
  17. data/app/cells/decidim/comments/comment_s_cell.rb +27 -0
  18. data/app/cells/decidim/comments/comment_thread/show.erb +2 -5
  19. data/app/cells/decidim/comments/comment_thread_cell.rb +0 -6
  20. data/app/cells/decidim/comments/comments/add_comment.erb +1 -20
  21. data/app/cells/decidim/comments/comments/blocked_comments_warning.erb +1 -3
  22. data/app/cells/decidim/comments/comments/comments_loading.erb +1 -3
  23. data/app/cells/decidim/comments/comments/order_control.erb +11 -35
  24. data/app/cells/decidim/comments/comments/show.erb +8 -9
  25. data/app/cells/decidim/comments/comments/single_comment_warning.erb +6 -9
  26. data/app/cells/decidim/comments/comments/user_comments_blocked_warning.erb +9 -6
  27. data/app/cells/decidim/comments/comments_cell.rb +1 -1
  28. data/app/cells/decidim/comments/edit_comment_modal_form/show.erb +20 -15
  29. data/app/commands/decidim/comments/create_comment.rb +17 -5
  30. data/app/commands/decidim/comments/delete_comment.rb +1 -1
  31. data/app/commands/decidim/comments/update_comment.rb +14 -2
  32. data/app/commands/decidim/comments/vote_comment.rb +1 -1
  33. data/app/controllers/decidim/comments/comments_controller.rb +14 -9
  34. data/app/controllers/decidim/comments/votes_controller.rb +1 -1
  35. data/app/events/decidim/comments/comment_by_followed_user_event.rb +1 -1
  36. data/app/events/decidim/comments/comment_by_followed_user_group_event.rb +1 -1
  37. data/app/events/decidim/comments/comment_event.rb +2 -7
  38. data/app/events/decidim/comments/reply_created_event.rb +1 -1
  39. data/app/events/decidim/comments/user_group_mentioned_event.rb +1 -1
  40. data/app/events/decidim/comments/user_mentioned_event.rb +1 -1
  41. data/app/helpers/decidim/comments/comment_cells_helper.rb +1 -1
  42. data/app/jobs/decidim/comments/hide_all_created_by_author_job.rb +13 -0
  43. data/app/models/decidim/comments/comment.rb +9 -7
  44. data/app/models/decidim/comments/comment_vote.rb +0 -10
  45. data/app/models/decidim/comments/seed.rb +30 -14
  46. data/app/packs/entrypoints/decidim_comments.js +5 -0
  47. data/app/packs/src/decidim/comments/comments.component.js +27 -36
  48. data/app/packs/src/decidim/comments/comments.component.test.js +218 -240
  49. data/app/packs/src/decidim/comments/comments.component_for_testing.js +1 -1
  50. data/app/packs/src/decidim/comments/comments.js +20 -1
  51. data/app/packs/stylesheets/comments.scss +327 -0
  52. data/app/queries/decidim/comments/metrics/comments_metric_manage.rb +1 -1
  53. data/app/queries/decidim/comments/sorted_comments.rb +10 -10
  54. data/app/services/decidim/comments/comment_creation.rb +1 -1
  55. data/app/services/decidim/comments/new_comment_notification_creator.rb +8 -8
  56. data/app/views/decidim/comments/admin/shared/_availability_fields.html.erb +4 -9
  57. data/app/views/decidim/comments/comments/_comment.html.erb +1 -1
  58. data/app/views/decidim/comments/comments/_comments.html.erb +1 -1
  59. data/app/views/decidim/comments/comments/_delete.html.erb +2 -4
  60. data/app/views/decidim/comments/comments/_moderated.html.erb +2 -4
  61. data/app/views/decidim/comments/comments/create.js.erb +5 -3
  62. data/app/views/decidim/comments/comments/delete.js.erb +4 -1
  63. data/app/views/decidim/comments/comments/index.js.erb +8 -1
  64. data/app/views/decidim/comments/comments/reload.js.erb +1 -2
  65. data/app/views/decidim/comments/comments/update.js.erb +5 -4
  66. data/app/views/decidim/comments/votes/create.js.erb +5 -5
  67. data/config/assets.rb +3 -0
  68. data/config/locales/ar.yml +0 -16
  69. data/config/locales/bg.yml +0 -166
  70. data/config/locales/ca.yml +15 -17
  71. data/config/locales/cs.yml +8 -10
  72. data/config/locales/de.yml +7 -9
  73. data/config/locales/el.yml +3 -11
  74. data/config/locales/en.yml +10 -12
  75. data/config/locales/es-MX.yml +10 -12
  76. data/config/locales/es-PY.yml +10 -12
  77. data/config/locales/es.yml +16 -18
  78. data/config/locales/eu.yml +6 -8
  79. data/config/locales/fi-plain.yml +7 -9
  80. data/config/locales/fi.yml +11 -13
  81. data/config/locales/fr-CA.yml +9 -11
  82. data/config/locales/fr.yml +9 -11
  83. data/config/locales/ga-IE.yml +0 -4
  84. data/config/locales/gl.yml +0 -16
  85. data/config/locales/hu.yml +3 -11
  86. data/config/locales/id-ID.yml +0 -11
  87. data/config/locales/is-IS.yml +0 -8
  88. data/config/locales/it.yml +0 -16
  89. data/config/locales/ja.yml +6 -8
  90. data/config/locales/lb.yml +0 -16
  91. data/config/locales/lt.yml +7 -10
  92. data/config/locales/lv.yml +0 -11
  93. data/config/locales/nl.yml +0 -16
  94. data/config/locales/no.yml +0 -16
  95. data/config/locales/pl.yml +7 -11
  96. data/config/locales/pt-BR.yml +0 -18
  97. data/config/locales/pt.yml +0 -16
  98. data/config/locales/ro-RO.yml +6 -14
  99. data/config/locales/ru.yml +0 -11
  100. data/config/locales/sk.yml +0 -11
  101. data/config/locales/sq-AL.yml +0 -38
  102. data/config/locales/sv.yml +4 -18
  103. data/config/locales/tr-TR.yml +1 -13
  104. data/config/locales/uk.yml +0 -8
  105. data/config/locales/zh-CN.yml +0 -13
  106. data/config/locales/zh-TW.yml +1 -9
  107. data/lib/decidim/api/comment_type.rb +2 -2
  108. data/lib/decidim/api/commentable_interface.rb +1 -1
  109. data/lib/decidim/comments/comment_serializer.rb +1 -1
  110. data/lib/decidim/comments/comment_vote_serializer.rb +1 -1
  111. data/lib/decidim/comments/commentable.rb +1 -1
  112. data/lib/decidim/comments/comments_helper.rb +6 -3
  113. data/lib/decidim/comments/engine.rb +31 -1
  114. data/lib/decidim/comments/export.rb +1 -1
  115. data/lib/decidim/comments/test/factories.rb +9 -22
  116. data/lib/decidim/comments/test/shared_examples/comment_event.rb +4 -37
  117. data/lib/decidim/comments/test/shared_examples/comment_voted_event.rb +4 -4
  118. data/lib/decidim/comments/test/shared_examples/create_comment_context.rb +5 -5
  119. data/lib/decidim/comments/test/shared_examples/has_comments_availability_attributes.rb +2 -2
  120. data/lib/decidim/comments/test/shared_examples/translatable_comment.rb +3 -3
  121. data/lib/decidim/comments/version.rb +1 -1
  122. metadata +27 -24
  123. data/app/cells/decidim/comments/comment/author.erb +0 -1
  124. data/app/cells/decidim/comments/comment/utilities.erb +0 -41
  125. data/app/cells/decidim/comments/comment_m/footer.erb +0 -5
  126. data/app/cells/decidim/comments/comment_m/top.erb +0 -7
  127. data/app/cells/decidim/comments/comment_m_cell.rb +0 -29
  128. data/app/cells/decidim/comments/comment_thread/title.erb +0 -3
  129. data/config/locales/he-IL.yml +0 -1
  130. data/db/migrate/20240304092558_add_comment_vote_counter_cache_to_comments.rb +0 -21
  131. data/decidim-comments.gemspec +0 -33
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable id-length, max-lines */
2
- /* global spyOn, jest */
2
+ /* global jest */
3
3
 
4
4
  const $ = require("jquery");
5
5
 
@@ -8,14 +8,12 @@ const $ = require("jquery");
8
8
  // in order for them to define the $ variable correctly.
9
9
  window.$ = jest.fn().mockImplementation((...args) => $(...args));
10
10
  window.$.ajax = jest.fn().mockImplementation((...args) => $.ajax(...args));
11
-
12
- // Quill is expected by the input character counter
13
- import Quill from "quill"
14
- window.Quill = Quill
11
+ window.$.extend = jest.fn().mockImplementation((...args) => $.extend(...args));
15
12
 
16
13
  // Rails.ajax is used by the fetching/polling of the comments
17
14
  import Rails from "@rails/ujs";
18
15
  jest.mock("@rails/ujs");
16
+ window.Rails = Rails;
19
17
 
20
18
  // Fake timers for testing polling
21
19
  jest.useFakeTimers();
@@ -23,10 +21,9 @@ jest.useFakeTimers();
23
21
  import { createCharacterCounter } from "../../../../../../decidim-core/app/packs/src/decidim/input_character_counter";
24
22
  import Configuration from "../../../../../../decidim-core/app/packs/src/decidim/configuration";
25
23
  // Component is loaded with require because using import loads it before $ has been mocked
26
- // so tests aren't able to check the spied behaviours
24
+ // so tests are not able to check the spied behaviours
27
25
  const CommentsComponent = require("./comments.component_for_testing.js");
28
26
 
29
-
30
27
  // Create a dummy foundation jQuery method for the comments component to call
31
28
  $.fn.foundation = () => {};
32
29
 
@@ -48,28 +45,28 @@ describe("CommentsComponent", () => {
48
45
  const spyOnAddComment = (methodToSpy) => {
49
46
  addComment.each((i) => {
50
47
  addComment[i].$ = $(addComment[i]);
51
- addComment[i].opinionToggles = $(".opinion-toggle .button", addComment[i].$);
48
+ addComment[i].opinionToggles = $(".opinion-toggle button", addComment[i].$);
52
49
  addComment[i].commentForm = $("form", addComment[i].$);
53
50
  addComment[i].commentTextarea = $("textarea", addComment[i].commentForm);
54
51
 
55
52
  if (methodToSpy) {
56
- spyOn(addComment[i].opinionToggles, methodToSpy);
57
- spyOn(addComment[i].commentForm, methodToSpy);
58
- spyOn(addComment[i].commentTextarea, methodToSpy);
53
+ jest.spyOn(addComment[i].opinionToggles, methodToSpy);
54
+ jest.spyOn(addComment[i].commentForm, methodToSpy);
55
+ jest.spyOn(addComment[i].commentTextarea, methodToSpy);
59
56
  }
60
57
  });
61
58
 
62
- spyOn(window, "$").mockImplementation((...args) => {
59
+ jest.spyOn(window, "$").mockImplementation((...args) => {
63
60
  const jqSelector = args[0];
64
61
  const parent = args[1];
65
62
 
66
63
  if (jqSelector === document) {
67
64
  return $doc;
68
- } else if (jqSelector === ".order-by__dropdown .is-submenu-item a" && parent.is(subject.$element)) {
65
+ } else if (jqSelector === ".comment-order-by a.comment-order-by__item" && parent.is(subject.$element)) {
69
66
  return orderLinks;
70
67
  } else if (jqSelector === ".add-comment" && parent.is(subject.$element)) {
71
68
  return addComment;
72
- } else if (jqSelector === ".add-comment .opinion-toggle .button" && parent.is(subject.$element)) {
69
+ } else if (jqSelector === ".add-comment .opinion-toggle button" && parent.is(subject.$element)) {
73
70
  return allToggles;
74
71
  } else if (jqSelector === ".add-comment textarea" && parent.is(subject.$element)) {
75
72
  return allTextareas;
@@ -78,7 +75,7 @@ describe("CommentsComponent", () => {
78
75
  }
79
76
  const addCommentsArray = addComment.toArray();
80
77
  for (let i = 0; i < addCommentsArray.length; i += 1) {
81
- if (jqSelector === ".opinion-toggle .button" && parent.is(addCommentsArray[i].$)) {
78
+ if (jqSelector === ".opinion-toggle button" && parent.is(addCommentsArray[i].$)) {
82
79
  return addCommentsArray[i].opinionToggles;
83
80
  } else if (jqSelector === "form" && parent.is(addCommentsArray[i].$)) {
84
81
  return addCommentsArray[i].commentForm;
@@ -93,162 +90,186 @@ describe("CommentsComponent", () => {
93
90
  const generateCommentForm = (modelName, modelId) => {
94
91
  return `
95
92
  <form class="new_comment" id="new_comment_for_${modelName}_${modelId}" action="/comments?order=older" accept-charset="UTF-8" data-remote="true" method="post">
96
- <input name="utf8" type="hidden" value="" />
97
- <input type="hidden" value="commentable-gid" name="comment[commentable_gid]" />
98
- <input class="alignment-input" type="hidden" value="0" name="comment[alignment]" />
99
- <div class="field">
100
- <label for="add-comment-${modelName}-${modelId}-user-group-id">
101
- Comment as
102
- </label>
103
- <select id="add-comment-${modelName}-${modelId}-user-group-id" name="comment[user_group_id]">
104
- <option value="">Dwain Oberbrunner</option>
105
- <option value="4">Schmidt, Adams and Cassin</option>
106
- </select>
93
+ <input class="alignment-input" autocomplete="off" type="hidden" value="0" name="comment[alignment]">
94
+ <div class="comment__as">
95
+ <label for="add-comment-${modelName}-${modelId}-user-group-id">
96
+ Comment as
97
+ </label>
98
+ <select id="add-comment-${modelName}-${modelId}-user-group-id" name="comment[user_group_id]">
99
+ <option value="">Renetta Okuneva</option>
100
+ <option value="6">Pollich-Ratke</option>
101
+ </select>
102
+ </div>
103
+
104
+ <div class="form__wrapper gap-2">
105
+ <label class="show-for-sr" for="add-comment-${modelName}-${modelId}">
106
+ Comment
107
+ </label>
108
+ <span class="emoji__container">
109
+ <textarea
110
+ required="required"
111
+ maxlength="1000"
112
+ id="add-comment-${modelName}-${modelId}"
113
+ class="w-full rounded border min-h-[160px] border-text-gray-2"
114
+ placeholder="What do you think about this?"
115
+ data-remaining-characters="#add-comment-${modelName}-${modelId}-remaining-characters"
116
+ data-input-emoji="true"
117
+ name="comment[body]"
118
+ aria-describedby="add-comment-${modelName}-${modelId}-remaining-characters_sr"
119
+ data-input-emoji-initialized="true"
120
+ data-tribute="true">
121
+ </textarea>
122
+ <span class="emoji__trigger">
123
+ <button class="emoji__button" type="button" aria-label="Add emoji">
124
+ <svg aria-hidden="true" focusable="false" data-prefix="far" data-icon="smile" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512">
125
+ <path fill="currentColor" d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm-80-216c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm160 0c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm4 72.6c-20.8 25-51.5 39.4-84 39.4s-63.2-14.3-84-39.4c-8.5-10.2-23.7-11.5-33.8-3.1-10.2 8.5-11.5 23.6-3.1 33.8 30 36 74.1 56.6 120.9 56.6s90.9-20.6 120.9-56.6c8.5-10.2 7.1-25.3-3.1-33.8-10.1-8.4-25.3-7.1-33.8 3.1z">
126
+ </path>
127
+ </svg>
128
+ </button>
129
+ </span>
130
+ <span class="emoji__reference" style="position: absolute; display: block; bottom: -8px; right: -16px;"></span>
131
+ <span class="form-error">There is an error in this field.</span>
132
+ </span>
133
+ <span role="status" id="add-comment-${modelName}-${modelId}-remaining-characters_sr" class="sr-only remaining-character-count-sr">1000 characters left</span>
134
+ <span id="add-comment-${modelName}-${modelId}-remaining-characters" class="remaining-character-count show-erb-comment" aria-hidden="true">1000 characters left</span>
135
+ <div class="w-full text-right">
136
+ <button type="submit" class="button button__sm button__secondary" disabled="disabled">
137
+ <span>Publish comment</span>
138
+ <svg width="1em" height="1em" role="img" aria-hidden="true"><use href="/decidim-packs/media/images/remixicon.symbol-5540ed538fb6bd400d2a.svg#ri-chat-1-line" tabindex="-1"></use></svg>
139
+ </button>
107
140
  </div>
141
+ </div>
142
+ </form>
143
+ `;
144
+ };
108
145
 
109
- <div class="field">
110
- <label class="show-for-sr" for="add-comment-${modelName}-${modelId}">
111
- Comment
112
- </label>
113
- <div class="hashtags__container">
114
- <label for="comment_body">
115
- Body
116
- <span
117
- title=""
118
- data-tooltip="true"
119
- data-disable-hover="false"
120
- data-keep-on-hover="true"
121
- class="label-required has-tip"
122
- >
123
- <span aria-hidden="true">*</span><span class="show-for-sr">Required field</span>
146
+ const generateFlagModalForm = (commentId) => {
147
+ return `
148
+ <div id="flagModalComment${commentId}" data-dialog="flagModalComment${commentId}" role="dialog" tabindex="-1" aria-hidden="true" aria-labelledby="dialog-title-flagModalComment${commentId}" aria-modal="true"><div id="flagModalComment${commentId}-content"><button type="button" data-dialog-close="flagModalComment${commentId}" data-dialog-closable="" aria-label="Close modal">×</button>
149
+ <form class="modal__report form-defaults" novalidate="novalidate" data-abide="true" data-live-validate="true" data-validate-on-blur="true" action="/report?sgid=BAh7CEkiCGdpZAY6BkVUSSJBZ2lkOi8vZGVjaWRpbS1kZXZlbG9wbWVudC1hcHAvRGVjaWRpbTo6Q29tbWVudHM6OkNvbW1lbnQvODMyBjsAVEkiDHB1cnBvc2UGOwBUSSIMZGVmYXVsdAY7AFRJIg9leHBpcmVzX2F0BjsAVEkiHTIwMjMtMDEtMTlUMDM6MzA6MzMuNDM2WgY7AFQ%3D--7b3754f17d4b3f13b7065d98eba5b44a0d9af373" accept-charset="UTF-8" method="post"><input type="hidden" name="authenticity_token" value="4gZ0SkWxuyZ0SyUWhphWwAju8XO4c44aOJr1zGRfbGC19ZssM1mhifceP4zjs8e6UQbOWGO921OMR_XxS4PBxw" autocomplete="off">
150
+ <div data-dialog-container="">
151
+ <svg width="1em" height="1em" role="img" aria-hidden="true" class="inline-block align-middle"><use href="/decidim-packs/media/images/remixicon.symbol-5540ed538fb6bd400d2a.svg#ri-flag-line" tabindex="-1"></use></svg>
152
+ <h3 data-dialog-title="" id="dialog-title-flagModalComment${commentId}">
153
+ Report inappropriate content
154
+ </h3>
155
+ <div>
156
+ <p class="modal__report-text">
157
+ Is this content inappropriate?
158
+ </p>
159
+ <fieldset>
160
+ <legend>Reason</legend>
161
+ <input type="hidden" name="report[reason]" value="" autocomplete="off">
162
+ <div class="modal__report-container__radio">
163
+ <input id="spam" type="radio" value="spam" checked="checked" name="report[reason]">
164
+ <label for="spam">
165
+ Contains clickbait, advertising, scams or script bots.
166
+ </label>
167
+ </div>
168
+
169
+ <div class="modal__report-container__radio">
170
+ <input id="offensive" type="radio" value="offensive" name="report[reason]">
171
+ <label for="offensive">
172
+ Contains racism, sexism, slurs, personal attacks, death threats, suicide requests or any form of hate speech.
173
+ </label>
174
+ </div>
175
+
176
+ <div class="modal__report-container__radio">
177
+ <input id="does_not_belong" type="radio" value="does_not_belong" name="report[reason]">
178
+ <label for="does_not_belong">
179
+ Contains illegal activity, suicide threats, personal information, or something else you think does not belong on Reichel, Bernhard and Glover.
180
+ </label>
181
+ </div>
182
+ </fieldset>
183
+ <label for="flagModalComment${commentId}" class="text-gray-2">Additional comments<textarea class="w-full rounded border min-h-[160px] border-text-gray-2 mt-2" id="flagModalComment${commentId}" name="report[details]"></textarea></label>
184
+ </div>
185
+ </div>
186
+ <div data-dialog-actions="">
187
+ <button type="submit" class="button button__lg button__secondary">
188
+ <span>
189
+ Report
124
190
  </span>
125
- <textarea
126
- required="required"
127
- maxlength="1000"
128
- id="add-comment-Comment-${modelId}"
129
- rows="4"
130
- placeholder="What do you think about this?"
131
- data-tribute="true"
132
- data-remaining-characters="#add-comment-${modelName}-${modelId}-remaining-characters"
133
- name="comment[body]"
134
- ></textarea>
135
- <span class="form-error">There's an error in this field.</span>
136
- </label>
191
+ <svg width="1em" height="1em" role="img" aria-hidden="true"><use href="/decidim-packs/media/images/remixicon.symbol-5540ed538fb6bd400d2a.svg#ri-arrow-right-line" tabindex="-1"></use></svg>
192
+ </button>
137
193
  </div>
138
- <button type="submit" class="button button--sc" disabled="disabled">Send</button>
139
- <span id="add-comment-${modelName}-${modelId}-remaining-characters" class="remaining-character-count">1000 characters left</span>
140
- </div>
141
- </form>
194
+ </form>
195
+ </div>
142
196
  `;
143
- };
197
+ }
144
198
 
145
199
  const generateSingleComment = (commentId, content, replies = "") => {
146
200
  return `
147
- <div id="comment_${commentId}" class="comment comment--nested" data-comment-id="${commentId}">
201
+ <div id="comment_${commentId}" class="comment" data-comment-id="${commentId}">
148
202
  <div class="comment__header">
149
- <div class="author-data">
150
- <div class="author-data__main">
151
- <div class="author author--inline">
152
- <a href="/profiles/eusebio_rempel">
153
- <span class="author__avatar">
154
- <img alt="Avatar" src="/assets/decidim/default-avatar-123.svg" />
155
- </span>
156
- <span
157
- class="author__name m-none has-tip"
158
- data-position="top"
159
- data-show-on="medium"
160
- data-alignment="center"
161
- data-click-open="false"
162
- data-keep-on-hover="true"
163
- data-allow-html="true"
164
- data-template-classes="light expanded"
165
- data-tip-text="Tip text"
166
- title=""
167
- >Dwain Oberbrunner</span>
168
- </a>
169
- </div>
170
-
171
- <span>
172
- <time datetime="2020-09-28T17:15:08Z">28/09/2020 17:15</time>
203
+ <span class="font-bold">
204
+ <a class="flex items-center gap-2.5" href="/profiles/kathline">
205
+ <span class="rounded-full overflow-hidden inline-block w-6 h-6">
206
+ <img alt="Avatar: Buster Hammes" class="w-full h-full object-cover" src="/decidim-packs/media/images/default-avatar-aaa9e55bac5d7159b847.svg">
173
207
  </span>
174
- </div>
175
- <div class="author-data__extra">
176
- <button type="button" class="link-alt" data-open="flagModalComment${commentId}" title="Report inappropriate content" aria-controls="flagModalComment${commentId}" aria-haspopup="dialog" tabindex="0">
177
- <svg role="img" aria-hidden="true" class="icon--flag icon icon--small">
178
- <title></title>
179
- <use href="/assets/decidim/icons-123.svg#icon-flag"></use>
180
- </svg>
181
- <span class="show-for-sr">Report inappropriate content</span>
208
+ <span>Buster Hammes</span>
209
+ </a>
210
+ </span>
211
+ <span class="text-gray-2 text-sm"><time datetime="2022-12-15T11:19:22Z">4 days ago</time></span>
212
+ <details class="ml-auto">
213
+ <summary class="button button__sm button__text-secondary" aria-controls="toggle-context-menu-${commentId}">
214
+ <svg width="1em" height="1em" role="img" aria-hidden="true"><use href="/decidim-packs/media/images/remixicon.symbol-5540ed538fb6bd400d2a.svg#ri-more-line" tabindex="-1"></use></svg>
215
+ </summary>
216
+ <ul id="toggle-context-menu-${commentId}" class="dropdown dropdown__bottom divide-y divide-gray-3 px-4">
217
+ <li>
218
+ <button type="button" class="dropdown__item" data-dialog-open="flagModalComment${commentId}" title="Report" aria-controls="flagModalComment${commentId}" aria-haspopup="dialog" tabindex="0">
219
+ <svg width="1em" height="1em" role="img" aria-hidden="true"><use href="/decidim-packs/media/images/remixicon.symbol-5540ed538fb6bd400d2a.svg#ri-flag-line" tabindex="-1"></use></svg>
220
+ <span>Report</span>
182
221
  </button>
183
-
184
- <a title="Get link to single comment" href="/path/to/dummy/123?commentId=${commentId}#comment_${commentId}">
185
- <span class="show-for-sr">Get link to single comment</span>
186
- <svg role="img" aria-hidden="true" class="icon--link-intact icon icon--small">
187
- <title></title>
188
- <use href="/assets/decidim/icons-123.svg#icon-link-intact"></use>
189
- </svg>
190
- </a>
191
- </div>
192
- </div>
222
+ </li>
223
+ <li>
224
+ <a target="_blank" data-external-link="false" class="dropdown__item" title="Get link" tabindex="1" href="/processes/enim-consectetur/f/9/posts/2?commentId=${commentId}#comment_${commentId}">
225
+ <svg width="1em" height="1em" role="img" aria-hidden="true"><use href="/decidim-packs/media/images/remixicon.symbol-5540ed538fb6bd400d2a.svg#ri-share-line" tabindex="-1"></use></svg>
226
+ <span>Get link</span>
227
+ <span class="inline-block mx-0.5"><svg class="icon icon--external-link w-2 h-2 fill-current" role="img" aria-hidden="true"><title>external-link</title><use href="/decidim-packs/media/images/remixicon.symbol-5540ed538fb6bd400d2a.svg#icon-external-link"></use></svg><span class="sr-only">(External link)</span></span></a>
228
+ </li>
229
+ </ul>
230
+ </details>
231
+ ${generateFlagModalForm(commentId)}
193
232
  </div>
194
233
  <div class="comment__content">
195
- <p>${content}</p>
234
+ <div><p>${content}</p></div>
196
235
  </div>
197
- <div class="comment__footer">
236
+ <div class="comment__footer" data-component="accordion" role="presentation">
237
+ <div class="comment__footer-grid">
198
238
  <div class="comment__actions">
199
- <button class="comment__reply muted-link" aria-controls="comment${commentId}-reply" data-toggle="comment${commentId}-reply" aria-expanded="true">
200
- <svg role="img" aria-hidden="true" class="icon--pencil icon icon--small">
201
- <title></title>
202
- <use href="/assets/decidim/icons-123.svg#icon-pencil"></use>
203
- </svg>
204
- &nbsp;Reply
239
+ <button class="button button__sm button__text-secondary" data-controls="panel-comment${commentId}-reply" role="button" tabindex="0" aria-controls="panel-comment${commentId}-reply" aria-expanded="false" aria-disabled="false">
240
+ <svg width="1em" height="1em" role="img" aria-hidden="true"><use href="/decidim-packs/media/images/remixicon.symbol-5540ed538fb6bd400d2a.svg#ri-chat-1-line" tabindex="-1"></use></svg>
241
+ <span class="font-normal">Reply</span>
242
+ <svg width="1em" height="1em" role="img" aria-hidden="true"><use href="/decidim-packs/media/images/remixicon.symbol-5540ed538fb6bd400d2a.svg#ri-close-circle-line" tabindex="-1"></use></svg>
243
+ <span class="font-normal">Cancel reply</span>
205
244
  </button>
206
245
  </div>
207
-
208
246
  <div class="comment__votes">
209
247
  <form class="button_to" method="post" action="/comments/${commentId}/votes?weight=1" data-remote="true">
210
- <button class="comment__votes--up" title="I agree with this comment" type="submit">
211
- <span class="show-for-sr">I agree with this comment</span>
212
- <svg role="img" aria-hidden="true" class="icon--chevron-top icon icon--small">
213
- <title></title>
214
- <use href="/assets/decidim/icons-123.svg#icon-chevron-top"></use>
215
- </svg>
216
- <span class="comment__votes--count">0</span>
248
+ <button class="button button__sm button__text-secondary js-comment__votes--up" title="I agree with this comment" type="submit">
249
+ <svg width="1em" height="1em" role="img" aria-hidden="true"><use href="/decidim-packs/media/images/remixicon.symbol-5540ed538fb6bd400d2a.svg#ri-thumb-up-line" tabindex="-1"></use></svg>
250
+ <svg width="1em" height="1em" role="img" aria-hidden="true"><use href="/decidim-packs/media/images/remixicon.symbol-5540ed538fb6bd400d2a.svg#ri-thumb-up-fill" tabindex="-1"></use></svg>
251
+ <span>0</span>
217
252
  </button>
218
- <input type="hidden" name="authenticity_token" value="xyz123" />
253
+ <input type="hidden" name="authenticity_token" value="knr7y99HXbKv5sdm5OlghBlFsjIX7KOnIvHZ5-vXThb87Qszlh8j_CPxdbhsiqcIPAwvofsM9zR0vWFgojq6dA" autocomplete="off">
219
254
  </form>
220
-
221
255
  <form class="button_to" method="post" action="/comments/${commentId}/votes?weight=-1" data-remote="true">
222
- <button class="comment__votes--down" title="I disagree with this comment" type="submit">
223
- <span class="show-for-sr">I disagree with this comment</span>
224
- <svg role="img" aria-hidden="true" class="icon--chevron-bottom icon icon--small">
225
- <title></title>
226
- <use href="/assets/decidim/icons-123.svg#icon-chevron-bottom"></use>
227
- </svg>
228
- <span class="comment__votes--count">0</span>
256
+ <button class="button button__sm button__text-secondary js-comment__votes--down" title="I disagree with this comment" type="submit">
257
+ <svg width="1em" height="1em" role="img" aria-hidden="true"><use href="/decidim-packs/media/images/remixicon.symbol-5540ed538fb6bd400d2a.svg#ri-thumb-down-line" tabindex="-1"></use></svg>
258
+ <svg width="1em" height="1em" role="img" aria-hidden="true"><use href="/decidim-packs/media/images/remixicon.symbol-5540ed538fb6bd400d2a.svg#ri-thumb-down-fill" tabindex="-1"></use></svg>
259
+ <span>0</span>
229
260
  </button>
230
- <input type="hidden" name="authenticity_token" value="xyz123" />
261
+ <input type="hidden" name="authenticity_token" value="OOIZTq0QSU1CB6OXV1D6j337zCgOA6al6xDOmy_qlZpWdem25Eg3A84QEUnfMz0DWLJRu-Lj8ja9XHYcZgdh-A" autocomplete="off">
231
262
  </form>
232
263
  </div>
264
+ </div>
265
+ <div id="panel-comment${commentId}-reply" class="add-comment" role="region" tabindex="-1" aria-labelledby="" aria-hidden="true">
266
+ ${generateCommentForm("Comment", commentId)}
267
+ </div>
233
268
  </div>
234
269
  <div id="comment-${commentId}-replies">${replies}</div>
235
-
236
- <div class="comment__additionalreply hide">
237
- <button class="comment__reply muted-link" aria-controls="comment${commentId}-reply" data-toggle="comment${commentId}-reply" aria-expanded="true">
238
- <svg role="img" aria-hidden="true" class="icon--pencil icon icon--small">
239
- <title></title>
240
- <use href="/assets/decidim/icons-123.svg#icon-pencil"></use>
241
- </svg>
242
- &nbsp;Reply
243
- </button>
244
- </div>
245
-
246
- <div class="add-comment hide" id="comment${commentId}-reply" data-toggler=".hide">
247
- ${generateCommentForm("Comment", commentId)}
248
- </div>
249
270
  </div>
250
271
  `;
251
- };
272
+ }
252
273
 
253
274
  const generateCommentThread = (commentId, content, replies = "") => {
254
275
  return `
@@ -262,33 +283,23 @@ describe("CommentsComponent", () => {
262
283
 
263
284
  beforeEach(() => {
264
285
  let orderSelector = `
265
- <ul id="comments-order-menu" class="dropdown menu" data-dropdown-menu="data-dropdown-menu" data-autoclose="false" data-disable-hover="true" data-click-open="true" data-close-on-click="true" tabindex="-1" role="menubar">
266
- <li class="is-dropdown-submenu-parent opens-right" tabindex="-1" role="none">
267
- <a href="#" id="comments-order-menu-control" aria-label="Order by:" aria-controls="comments-order-menu" aria-haspopup="menu" role="menuitem">Older</a>
268
- <ul class="menu is-dropdown-submenu submenu first-sub vertical" id="comments-order-chooser-menu" role="menu" aria-labelledby="comments-order-menu-control" tabindex="-1" data-submenu="">
269
- <li role="none" class="is-submenu-item is-dropdown-submenu-item">
270
- <a tabindex="-1" role="menuitem" data-remote="true" href="/comments?commentable_gid=commentable-gid&amp;order=best_rated&amp;reload=1">
271
- Best rated
272
- </a>
273
- </li>
274
- <li role="none" class="is-submenu-item is-dropdown-submenu-item">
275
- <a tabindex="-1" role="menuitem" data-remote="true" href="/comments?commentable_gid=commentable-gid&amp;order=recent&amp;reload=1">
276
- Recent
277
- </a>
278
- </li>
279
- <li role="none" class="is-submenu-item is-dropdown-submenu-item">
280
- <a tabindex="-1" role="menuitem" data-remote="true" href="/comments?commentable_gid=commentable-gid&amp;order=older&amp;reload=1">
281
- Older
282
- </a>
283
- </li>
284
- <li role="none" class="is-submenu-item is-dropdown-submenu-item">
285
- <a tabindex="-1" role="menuitem" data-remote="true" href="/comments?commentable_gid=commentable-gid&amp;order=most_discussed&amp;reload=1">
286
- Most discussed
287
- </a>
288
- </li>
289
- </ul>
290
- </li>
291
- </ul>
286
+ <div class="comment-order-by">
287
+ <div class="text-center">
288
+ <a class="button button__sm button__text-secondary only:m-auto comment-order-by__item inline-block " data-remote="true" href="/comments?commentable_gid=commentable-gid&amp;order=best_rated&amp;reload=1">Best rated</a>
289
+ </div>
290
+
291
+ <div class="text-center">
292
+ <a class="button button__sm button__text-secondary only:m-auto comment-order-by__item inline-block " data-remote="true" href="/comments?commentable_gid=commentable-gid&amp;order=recent&amp;reload=1">Recent</a>
293
+ </div>
294
+
295
+ <div class="text-center">
296
+ <a class="button button__sm button__text-secondary only:m-auto comment-order-by__item inline-block underline font-bold" data-remote="true" href="/comments?commentable_gid=commentable-gid&amp;order=older&amp;reload=1">Older</a>
297
+ </div>
298
+
299
+ <div class="text-center">
300
+ <a class="button button__sm button__text-secondary only:m-auto comment-order-by__item inline-block " data-remote="true" href="/comments?commentable_gid=commentable-gid&amp;order=most_discussed&amp;reload=1">Most discussed</a>
301
+ </div>
302
+ </div>
292
303
  `;
293
304
 
294
305
  let reply = generateSingleComment(451, "This is a reply.");
@@ -297,14 +308,14 @@ describe("CommentsComponent", () => {
297
308
 
298
309
  let comments = `
299
310
  <div id="comments-for-Dummy-123" data-decidim-comments='{"singleComment":false,"toggleTranslations":false,"commentableGid":"commentable-gid","commentsUrl":"/comments","rootDepth":0,"lastCommentId":456,"order":"older"}'>
300
- <div class="columns large-9 comments-container" id="comments">
311
+ <div id="comments">
301
312
  <div class="comments">
302
- <div class="row collapse order-by">
303
- <h2 class="order-by__text section-heading">3 comments</h2>
304
- <div class="order-by__dropdown order-by__dropdown--right">
305
- <span class="order-by__text">Order by:</span>
306
- ${orderSelector}
307
- </div>
313
+ <div class="comments__header">
314
+ <h2 class="h4">
315
+ <svg width="1em" height="1em" role="img" aria-hidden="true" class="fill-tertiary w-6 h-6 inline-block align-middle"><use href="/decidim-packs/media/images/remixicon.symbol-5540ed538fb6bd400d2a.svg#ri-chat-1-line" tabindex="-1"></use></svg>
316
+ <span class="comments-count inline-block align-middle">3 comments</span>
317
+ </h2>
318
+ ${orderSelector}
308
319
  </div>
309
320
 
310
321
  <div class="comment-threads">
@@ -312,38 +323,35 @@ describe("CommentsComponent", () => {
312
323
  ${secondThread}
313
324
  </div>
314
325
  <div class="add-comment">
315
- <h4 class="section-heading">Add your comment</h4>
316
-
317
- <div class="opinion-toggle button-group">
318
- <button aria-pressed="false" class="button tiny button--muted opinion-toggle--ok" data-selected-label="Your opinion about this topic is positive">
319
- <svg role="img" aria-hidden="true" class="icon--thumb-up icon">
320
- <title></title>
321
- <use href="/assets/decidim/icons-2ba788b32e181c1a7197f7a54a0f03101c146dd434b9e56191690c7c2d7bdae3.svg#icon-thumb-up"></use>
322
- </svg>
326
+ <div class="opinion-toggle button-group comment__opinion-container">
327
+ <span class="show-for-sr py-1.5">Your opinion about this topic</span>
328
+ <button aria-pressed="false" class="button button__sm button__text-secondary opinion-toggle--ok" data-selected-label="Your opinion about this topic is positive">
329
+ <svg width="1em" height="1em" role="img" aria-hidden="true"><use href="/decidim-packs/media/images/remixicon.symbol-5540ed538fb6bd400d2a.svg#ri-thumb-up-line" tabindex="-1"></use></svg>
330
+ <svg width="1em" height="1em" role="img" aria-hidden="true"><use href="/decidim-packs/media/images/remixicon.symbol-5540ed538fb6bd400d2a.svg#ri-thumb-up-fill" tabindex="-1"></use></svg>
323
331
  <span class="show-for-sr">Positive</span>
324
332
  </button>
325
- <button aria-pressed="true" class="button tiny button--muted opinion-toggle--meh is-active" data-selected-label="Your opinion about this topic is neutral">
326
- Neutral
333
+ <button aria-pressed="true" class="button button__sm button__text-secondary opinion-toggle--meh is-active" data-selected-label="Your opinion about this topic is neutral">
334
+ <span class="show-for-sr">Neutral
335
+ </span>
327
336
  </button>
328
- <button aria-pressed="false" class="button tiny button--muted opinion-toggle--ko" data-selected-label="Your opinion about this topic is negative">
329
- <svg role="img" aria-hidden="true" class="icon--thumb-down icon">
330
- <title></title>
331
- <use href="/assets/decidim/icons-2ba788b32e181c1a7197f7a54a0f03101c146dd434b9e56191690c7c2d7bdae3.svg#icon-thumb-down"></use>
332
- </svg>
337
+ <button aria-pressed="false" class="button button__sm button__text-secondary opinion-toggle--ko" data-selected-label="Your opinion about this topic is negative">
338
+ <svg width="1em" height="1em" role="img" aria-hidden="true"><use href="/decidim-packs/media/images/remixicon.symbol-5540ed538fb6bd400d2a.svg#ri-thumb-down-line" tabindex="-1"></use></svg>
339
+ <svg width="1em" height="1em" role="img" aria-hidden="true"><use href="/decidim-packs/media/images/remixicon.symbol-5540ed538fb6bd400d2a.svg#ri-thumb-down-fill" tabindex="-1"></use></svg>
333
340
  <span class="show-for-sr">Negative</span>
334
341
  </button>
335
- <div role="alert" aria-live="assertive" aria-atomic="true" class="selected-state shot-for-sr"></div>
342
+ <div role="alert" aria-live="assertive" aria-atomic="true" class="selected-state sr-only"></div>
336
343
  </div>
337
-
338
344
  ${generateCommentForm("Dummy", 123)}
339
345
  </div>
340
- </div>
341
- <div class="callout primary loading-comments hide">
342
- <p>Loading comments ...</p>
343
- </div>
346
+ <div class="flash primary loading-comments hidden">
347
+ <span class="flash__message">
348
+ Loading comments ...
349
+ </span>
350
+ </div>
344
351
  </div>
345
352
  </div>
346
353
  `;
354
+
347
355
  $("body").append(comments);
348
356
 
349
357
  $container = $(document).find(selector);
@@ -361,7 +369,7 @@ describe("CommentsComponent", () => {
361
369
 
362
370
  $doc = $(document);
363
371
  addComment = $(".add-comment", subject.$element);
364
- orderLinks = $(".order-by__dropdown .is-submenu-item a", subject.$element);
372
+ orderLinks = $(".comment-order-by a.comment-order-by__item", subject.$element);
365
373
 
366
374
  allToggles = $(".add-comment .opinion-toggle .button", subject.$element);
367
375
  allTextareas = $(".add-comment textarea", subject.$element);
@@ -377,7 +385,7 @@ describe("CommentsComponent", () => {
377
385
  });
378
386
 
379
387
  it("initializes the comments element with the given selector", () => {
380
- expect(subject.$element).toEqual($(selector));
388
+ expect(subject.$element[0]).toEqual($(selector)[0]);
381
389
  });
382
390
 
383
391
  it("loads the comments through AJAX", () => {
@@ -411,6 +419,7 @@ describe("CommentsComponent", () => {
411
419
  });
412
420
 
413
421
  it("starts polling for new comments", () => {
422
+ jest.spyOn(window, "setTimeout");
414
423
  Rails.ajax.mockImplementationOnce((options) => options.success());
415
424
 
416
425
  subject.mountComponent();
@@ -426,7 +435,7 @@ describe("CommentsComponent", () => {
426
435
  // Delay the success call 2s after the polling has happened to test that
427
436
  // the textarea is still enabled when the polling is happening.
428
437
  Rails.ajax.mockImplementationOnce((options) => {
429
- setTimeout(options.success(), 2000);
438
+ setTimeout(() => options.success(), 2000);
430
439
  });
431
440
  jest.advanceTimersByTime(1500);
432
441
 
@@ -436,8 +445,8 @@ describe("CommentsComponent", () => {
436
445
  describe("when mounted", () => {
437
446
  beforeEach(() => {
438
447
  spyOnAddComment("on");
439
- spyOn(orderLinks, "on");
440
- spyOn($doc, "trigger");
448
+ jest.spyOn(orderLinks, "on");
449
+ jest.spyOn($doc, "trigger");
441
450
 
442
451
  subject.mountComponent();
443
452
  });
@@ -450,13 +459,6 @@ describe("CommentsComponent", () => {
450
459
  expect(subject.mounted).toBeTruthy();
451
460
  });
452
461
 
453
- it("binds the order selector events", () => {
454
- expect(orderLinks.on).toHaveBeenCalledWith(
455
- "click.decidim-comments",
456
- expect.any(Function)
457
- );
458
- });
459
-
460
462
  it("binds the add comment element events", () => {
461
463
  addComment.each((i) => {
462
464
  expect(addComment[i].opinionToggles.on).toHaveBeenCalledWith(
@@ -519,7 +521,7 @@ describe("CommentsComponent", () => {
519
521
  });
520
522
 
521
523
  it("disables the submit button on submit and stops polling", () => {
522
- spyOn(window, "clearTimeout");
524
+ jest.spyOn(window, "clearTimeout");
523
525
 
524
526
  commentText.html("This is a test comment")
525
527
  commentText.trigger("input");
@@ -633,7 +635,7 @@ describe("CommentsComponent", () => {
633
635
  });
634
636
 
635
637
  it("does not clear the reply comment form text area", () => {
636
- const commentSection = $("#comment450-reply", subject.$element);
638
+ const commentSection = $("#comment-450-replies", subject.$element);
637
639
  const textArea = $("textarea", commentSection);
638
640
  textArea.val("I am writing a new comment...");
639
641
 
@@ -642,18 +644,9 @@ describe("CommentsComponent", () => {
642
644
  expect(textArea.val()).toEqual("I am writing a new comment...");
643
645
  });
644
646
 
645
- it("does not hide the reply form", () => {
646
- const commentSection = $("#comment450-reply", subject.$element);
647
- commentSection.removeClass("hide");
648
-
649
- subject.addReply(450, newReply);
650
-
651
- expect(commentSection.hasClass("hide")).toBeFalsy();
652
- });
653
-
654
647
  describe("as the current user", () => {
655
648
  it("clears the comment form text area", () => {
656
- const commentSection = $("#comment450-reply", subject.$element);
649
+ const commentSection = $(".add-comment", subject.$element);
657
650
  const textArea = $("textarea", commentSection);
658
651
  textArea.val("I am writing a new comment...");
659
652
 
@@ -661,25 +654,16 @@ describe("CommentsComponent", () => {
661
654
 
662
655
  expect(textArea.val()).toEqual("");
663
656
  });
664
-
665
- it("hides the reply form", () => {
666
- const commentSection = $("#comment450-reply", subject.$element);
667
- commentSection.removeClass("hide");
668
-
669
- subject.addReply(450, newReply, true);
670
-
671
- expect(commentSection.hasClass("hide")).toBeTruthy();
672
- });
673
657
  });
674
658
  });
675
659
  });
676
660
 
677
661
  describe("when unmounted", () => {
678
662
  beforeEach(() => {
679
- spyOn(orderLinks, "off");
680
- spyOn(allToggles, "off");
681
- spyOn(allTextareas, "off");
682
- spyOn(allForms, "off");
663
+ jest.spyOn(orderLinks, "off");
664
+ jest.spyOn(allToggles, "off");
665
+ jest.spyOn(allTextareas, "off");
666
+ jest.spyOn(allForms, "off");
683
667
 
684
668
  subject.mountComponent();
685
669
  subject.unmountComponent();
@@ -689,12 +673,6 @@ describe("CommentsComponent", () => {
689
673
  expect(subject.mounted).toBeFalsy();
690
674
  });
691
675
 
692
- it("unbinds the order selector events", () => {
693
- expect(orderLinks.off).toHaveBeenCalledWith(
694
- "click.decidim-comments"
695
- );
696
- });
697
-
698
676
  it("unbinds the add comment element events", () => {
699
677
  expect(allToggles.off).toHaveBeenCalledWith("click.decidim-comments");
700
678
  expect(allTextareas.off).toHaveBeenCalledWith("input.decidim-comments");