decidim-comments 0.31.4 → 0.32.0.rc1

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +18 -16
  3. data/app/cells/decidim/comments/comment/deletion_data.erb +3 -7
  4. data/app/cells/decidim/comments/comment/replies.erb +23 -3
  5. data/app/cells/decidim/comments/comment/show.erb +5 -19
  6. data/app/cells/decidim/comments/comment_cell.rb +10 -6
  7. data/app/cells/decidim/comments/comment_form/show.erb +1 -1
  8. data/app/cells/decidim/comments/comments/inline.erb +13 -10
  9. data/app/cells/decidim/comments/comments_cell.rb +7 -2
  10. data/app/cells/decidim/comments/two_columns_comments/column.erb +7 -2
  11. data/app/cells/decidim/comments/two_columns_comments/show.erb +7 -4
  12. data/app/cells/decidim/comments/two_columns_comments_cell.rb +30 -31
  13. data/app/controllers/decidim/comments/comments_controller.rb +32 -7
  14. data/app/models/decidim/comments/seed.rb +17 -7
  15. data/app/packs/entrypoints/decidim_comments.js +6 -0
  16. data/app/packs/src/decidim/comments/comments.component.js +1 -43
  17. data/app/packs/src/decidim/comments/comments.component.test.js +63 -62
  18. data/app/packs/src/decidim/comments/controllers/load_more_comments/controller.js +201 -0
  19. data/app/packs/src/decidim/comments/controllers/show_replies/controller.js +240 -0
  20. data/app/packs/stylesheets/comments.scss +62 -1
  21. data/app/queries/decidim/comments/sorted_comments.rb +77 -33
  22. data/app/views/decidim/comments/comments/_load_more_comments.html.erb +22 -0
  23. data/app/views/decidim/comments/comments/create.js.erb +38 -4
  24. data/app/views/decidim/comments/comments/index.js.erb +58 -23
  25. data/app/views/decidim/comments/comments/load_more_comments.js.erb +74 -0
  26. data/app/views/decidim/comments/comments/update.js.erb +3 -13
  27. data/config/locales/ar.yml +0 -1
  28. data/config/locales/bg.yml +0 -1
  29. data/config/locales/bs-BA.yml +0 -1
  30. data/config/locales/ca-IT.yml +6 -4
  31. data/config/locales/ca.yml +6 -4
  32. data/config/locales/cs.yml +3 -6
  33. data/config/locales/de.yml +6 -4
  34. data/config/locales/el.yml +0 -1
  35. data/config/locales/en.yml +6 -3
  36. data/config/locales/es-MX.yml +6 -4
  37. data/config/locales/es-PY.yml +6 -4
  38. data/config/locales/es.yml +6 -4
  39. data/config/locales/eu.yml +6 -4
  40. data/config/locales/fi-plain.yml +6 -4
  41. data/config/locales/fi.yml +6 -4
  42. data/config/locales/fr-CA.yml +3 -4
  43. data/config/locales/fr.yml +3 -4
  44. data/config/locales/ga-IE.yml +0 -1
  45. data/config/locales/gl.yml +0 -1
  46. data/config/locales/hu.yml +0 -1
  47. data/config/locales/id-ID.yml +0 -1
  48. data/config/locales/is-IS.yml +1 -2
  49. data/config/locales/it.yml +0 -1
  50. data/config/locales/ja.yml +5 -3
  51. data/config/locales/lb.yml +0 -1
  52. data/config/locales/lt.yml +0 -1
  53. data/config/locales/lv.yml +0 -1
  54. data/config/locales/nl.yml +0 -1
  55. data/config/locales/no.yml +0 -1
  56. data/config/locales/pl.yml +0 -1
  57. data/config/locales/pt-BR.yml +6 -4
  58. data/config/locales/pt.yml +0 -1
  59. data/config/locales/ro-RO.yml +0 -5
  60. data/config/locales/ru.yml +0 -1
  61. data/config/locales/si-LK.yml +0 -1
  62. data/config/locales/sk.yml +0 -1
  63. data/config/locales/sl.yml +0 -1
  64. data/config/locales/sq-AL.yml +0 -1
  65. data/config/locales/sr-CS.yml +0 -1
  66. data/config/locales/sv.yml +0 -4
  67. data/config/locales/tr-TR.yml +0 -1
  68. data/config/locales/uk.yml +0 -1
  69. data/config/locales/zh-CN.yml +0 -1
  70. data/config/locales/zh-TW.yml +0 -1
  71. data/db/migrate/20260208201401_remove_user_group_comments.rb +13 -0
  72. data/decidim-comments.gemspec +6 -9
  73. data/lib/decidim/api/comment_mutation_type.rb +12 -4
  74. data/lib/decidim/api/commentable_interface.rb +1 -0
  75. data/lib/decidim/api/commentable_mutation_type.rb +4 -0
  76. data/lib/decidim/comments/commentable.rb +5 -0
  77. data/lib/decidim/comments/commentable_with_component.rb +9 -0
  78. data/lib/decidim/comments/test/factories.rb +1 -1
  79. data/lib/decidim/comments/test/shared_examples/translatable_comment.rb +1 -0
  80. data/lib/decidim/comments/version.rb +1 -1
  81. metadata +15 -14
  82. data/app/resolvers/decidim/comments/vote_comment_resolver.rb +0 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8b4d964f989f7d3261d3858f6847bcf61c80ace4f570405f6e89df3ef2ef8444
4
- data.tar.gz: a4bb000606a9701888bbb9bbdbec79117345919d53b99b8363eb33cb88734a01
3
+ metadata.gz: 31c9f9edb9b180b45de88f99e78665579abf750966bcd87eba5094a27f2b3ca9
4
+ data.tar.gz: 6a66c1581118aafa964547213c97454a5493fa0b38ef2e88bb70902d9ddef093
5
5
  SHA512:
6
- metadata.gz: b6b1bac4a7c62f5d44f2128b15f9f4bb6d5c6d5b3b55106da3294b5bf96d52331673e1203c9c5ed4c4eeea2c1e9efa71e2ed2f5d43d0890f6936e7dd0c65e8d9
7
- data.tar.gz: '00063569084ab6ea353675967b9b928778a60c94f2a4f063c7185e99aff8b45f9cbbf75c3313fd541d92b8f254307c6bf726e717149b833c1e49d06456278ca4'
6
+ metadata.gz: d026ab1b9fb210f23ba6f50e8b94f6d1ab728c6c159dd9b790fc25cab52f6489e9de1c95db96b8b351f4c7e757d78a802cdbe1a21e3e37c3d6f8d82a4f6b9fdf
7
+ data.tar.gz: 9efa7deae0c784ace5ff6814868e54215d4cad7a4534b9f6da7236c6c26f8e950824d733a840fbe051a975bc81a165b05030dd23251e1dd62e2064a04bb052ed
data/README.md CHANGED
@@ -1,8 +1,24 @@
1
- # Decidim::Comments
1
+ # decidim-comments
2
2
 
3
3
  The Comments module adds the ability to include comments to any resource which can be commentable by users.
4
4
 
5
- ## Usage
5
+ This is a module oriented for developers, as a building block to be used by other modules.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your module's gemspec:
10
+
11
+ ```ruby
12
+ s.add_dependency "decidim-comments", Decidim::YourModule.version
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ ```bash
18
+ bundle
19
+ ```
20
+
21
+ ## Usage on another modules
6
22
 
7
23
  The Comments component is exposed as a Rails helper:
8
24
 
@@ -22,20 +38,6 @@ Finally, add the comments javascript module like this:
22
38
  import "src/decidim/comments/comments";
23
39
  ```
24
40
 
25
- ## Installation
26
-
27
- Add this line to your application's Gemfile.
28
-
29
- ```ruby
30
- gem 'decidim-comments'
31
- ```
32
-
33
- And then execute:
34
-
35
- ```bash
36
- bundle
37
- ```
38
-
39
41
  ## How to contribute
40
42
 
41
43
  The technology stack used in this module is the following:
@@ -1,9 +1,5 @@
1
1
  <%= render partial: "decidim/comments/comments/delete", formats: [:html], locals: { comment: model } %>
2
2
 
3
- <div data-comment-footer data-controller="accordion" id="accordion-<%= model.id %>">
4
- <div id="comment-<%= model.id %>-replies" class="<%= "comment-reply" if has_replies_in_children? %>">
5
- <% if has_replies_in_children? %>
6
- <%= render :replies %>
7
- <% end %>
8
- </div>
9
- </div>
3
+ <% if has_replies_in_children? %>
4
+ <%= render :replies %>
5
+ <% end %>
@@ -1,3 +1,23 @@
1
- <% replies.each do |reply| %>
2
- <%= cell("decidim/comments/comment", reply, root_depth: , order: , reloaded: reloaded?) %>
3
- <% end %>
1
+ <div data-controller="show-replies"
2
+ data-show-replies-url-value="<%= decidim_comments.comments_path %>"
3
+ data-show-replies-comment-gid-value="<%= model.to_signed_global_id.to_s %>"
4
+ data-show-replies-order-value="<%= order %>"
5
+ data-show-replies-loaded-value="false">
6
+ <div class="show-replies-button">
7
+ <button class="button button__xs button__text-secondary"
8
+ data-action="click->show-replies#toggle"
9
+ data-show-replies-target="button"
10
+ aria-expanded="false"
11
+ aria-controls="comment-<%= model.id %>-replies"
12
+ id="comment-<%= model.id %>-replies-trigger">
13
+ <span class="font-normal"><%= t("decidim.components.comment.replies_count", count: replies_count) %></span>
14
+ <%= icon "arrow-down-s-line" %>
15
+ <%= icon "arrow-up-s-line" %>
16
+ </button>
17
+ <span data-show-replies-target="spinner" class="ml-2 hidden"><%= icon "loader-3-line", class: "animate-spin fill-secondary" %></span>
18
+ </div>
19
+ <div id="comment-<%= model.id %>-replies"
20
+ data-show-replies-target="container"
21
+ class="comment-reply hidden">
22
+ </div>
23
+ </div>
@@ -90,31 +90,17 @@
90
90
  <%= votes %>
91
91
  </div>
92
92
  </div>
93
- <div class="comment__reply-button">
94
- <% if depth.zero? && has_replies_in_children? %>
95
- <button class="button button__xs button__transparent-secondary border-white absolute top-4" data-comment-hide data-controls="comment-<%= model.id %>-replies" data-open="false" id="comment-<%= model.id %>-replies-trigger">
96
- <span data-show-comment-reply class="font-normal" aria-label="<%= t("decidim.components.comment.show_replies", count: replies.size) %>">
97
- <%= t("decidim.components.comment.answers", count: replies.size) %>
98
- </span>
99
- <%= icon "arrow-down-s-line" %>
100
- <span data-hide-comment-reply class="font-normal" aria-label="<%= t("decidim.components.comment.hide_replies", count: replies.size) %>">
101
- <%= t("decidim.components.comment.answers", count: replies.size) %>
102
- </span>
103
- <%= icon "arrow-up-s-line" %>
104
- </button>
105
- <% end %>
106
- </div>
107
93
  <% if can_reply? %>
108
94
  <div id="panel-<%= reply_id %>" class="add-comment" data-additional-reply>
109
95
  <%== cell("decidim/comments/comment_form", model, root_depth:, order:) %>
110
96
  </div>
111
97
  <% end %>
112
- <div id="comment-<%= model.id %>-replies" class="<%= "comment-reply" if has_replies_in_children? %>">
113
- <% if has_replies_in_children? %>
114
- <%= render :replies %>
115
- <% end %>
116
- </div>
117
98
  </div>
99
+ <% if has_replies_in_children? %>
100
+ <%= render :replies %>
101
+ <% elsif can_reply? %>
102
+ <div id="comment-<%= model.id %>-replies" class="comment-reply"></div>
103
+ <% end %>
118
104
  <% end %>
119
105
  <% if current_user.present? %>
120
106
  <%= cell("decidim/report_button", model, modal_id: "flagModalComment#{model.id}").flag_modal %>
@@ -86,10 +86,6 @@ module Decidim
86
86
  formatted_body
87
87
  end
88
88
 
89
- def replies
90
- SortedComments.for(model, order_by: order)
91
- end
92
-
93
89
  def order
94
90
  options[:order] || "older"
95
91
  end
@@ -126,7 +122,11 @@ module Decidim
126
122
  def can_reply?
127
123
  return false if two_columns_layout?
128
124
  return false if model.depth >= Comment::MAX_DEPTH
129
- return true if current_participatory_space && user_has_any_role?(current_user, current_participatory_space)
125
+
126
+ if current_participatory_space
127
+ return true if user_has_any_role?(current_user, current_participatory_space)
128
+ return false unless current_participatory_space.can_participate?(current_user)
129
+ end
130
130
 
131
131
  user_signed_in? && accepts_new_comments? &&
132
132
  root_commentable.user_allowed_to_comment?(current_user)
@@ -234,7 +234,11 @@ module Decidim
234
234
  end
235
235
 
236
236
  def has_replies_in_children?
237
- model.descendants.where(decidim_commentable_type: "Decidim::Comments::Comment").not_hidden.not_deleted.exists?
237
+ replies_count.positive?
238
+ end
239
+
240
+ def replies_count
241
+ @replies_count ||= model.replies.count
238
242
  end
239
243
 
240
244
  # action_authorization_button expects current_component to be available
@@ -31,7 +31,7 @@
31
31
  <% end %>
32
32
  <div class="<%= reply? ? "" : "publish-comment-button" %>">
33
33
  <button type="submit"
34
- class="button button__sm button__secondary <%= reply? ? "w-full" : "h-9 close-comment-fullscreen" %>"
34
+ class="button button__sm button__secondary <%= reply? ? "" : "h-9 close-comment-fullscreen" %>"
35
35
  disabled="disabled">
36
36
  <span>
37
37
  <%= reply? ? t("decidim.components.add_comment_form.form.submit_reply") : t("decidim.components.add_comment_form.form.submit_root_comment") %>
@@ -1,6 +1,13 @@
1
1
  <div id="comments">
2
2
  <div class="comments">
3
- <div class="comments__header">
3
+ <% if user_signed_in? %>
4
+ <button class="button button__lg button__secondary flex md:hidden w-full h-9 text-sm add-comment-mobile">
5
+ <%= t("add_comment", scope: "decidim.components.add_comment_form") %>
6
+ </button>
7
+ <% end %>
8
+ <%= add_comment %>
9
+ <%= user_comments_blocked_warning %>
10
+ <div class="comments__header mt-8">
4
11
  <h2 class="h4">
5
12
  <% if single_comment? %>
6
13
  <%= t("decidim.components.comments.comment_details_title") %>
@@ -11,18 +18,14 @@
11
18
  </span>
12
19
  <% end %>
13
20
  </h2>
14
- <%= render :order_control unless two_columns_layout? %>
21
+ <% if two_columns_layout? %>
22
+ <div class="md:hidden"><%= render :order_control %></div>
23
+ <% else %>
24
+ <%= render :order_control %>
25
+ <% end %>
15
26
  </div>
16
27
  <%= single_comment_warning %>
17
28
  <%= blocked_comments_warning %>
18
29
  <%= render_comments %>
19
- <% if user_signed_in? %>
20
- <button class="button button__lg button__secondary flex md:hidden w-full h-9 text-sm add-comment-mobile">
21
- <%= t("add_comment", scope: "decidim.components.add_comment_form") %>
22
- </button>
23
- <% end %>
24
- <%= add_comment %>
25
- <%= user_comments_blocked_warning %>
26
30
  </div>
27
- <%= cell("decidim/announcement", t("decidim.components.comments.loading"), callout_class: "primary loading-comments hidden") %>
28
31
  </div>
@@ -5,6 +5,7 @@ module Decidim
5
5
  # A cell to display a comments section for a commentable object.
6
6
  class CommentsCell < Decidim::ViewModel
7
7
  include UserRoleChecker
8
+
8
9
  delegate :user_signed_in?, to: :controller
9
10
 
10
11
  def render_comments
@@ -67,7 +68,10 @@ module Decidim
67
68
  end
68
69
 
69
70
  def can_add_comments?
70
- return true if current_participatory_space && user_has_any_role?(current_user, current_participatory_space)
71
+ if current_participatory_space
72
+ return true if user_has_any_role?(current_user, current_participatory_space)
73
+ return false unless current_participatory_space.can_participate?(current_user)
74
+ end
71
75
  return if single_comment?
72
76
  return if comments_blocked?
73
77
  return if user_comments_blocked?
@@ -108,7 +112,7 @@ module Decidim
108
112
  end
109
113
 
110
114
  def order
111
- options[:order] || "older"
115
+ options[:order] || (two_columns_layout? ? "recent" : "older")
112
116
  end
113
117
 
114
118
  def decidim
@@ -158,6 +162,7 @@ module Decidim
158
162
 
159
163
  def user_comments_blocked?
160
164
  return false unless user_signed_in?
165
+ return true if current_participatory_space && !current_participatory_space.can_participate?(current_user)
161
166
 
162
167
  !model.user_allowed_to_comment?(current_user)
163
168
  end
@@ -14,7 +14,12 @@
14
14
  <% @comments.each do |comment| %>
15
15
  <%= cell("decidim/comments/comment_thread", comment, order:) %>
16
16
  <% end %>
17
- <% else %>
18
- <p class="comments-section__no-comments"><%= @no_comments_message %></p>
17
+ <% elsif @top_comment.blank? %>
18
+ <p class="comments-section__no-comments"><%= t("decidim.components.comments.no_comments_yet") %></p>
19
+ <% end %>
20
+
21
+ <% if @has_more %>
22
+ <% offset = @comments.size + (@top_comment.present? ? 1 : 0) %>
23
+ <%= controller.view_context.render partial: "decidim/comments/comments/load_more_comments", locals: { commentable: model, order:, offset:, alignment: @alignment } %>
19
24
  <% end %>
20
25
  </div>
@@ -1,11 +1,14 @@
1
1
  <div id="desktopContainer" class="comments-two-columns card__grid-grid hidden md:grid">
2
- <%= render_column(@top_comment_in_favor, @sorted_comments_in_favor, "thumb-up-line", t("decidim.components.comments.in_favor")) %>
3
- <%= render_column(@top_comment_against, @sorted_comments_against, "thumb-down-line", t("decidim.components.comments.against")) %>
2
+ <%= render_column(@top_comment_in_favor, @sorted_comments_in_favor, "thumb-up-line", t("decidim.components.comments.in_favor"), 1, @has_more_in_favor) %>
3
+ <%= render_column(@top_comment_against, @sorted_comments_against, "thumb-down-line", t("decidim.components.comments.against"), -1, @has_more_against) %>
4
4
  </div>
5
5
 
6
6
  <div id="mobileContainer" class="comment-threads block md:hidden" aria-live="polite">
7
7
  <%= comments_loading %>
8
- <% @interleaved_comments.each do |comment| %>
9
- <%= cell("decidim/comments/comment_thread", comment, order:, top_comment: (comment == @top_comment_in_favor || comment == @top_comment_against)) %>
8
+ <% @mobile_comments.each do |comment| %>
9
+ <%= cell("decidim/comments/comment_thread", comment, order:) %>
10
+ <% end %>
11
+ <% if @has_more_mobile %>
12
+ <%= controller.view_context.render partial: "decidim/comments/comments/load_more_comments", locals: { commentable: model, order:, offset: @mobile_comments.size } %>
10
13
  <% end %>
11
14
  </div>
@@ -6,14 +6,15 @@ module Decidim
6
6
  class TwoColumnsCommentsCell < Decidim::Comments::CommentsCell
7
7
  def call
8
8
  initialize_comments
9
- @interleaved_comments = interleave_comments(@sorted_comments_in_favor, @sorted_comments_against)
10
9
  render :show
11
10
  end
12
11
 
13
- def render_column(top_comment, comments, icon_name, title)
14
- set_column_variables(top_comment, comments, icon_name, title)
12
+ # rubocop:disable Metrics/ParameterLists
13
+ def render_column(top_comment, comments, icon_name, title, alignment, has_more)
14
+ set_column_variables(top_comment, comments, icon_name, title, alignment, has_more)
15
15
  render :column
16
16
  end
17
+ # rubocop:enable Metrics/ParameterLists
17
18
 
18
19
  private
19
20
 
@@ -21,19 +22,25 @@ module Decidim
21
22
  if model.closed?
22
23
  load_closed_comments
23
24
  else
24
- @sorted_comments_in_favor = comments_in_favor
25
- @sorted_comments_against = comments_against
25
+ @sorted_comments_in_favor = comments_in_favor_query.query
26
+ @sorted_comments_against = comments_against_query.query
26
27
  end
28
+
29
+ counts = comments_count_by_alignment
30
+ @has_more_in_favor = (counts[1] || 0) > comments_in_favor_query.offset + comments_in_favor_query.limit
31
+ @has_more_against = (counts[-1] || 0) > comments_against_query.offset + comments_against_query.limit
32
+
33
+ load_mobile_comments(counts.values.sum)
27
34
  end
28
35
 
29
36
  def load_closed_comments
30
- @top_comment_in_favor, @sorted_comments_in_favor = sorted_comments(comments_in_favor)
31
- @top_comment_against, @sorted_comments_against = sorted_comments(comments_against)
37
+ @top_comment_in_favor, @sorted_comments_in_favor = sorted_comments(comments_in_favor_query.query)
38
+ @top_comment_against, @sorted_comments_against = sorted_comments(comments_against_query.query)
32
39
  end
33
40
 
34
41
  def sorted_comments(comments)
35
42
  top_comment = find_top_comment(comments)
36
- sorted_comments = comments.where.not(id: top_comment&.id).order(created_at: :asc)
43
+ sorted_comments = comments.where.not(id: top_comment&.id)
37
44
  [top_comment, sorted_comments]
38
45
  end
39
46
 
@@ -45,42 +52,34 @@ module Decidim
45
52
  .first
46
53
  end
47
54
 
48
- def interleave_comments(comments_in_favor, comments_against)
49
- interleave_top_comments + interleave_remaining_comments(comments_in_favor, comments_against)
50
- end
51
-
52
- def interleave_top_comments
53
- return [] unless model.closed?
54
-
55
- Array(@top_comment_in_favor) + Array(@top_comment_against)
55
+ def comments_in_favor_query
56
+ @comments_in_favor_query ||= SortedComments.new(model, order_by: order, alignment: 1, offset: 0)
56
57
  end
57
58
 
58
- def interleave_remaining_comments(comments_in_favor, comments_against)
59
- interleaved = []
60
- max_length = [comments_in_favor.size, comments_against.size].max
61
-
62
- max_length.times do |i|
63
- interleaved << comments_in_favor[i] if comments_in_favor[i]
64
- interleaved << comments_against[i] if comments_against[i]
65
- end
66
-
67
- interleaved
59
+ def comments_against_query
60
+ @comments_against_query ||= SortedComments.new(model, order_by: order, alignment: -1, offset: 0)
68
61
  end
69
62
 
70
- def comments_in_favor
71
- @comments_in_favor ||= model.comments.positive.order(:created_at)
63
+ def load_mobile_comments(total_count)
64
+ @sorted_comments_query = SortedComments.new(model, order_by: order, offset: 0)
65
+ @mobile_comments = @sorted_comments_query.query
66
+ @has_more_mobile = total_count > @sorted_comments_query.offset + @sorted_comments_query.limit
72
67
  end
73
68
 
74
- def comments_against
75
- @comments_against ||= model.comments.negative.order(:created_at)
69
+ def comments_count_by_alignment
70
+ @comments_count_by_alignment ||= Decidim::Comments::Comment.where(commentable: model).group(:alignment).count
76
71
  end
77
72
 
78
- def set_column_variables(top_comment, comments, icon_name, title)
73
+ # rubocop:disable Metrics/ParameterLists
74
+ def set_column_variables(top_comment, comments, icon_name, title, alignment, has_more)
79
75
  @top_comment = top_comment
80
76
  @comments = comments
81
77
  @icon_name = icon_name
82
78
  @title = title
79
+ @alignment = alignment
80
+ @has_more = has_more
83
81
  end
82
+ # rubocop:enable Metrics/ParameterLists
84
83
  end
85
84
  end
86
85
  end
@@ -13,21 +13,29 @@ module Decidim
13
13
  before_action :set_commentable, except: [:destroy, :update]
14
14
  before_action :ensure_commentable!, except: [:destroy, :update]
15
15
 
16
- helper_method :root_depth, :commentable, :order, :reply?, :reload?, :root_comment
16
+ helper_method :root_depth, :commentable, :order, :reply?, :reload?, :root_comment, :load_more?, :comments_offset, :alignment
17
17
 
18
18
  def index
19
19
  enforce_permission_to(:read, :comment, commentable:)
20
20
 
21
- @comments = SortedComments.for(
22
- commentable,
23
- order_by: order,
24
- after: params.fetch(:after, 0).to_i
25
- )
21
+ if commentable.is_a?(Decidim::Comments::Comment)
22
+ @comments = commentable.descendants.includes(:author, :up_votes, :down_votes).to_a
23
+ @has_more_comments = false
24
+ else
25
+ @sorted_comments_query = SortedComments.new(
26
+ commentable,
27
+ order_by: order,
28
+ offset: comments_offset,
29
+ alignment:
30
+ )
31
+ @comments = @sorted_comments_query.query
32
+ @has_more_comments = @sorted_comments_query.has_more?
33
+ end
26
34
  @comments = @comments.reject do |comment|
27
35
  next if comment.depth < 1
28
36
  next if !comment.deleted? && !comment.hidden?
29
37
 
30
- comment.commentable.descendants.where(decidim_commentable_type: "Decidim::Comments::Comment").not_hidden.not_deleted.blank?
38
+ comment.commentable.replies.blank?
31
39
  end
32
40
  @comments_count = commentable.comments_count
33
41
 
@@ -35,6 +43,8 @@ module Decidim
35
43
  format.js do
36
44
  if reload?
37
45
  render :reload
46
+ elsif load_more?
47
+ render :load_more_comments
38
48
  else
39
49
  render :index
40
50
  end
@@ -187,10 +197,25 @@ module Decidim
187
197
  params.fetch(:reload, 0).to_i == 1
188
198
  end
189
199
 
200
+ def load_more?
201
+ params.fetch(:load_more, 0).to_i == 1
202
+ end
203
+
204
+ def comments_offset
205
+ params.fetch(:offset, 0).to_i
206
+ end
207
+
190
208
  def root_depth
191
209
  params.fetch(:root_depth, 0).to_i
192
210
  end
193
211
 
212
+ def alignment
213
+ value = params.fetch(:alignment, nil)
214
+ return nil if value.blank?
215
+
216
+ value.to_i
217
+ end
218
+
194
219
  def commentable_path
195
220
  return commentable.polymorphic_resource_path({}) if commentable.respond_to?(:polymorphic_resource_path)
196
221
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "decidim/seeds"
4
+
3
5
  module Decidim
4
6
  module Comments
5
7
  # A comment can belong to many Commentable models. This class is responsible
@@ -10,7 +12,7 @@ module Decidim
10
12
  # Adds a random amount of comments for a given resource.
11
13
  #
12
14
  # @param resource [Object] - the Decidim resource to add the comments to.
13
- # examples: Decidim::Proposals::CollaborativeDraft, Decidim::Proposals::Proposal,
15
+ # examples: Decidim::Proposals::Proposal
14
16
  #
15
17
  # @return nil
16
18
  def comments_for(resource)
@@ -20,16 +22,16 @@ module Decidim
20
22
 
21
23
  @organization = resource.organization
22
24
 
23
- rand(0..6).times do
25
+ rand(0..config_value(:comments_count)).times do
24
26
  comment1 = create_comment(resource)
25
27
  NewCommentNotificationCreator.new(comment1, []).create
26
28
 
27
- if [true, false].sample
29
+ if rand < config_value(:comments_nested_probability)
28
30
  comment2 = create_comment(comment1, resource)
29
31
  NewCommentNotificationCreator.new(comment2, []).create
30
32
  end
31
33
 
32
- next if [true, false].sample
34
+ next if rand < config_value(:comments_vote_skip_probability)
33
35
 
34
36
  create_votes(comment1) if comment1
35
37
  create_votes(comment2) if comment2
@@ -40,12 +42,20 @@ module Decidim
40
42
 
41
43
  attr_reader :organization
42
44
 
45
+ def config_value(key)
46
+ slow_seeds? ? Decidim::Seeds::SEEDS_CONFIG[key][:slow] : Decidim::Seeds::SEEDS_CONFIG[key][:fast]
47
+ end
48
+
49
+ def slow_seeds?
50
+ Decidim::Env.new("SLOW_SEEDS").present?
51
+ end
52
+
43
53
  # Creates a comment for a given resource.
44
54
  #
45
55
  # @private
46
56
  #
47
57
  # @param resource [Object] - the Decidim resource to add the comments to.
48
- # @param root_commentable - the root commentable resource. It is optional, used for making nested comments.
58
+ # @param root_commentable [Object, Decidim::Comments::Comment] - the root commentable resource. It is optional, used for making nested comments.
49
59
  #
50
60
  # @return [Decidim::Comments::Comment]
51
61
  def create_comment(resource, root_commentable = nil)
@@ -70,11 +80,11 @@ module Decidim
70
80
  #
71
81
  # @private
72
82
  #
73
- # @param [Decidim::Comments::Comment]
83
+ # @param comment [Decidim::Comments::Comment]
74
84
  #
75
85
  # @return nil
76
86
  def create_votes(comment)
77
- rand(0..12).times do
87
+ rand(0..config_value(:comments_votes_count)).times do
78
88
  author = random_user
79
89
  next if CommentVote.where(comment:, author:).any?
80
90
 
@@ -4,3 +4,9 @@ import "stylesheets/comments.scss"
4
4
  // JavaScript
5
5
  import "src/decidim/comments/comments"
6
6
  import "src/decidim/comments/comments_mobile_modal"
7
+
8
+ // Stimulus controllers
9
+ import { definitionsFromContext } from "src/decidim/refactor/support/stimulus"
10
+
11
+ const context = require.context("src/decidim/comments/controllers", true, /controller\.js$/)
12
+ window.Stimulus.load(definitionsFromContext(context))
@@ -22,7 +22,6 @@ export default class CommentsComponent {
22
22
  this.rootDepth = config.rootDepth;
23
23
  this.order = config.order;
24
24
  this.lastCommentId = config.lastCommentId;
25
- this.pollingInterval = config.pollingInterval || 15000;
26
25
  this.singleComment = config.singleComment;
27
26
  this.toggleTranslations = config.toggleTranslations;
28
27
  this.id = this.$element.attr("id") || this._getUID();
@@ -59,7 +58,6 @@ export default class CommentsComponent {
59
58
  unmountComponent() {
60
59
  if (this.mounted) {
61
60
  this.mounted = false;
62
- this._stopPolling();
63
61
  this.lastCommentId = null;
64
62
 
65
63
  $(".add-comment [data-opinion-toggle] button", this.$element).off("click.decidim-comments");
@@ -161,7 +159,6 @@ export default class CommentsComponent {
161
159
  const $submit = $("button[type='submit']", $form);
162
160
 
163
161
  $submit.attr("disabled", "disabled");
164
- this._stopPolling();
165
162
  });
166
163
 
167
164
  const $dropdown = $add.find("[data-comments-dropdown]");
@@ -225,22 +222,6 @@ export default class CommentsComponent {
225
222
  }
226
223
  });
227
224
  }
228
-
229
- // Restart the polling
230
- this._pollComments();
231
- }
232
-
233
- /**
234
- * Sets a timeout to poll new comments.
235
- * @private
236
- * @returns {Void} - Returns nothing
237
- */
238
- _pollComments() {
239
- this._stopPolling();
240
-
241
- this.pollTimeout = setTimeout(() => {
242
- this._fetchComments();
243
- }, this.pollingInterval);
244
225
  }
245
226
 
246
227
  reloadAllComments() {
@@ -265,29 +246,16 @@ export default class CommentsComponent {
265
246
  "root_depth": this.rootDepth,
266
247
  "order": this.order,
267
248
  // From here, the rest of properties are optional
268
- ...(this.toggleTranslations && { "toggle_translations": this.toggleTranslations }),
269
- ...(this.lastCommentId && { "after": this.lastCommentId })
249
+ ...(this.toggleTranslations && { "toggle_translations": this.toggleTranslations })
270
250
  }),
271
251
  success: () => {
272
252
  if (successCallback) {
273
253
  successCallback();
274
254
  }
275
- this._pollComments();
276
255
  }
277
256
  });
278
257
  }
279
258
 
280
- /**
281
- * Stops polling for new comments.
282
- * @private
283
- * @returns {Void} - Returns nothing
284
- */
285
- _stopPolling() {
286
- if (this.pollTimeout) {
287
- clearTimeout(this.pollTimeout);
288
- }
289
- }
290
-
291
259
  /**
292
260
  * Sets the loading comments element visible in the view.
293
261
  * @private
@@ -299,16 +267,6 @@ export default class CommentsComponent {
299
267
  $("> .loading-comments", $container).removeClass("hidden");
300
268
  }
301
269
 
302
- /**
303
- * Event listener for the ordering links.
304
- * @private
305
- * @returns {Void} - Returns nothing
306
- */
307
- _onInitOrder() {
308
- this._stopPolling();
309
- this._setLoading();
310
- }
311
-
312
270
  /**
313
271
  * Updates the state of the submit button based on input text and opinion selection.
314
272
  *