decidim-comments 0.27.8 → 0.28.0.rc4

Sign up to get free protection for your applications and to get access to all the features.
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 +7 -9
  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 +2 -16
  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");