decidim-posts 1.0.0
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.
- checksums.yaml +7 -0
- data/LICENSE-AGPLv3.txt +661 -0
- data/README.md +40 -0
- data/Rakefile +9 -0
- data/app/cells/decidim/posts/comments/add_comment.erb +15 -0
- data/app/cells/decidim/posts/comments/comments_loading.erb +1 -0
- data/app/cells/decidim/posts/comments/order_control.erb +13 -0
- data/app/cells/decidim/posts/comments/show.erb +31 -0
- data/app/cells/decidim/posts/comments_cell.rb +158 -0
- data/app/cells/decidim/posts/content_blocks/posts/show.erb +3 -0
- data/app/cells/decidim/posts/content_blocks/posts_cell.rb +50 -0
- data/app/cells/decidim/posts/content_blocks/posts_settings_form/show.erb +3 -0
- data/app/cells/decidim/posts/content_blocks/posts_settings_form_cell.rb +23 -0
- data/app/cells/decidim/posts/feed_dropdown_metadata_cell.rb +19 -0
- data/app/cells/decidim/posts/meeting/show.erb +65 -0
- data/app/cells/decidim/posts/meeting_cell.rb +44 -0
- data/app/cells/decidim/posts/post/show.erb +30 -0
- data/app/cells/decidim/posts/post/survey.erb +68 -0
- data/app/cells/decidim/posts/post_attachments/show.erb +40 -0
- data/app/cells/decidim/posts/post_attachments_cell.rb +17 -0
- data/app/cells/decidim/posts/post_cell.rb +44 -0
- data/app/cells/decidim/posts/post_comment/show.erb +17 -0
- data/app/cells/decidim/posts/post_comment_cell.rb +49 -0
- data/app/cells/decidim/posts/post_header/show.erb +53 -0
- data/app/cells/decidim/posts/post_header_cell.rb +79 -0
- data/app/cells/decidim/posts/post_host/show.erb +74 -0
- data/app/cells/decidim/posts/post_host_cell.rb +73 -0
- data/app/cells/decidim/posts/post_metadata/show.erb +9 -0
- data/app/cells/decidim/posts/post_metadata_cell.rb +67 -0
- data/app/cells/decidim/posts/reaction_menu/show.erb +18 -0
- data/app/cells/decidim/posts/reaction_menu/styles.erb +7 -0
- data/app/cells/decidim/posts/reaction_menu_cell.rb +26 -0
- data/app/cells/decidim/posts/reactions/show.erb +8 -0
- data/app/cells/decidim/posts/reactions_cell.rb +22 -0
- data/app/commands/decidim/posts/add_reaction_to_resource.rb +90 -0
- data/app/commands/decidim/posts/create_post.rb +112 -0
- data/app/commands/decidim/posts/destroy_post.rb +20 -0
- data/app/commands/decidim/posts/remove_reaction_from_resource.rb +41 -0
- data/app/commands/decidim/posts/update_post.rb +72 -0
- data/app/controllers/concerns/decidim/posts/admin/filterable.rb +46 -0
- data/app/controllers/concerns/decidim/posts/reactionable.rb +31 -0
- data/app/controllers/decidim/posts/admin/application_controller.rb +26 -0
- data/app/controllers/decidim/posts/admin/posts_controller.rb +93 -0
- data/app/controllers/decidim/posts/application_controller.rb +18 -0
- data/app/controllers/decidim/posts/meetings_controller.rb +176 -0
- data/app/controllers/decidim/posts/posts_controller.rb +202 -0
- data/app/controllers/decidim/posts/reactions_controller.rb +54 -0
- data/app/controllers/decidim/posts/user_answers_controller.rb +36 -0
- data/app/events/decidim/posts/resource_reacted_event.rb +38 -0
- data/app/forms/decidim/posts/answer_form.rb +13 -0
- data/app/forms/decidim/posts/post_form.rb +121 -0
- data/app/forms/decidim/posts/question_form.rb +20 -0
- data/app/helpers/decidim/posts/admin/posts_helper.rb +8 -0
- data/app/helpers/decidim/posts/application_helper.rb +20 -0
- data/app/helpers/decidim/posts/post_cells_helper.rb +35 -0
- data/app/helpers/decidim/posts/posts_helper.rb +34 -0
- data/app/helpers/decidim/posts/reaction_helper.rb +22 -0
- data/app/models/decidim/posts/answer.rb +13 -0
- data/app/models/decidim/posts/application_record.rb +10 -0
- data/app/models/decidim/posts/post.rb +116 -0
- data/app/models/decidim/posts/question.rb +17 -0
- data/app/models/decidim/posts/reaction.rb +22 -0
- data/app/models/decidim/posts/reaction_type.rb +13 -0
- data/app/models/decidim/posts/user_answer.rb +11 -0
- data/app/packs/entrypoints/decidim_posts.js +5 -0
- data/app/packs/entrypoints/decidim_posts.scss +1 -0
- data/app/packs/images/decidim/posts/icon.svg +1 -0
- data/app/packs/src/decidim/posts/carousel.js +112 -0
- data/app/packs/src/decidim/posts/host_status.js +75 -0
- data/app/packs/src/decidim/posts/newFeeds.js +98 -0
- data/app/packs/src/decidim/posts/posts.js +272 -0
- data/app/packs/src/decidim/posts/submenu.js +46 -0
- data/app/packs/src/decidim/posts/survey.js +94 -0
- data/app/packs/stylesheets/decidim/posts/_variables.scss +10 -0
- data/app/packs/stylesheets/decidim/posts/posts.scss +415 -0
- data/app/permissions/decidim/posts/admin/permissions.rb +23 -0
- data/app/permissions/decidim/posts/permissions.rb +101 -0
- data/app/presenters/decidim/posts/post_presenter.rb +45 -0
- data/app/views/decidim/posts/admin/posts/_post-tr.html.erb +45 -0
- data/app/views/decidim/posts/admin/posts/index.html.erb +54 -0
- data/app/views/decidim/posts/meetings/edit.html.erb +24 -0
- data/app/views/decidim/posts/posts/_admin_options.html.erb +30 -0
- data/app/views/decidim/posts/posts/_attachment.html.erb +24 -0
- data/app/views/decidim/posts/posts/_edit_form.html.erb +16 -0
- data/app/views/decidim/posts/posts/_feed.html.erb +8 -0
- data/app/views/decidim/posts/posts/_form.html.erb +104 -0
- data/app/views/decidim/posts/posts/_index.html.erb +49 -0
- data/app/views/decidim/posts/posts/_meeting_form.erb +18 -0
- data/app/views/decidim/posts/posts/_new.html.erb +33 -0
- data/app/views/decidim/posts/posts/_new_survey.html.erb +20 -0
- data/app/views/decidim/posts/posts/_new_survey_answer.html.erb +11 -0
- data/app/views/decidim/posts/posts/_new_survey_question.html.erb +17 -0
- data/app/views/decidim/posts/posts/_post.html.erb +11 -0
- data/app/views/decidim/posts/posts/_post_form.html.erb +5 -0
- data/app/views/decidim/posts/posts/_sidebar.html.erb +36 -0
- data/app/views/decidim/posts/posts/edit.html.erb +34 -0
- data/app/views/decidim/posts/posts/index.html.erb +1 -0
- data/app/views/decidim/posts/posts/show.html.erb +12 -0
- data/app/views/decidim/posts/reactions/_update_buttons_and_counters.html.erb +1 -0
- data/config/assets.rb +9 -0
- data/config/i18n-tasks.yml +10 -0
- data/config/locales/bs.yml +215 -0
- data/config/locales/de.yml +217 -0
- data/config/locales/en.yml +216 -0
- data/config/locales/hr.yml +219 -0
- data/config/locales/it.yml +215 -0
- data/config/locales/sr.yml +220 -0
- data/config/locales/tr.yml +219 -0
- data/lib/decidim/posts/admin.rb +10 -0
- data/lib/decidim/posts/admin_engine.rb +25 -0
- data/lib/decidim/posts/component.rb +59 -0
- data/lib/decidim/posts/content_blocks/content_blocks_homepage.rb +19 -0
- data/lib/decidim/posts/engine.rb +84 -0
- data/lib/decidim/posts/test/factories.rb +14 -0
- data/lib/decidim/posts/version.rb +9 -0
- data/lib/decidim/posts.rb +13 -0
- metadata +183 -0
data/README.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Decidim::Posts component (under development)
|
|
2
|
+
|
|
3
|
+
This Feeds component adds social posts functionality to Decidim.
|
|
4
|
+
|
|
5
|
+
**The module is currently in development and not yet ready.**
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
Feeds will be available as a Component for a Participatory
|
|
10
|
+
Space.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
Add this line to your application's Gemfile:
|
|
15
|
+
|
|
16
|
+
```ruby
|
|
17
|
+
gem "decidim-posts", git: "https://github.com/DecidimAustria/decidim-module-posts.git", branch: "main"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
And then execute:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
bundle
|
|
24
|
+
bundle exec rails decidim_posts:install:migrations
|
|
25
|
+
bundle exec rails db:migrate
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Contributing
|
|
29
|
+
|
|
30
|
+
Contributions are welcome !
|
|
31
|
+
|
|
32
|
+
We expect the contributions to follow the [Decidim's contribution guide](https://github.com/decidim/decidim/blob/develop/CONTRIBUTING.adoc).
|
|
33
|
+
|
|
34
|
+
## Security
|
|
35
|
+
|
|
36
|
+
Security is very important to us. If you have any issue regarding security, please disclose the information responsibly by sending an email to __security [at] mitgestalten [dot] jetzt__ and not by creating a Github issue.
|
|
37
|
+
|
|
38
|
+
## License
|
|
39
|
+
|
|
40
|
+
This engine is distributed under the GNU AFFERO GENERAL PUBLIC LICENSE.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "decidim/dev/common_rake"
|
|
4
|
+
|
|
5
|
+
desc "Generates a dummy app for testing"
|
|
6
|
+
task test_app: "decidim:generate_external_test_app"
|
|
7
|
+
|
|
8
|
+
desc "Generates a development app."
|
|
9
|
+
task development_app: "decidim:generate_external_development_app"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<div class="add-comment">
|
|
2
|
+
<% if user_signed_in? %>
|
|
3
|
+
<%== cell("decidim/comments/comment_form", model, root_depth:) %>
|
|
4
|
+
<% else %>
|
|
5
|
+
<p>
|
|
6
|
+
<span>
|
|
7
|
+
<%== t(
|
|
8
|
+
"decidim.components.add_comment_form.account_message",
|
|
9
|
+
sign_in_url: decidim.new_user_session_path,
|
|
10
|
+
sign_up_url: decidim.new_user_registration_path
|
|
11
|
+
) %>
|
|
12
|
+
</span>
|
|
13
|
+
</p>
|
|
14
|
+
<% end %>
|
|
15
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= cell("decidim/announcement", t("decidim.components.comments.loading"), callout_class: "primary loading-comments mb-4") %>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<div class="comment-order-by">
|
|
2
|
+
<% available_orders.each do | order_value| %>
|
|
3
|
+
<div class="text-center">
|
|
4
|
+
<%= link_to(
|
|
5
|
+
t("decidim.components.comment_order_selector.order.#{order_value}"),
|
|
6
|
+
decidim_comments.comments_path(commentable_gid: model.to_signed_global_id.to_s, order: order_value, reload: 1),
|
|
7
|
+
class: "button button__sm button__text-secondary only:m-auto comment-order-by__item inline-block #{order_value == order ? "underline font-bold" : ""}",
|
|
8
|
+
remote: true,
|
|
9
|
+
aria: { controls: threads_node_id }
|
|
10
|
+
) %>
|
|
11
|
+
</div>
|
|
12
|
+
<% end %>
|
|
13
|
+
</div>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<%= append_stylesheet_pack_tag "decidim_comments" %>
|
|
2
|
+
<%= content_tag :div, id: node_id, data: { decidim_posts_comments: comments_data } do %>
|
|
3
|
+
<div id="comments">
|
|
4
|
+
<div class="comments">
|
|
5
|
+
<div class="comments__header">
|
|
6
|
+
<h2 class="h4">
|
|
7
|
+
<% if single_comment? %>
|
|
8
|
+
<%= t("decidim.components.comments.comment_details_title") %>
|
|
9
|
+
<% else %>
|
|
10
|
+
<%= icon "chat-1-line", class: "fill-tertiary w-6 h-6 inline-block align-middle" %>
|
|
11
|
+
<span class="comments-count inline-block align-middle">
|
|
12
|
+
<%= t("decidim.components.comments.title", count: comments_count) %>
|
|
13
|
+
</span>
|
|
14
|
+
<% end %>
|
|
15
|
+
</h2>
|
|
16
|
+
<%= render :order_control %>
|
|
17
|
+
</div>
|
|
18
|
+
<%= single_comment_warning %>
|
|
19
|
+
<%= blocked_comments_warning %>
|
|
20
|
+
<div class="comment-threads" id="<%= threads_node_id %>" aria-live="polite">
|
|
21
|
+
<%= comments_loading %>
|
|
22
|
+
<% comments.each do |comment| %>
|
|
23
|
+
<%= cell("decidim/comments/comment_thread", comment, order:) %>
|
|
24
|
+
<% end %>
|
|
25
|
+
</div>
|
|
26
|
+
<%= add_comment %>
|
|
27
|
+
<%= user_comments_blocked_warning %>
|
|
28
|
+
</div>
|
|
29
|
+
<%= cell("decidim/announcement", t("decidim.components.comments.loading"), callout_class: "primary loading-comments hidden") %>
|
|
30
|
+
</div>
|
|
31
|
+
<% end %>
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Posts
|
|
5
|
+
# A cell to display a comments section for a commentable object.
|
|
6
|
+
class CommentsCell < Decidim::ViewModel
|
|
7
|
+
include Decidim::IconHelper
|
|
8
|
+
|
|
9
|
+
delegate :user_signed_in?, to: :controller
|
|
10
|
+
|
|
11
|
+
def add_comment
|
|
12
|
+
return if single_comment?
|
|
13
|
+
return if comments_blocked?
|
|
14
|
+
return if user_comments_blocked?
|
|
15
|
+
|
|
16
|
+
render :add_comment
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def single_comment_warning
|
|
20
|
+
return unless single_comment?
|
|
21
|
+
|
|
22
|
+
render :single_comment_warning
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def comments_loading
|
|
26
|
+
return if single_comment?
|
|
27
|
+
|
|
28
|
+
render :comments_loading
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def blocked_comments_warning
|
|
32
|
+
return unless comments_blocked?
|
|
33
|
+
return unless user_comments_blocked?
|
|
34
|
+
|
|
35
|
+
render :blocked_comments_warning
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def user_comments_blocked_warning
|
|
39
|
+
return if comments_blocked? # Shows already the general warning
|
|
40
|
+
return unless user_comments_blocked?
|
|
41
|
+
|
|
42
|
+
render :user_comments_blocked_warning
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def decidim_comments
|
|
48
|
+
Decidim::Comments::Engine.routes.url_helpers
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def comments
|
|
52
|
+
single_comment? ? [single_comment] : []
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def comments_count
|
|
56
|
+
model.comments_count
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def root_depth
|
|
60
|
+
return 0 unless single_comment?
|
|
61
|
+
|
|
62
|
+
single_comment.depth
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def commentable_path(params = {})
|
|
66
|
+
return resource_locator(Array(options[:polymorphic]).push(model)).path(params) if options[:polymorphic]
|
|
67
|
+
|
|
68
|
+
resource_locator(model).path(params)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def alignment_enabled?
|
|
72
|
+
model.comments_have_alignment?
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def available_orders
|
|
76
|
+
%w(best_rated recent older most_discussed)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def order
|
|
80
|
+
options[:order] || "older"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def decidim
|
|
84
|
+
Decidim::Core::Engine.routes.url_helpers
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def node_id
|
|
88
|
+
"comments-for-#{commentable_type.demodulize}-#{model.id}"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def threads_node_id
|
|
92
|
+
"#{node_id}-threads"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def commentable_type
|
|
96
|
+
model.commentable_type
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def comments_data
|
|
100
|
+
{
|
|
101
|
+
singleComment: single_comment?,
|
|
102
|
+
toggleTranslations: machine_translations_toggled?,
|
|
103
|
+
commentableGid: model.to_signed_global_id.to_s,
|
|
104
|
+
commentsUrl: decidim_comments.comments_path,
|
|
105
|
+
rootDepth: root_depth,
|
|
106
|
+
order:,
|
|
107
|
+
pollingInterval: 300000
|
|
108
|
+
}
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def single_comment?
|
|
112
|
+
single_comment.present?
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def single_comment
|
|
116
|
+
return if options[:single_comment].blank?
|
|
117
|
+
|
|
118
|
+
@single_comment ||= SortedComments.for(model, id: options[:single_comment], order_by: order).first
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def machine_translations_toggled?
|
|
122
|
+
options[:machine_translations] == true
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def comments_blocked?
|
|
126
|
+
!model.accepts_new_comments?
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def user_comments_blocked?
|
|
130
|
+
return false unless user_signed_in?
|
|
131
|
+
|
|
132
|
+
!model.user_allowed_to_comment?(current_user)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def comment_permissions?
|
|
136
|
+
[model, current_component].any? do |resource|
|
|
137
|
+
resource.try(:permissions).try(:[], "comment")
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# action_authorization_link expects current_component to be available
|
|
142
|
+
def current_component
|
|
143
|
+
model.try(:component)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def blocked_comments_for_unauthorized_user_warning_link
|
|
147
|
+
options = if current_component.present?
|
|
148
|
+
{ resource: model }
|
|
149
|
+
else
|
|
150
|
+
{ resource: model, permissions_holder: model }
|
|
151
|
+
end
|
|
152
|
+
action_authorized_link_to(:comment, commentable_path, options) do
|
|
153
|
+
t("decidim.components.comments.blocked_comments_for_unauthorized_user_warning")
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Posts
|
|
5
|
+
module ContentBlocks
|
|
6
|
+
class PostsCell < Decidim::ViewModel
|
|
7
|
+
include Cell::ViewModel::Partial
|
|
8
|
+
include FormFactory
|
|
9
|
+
|
|
10
|
+
def show
|
|
11
|
+
@posts = Decidim::Posts::Post
|
|
12
|
+
.where(decidim_component_id: component_id)
|
|
13
|
+
.filter_category(params[:filter_post_category])
|
|
14
|
+
.order(created_at: :desc)
|
|
15
|
+
.limit(10)
|
|
16
|
+
extra_context = {
|
|
17
|
+
current_component: component,
|
|
18
|
+
current_organization: component.organization,
|
|
19
|
+
current_user:,
|
|
20
|
+
current_participatory_space: component.participatory_space
|
|
21
|
+
}
|
|
22
|
+
@form = form(Decidim::Posts::PostForm).from_params(params, extra_context)
|
|
23
|
+
render :show
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def decidim_feeds
|
|
27
|
+
Decidim::EngineRouter.main_proxy(component)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def posts_path
|
|
31
|
+
decidim_feeds.posts_path
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def component_id
|
|
37
|
+
@component_id ||= model.settings.try(:component_id)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def component
|
|
41
|
+
@component ||= Decidim::Component.find(component_id)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def post_creation_params
|
|
45
|
+
params[:post]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Posts
|
|
5
|
+
module ContentBlocks
|
|
6
|
+
class PostsSettingsFormCell < Decidim::ViewModel
|
|
7
|
+
# Found in HighlightedElementsForComponentSettingsFormCell
|
|
8
|
+
#include Decidim::ContentBlocks::HasRelatedComponents
|
|
9
|
+
alias form model
|
|
10
|
+
|
|
11
|
+
def available_feeds_options
|
|
12
|
+
available_feeds.map do |component|
|
|
13
|
+
[translated_attribute(component.name), component.id]
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def available_feeds
|
|
18
|
+
@available_feeds ||= Decidim::Component.where(manifest_name: "posts").where(participatory_space_id: current_organization.participatory_spaces.pluck(:id))
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Posts
|
|
5
|
+
class FeedDropdownMetadataCell < Decidim::ParticipatorySpaceDropdownMetadataCell
|
|
6
|
+
# include FeedsHelper
|
|
7
|
+
include Decidim::ComponentPathHelper
|
|
8
|
+
include ActiveLinkTo
|
|
9
|
+
|
|
10
|
+
def decidim_feeds
|
|
11
|
+
Decidim::Posts::Engine.routes.url_helpers
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def nav_items_method = :assembly_nav_items
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<article class="card__grid posts__post" data-content="calendar">
|
|
2
|
+
<%= cell("decidim/posts/post_header", meeting) %>
|
|
3
|
+
<div class="flex gap-4 py-2 px-2">
|
|
4
|
+
<div class="card__grid-text--meta flex flex-col gap-2">
|
|
5
|
+
<time class="card__calendar" datetime="<%= meeting.start_time.iso8601 %>">
|
|
6
|
+
<span class="card__calendar-month"><%= l(meeting.start_time, format: "%b") %></span>
|
|
7
|
+
<span class="card__calendar-day"><%= l(meeting.start_time, format: "%d") %></span>
|
|
8
|
+
<span class="card__calendar-year"><%= l(meeting.start_time, format: "%Y") %></span>
|
|
9
|
+
</time>
|
|
10
|
+
<% if meeting.start_time.to_date != meeting.end_time.to_date %>
|
|
11
|
+
<span class="self-center font-bold text-xs"><%= t("decidim.components.posts.calendar.date_separator") %></span>
|
|
12
|
+
<time class="card__calendar" datetime="<%= meeting.end_time.iso8601 %>">
|
|
13
|
+
<span class="card__calendar-month"><%= l(meeting.end_time, format: "%b") %></span>
|
|
14
|
+
<span class="card__calendar-day"><%= l(meeting.end_time, format: "%d") %></span>
|
|
15
|
+
<span class="card__calendar-year"><%= l(meeting.end_time, format: "%Y") %></span>
|
|
16
|
+
</time>
|
|
17
|
+
<% end %>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="card__grid-text p-0">
|
|
20
|
+
<h2 class="h3"><%= link_to meeting_title, Decidim::EngineRouter.main_proxy(meeting.component).meeting_path(meeting) %></h2>
|
|
21
|
+
<% should_truncate = strip_tags(meeting_description).length > 300 %>
|
|
22
|
+
<div class="content-block__description editor-content" <%= "data-component='accordion'" if should_truncate %>>
|
|
23
|
+
<% if should_truncate %>
|
|
24
|
+
<% seed = SecureRandom.hex(4) %>
|
|
25
|
+
<div id="panel-view-more-<%= seed %>" aria-hidden="true">
|
|
26
|
+
<%= meeting_description %>
|
|
27
|
+
</div>
|
|
28
|
+
<button class="button button__sm button__text-secondary mt-2" data-controls="panel-view-more-<%= seed %>" aria-expanded="false">
|
|
29
|
+
<span>
|
|
30
|
+
<%= t("view_more", scope: "layouts.decidim.announcements") %>
|
|
31
|
+
</span>
|
|
32
|
+
<%= icon "arrow-down-s-line" %>
|
|
33
|
+
<span>
|
|
34
|
+
<%= t("view_less", scope: "layouts.decidim.announcements") %>
|
|
35
|
+
</span>
|
|
36
|
+
<%= icon "arrow-up-s-line" %>
|
|
37
|
+
</button>
|
|
38
|
+
<% else %>
|
|
39
|
+
<%= meeting_description %>
|
|
40
|
+
<% end %>
|
|
41
|
+
</div>
|
|
42
|
+
<div class="flex gap-4 mt-auto flex-wrap">
|
|
43
|
+
<div class="bg-background p-2 rounded-md font-bold shrink">
|
|
44
|
+
<time datetime="<%= meeting.start_time.iso8601 %>">
|
|
45
|
+
<%= l(meeting.start_time, format: "%H:%M") %>
|
|
46
|
+
</time>
|
|
47
|
+
</time>
|
|
48
|
+
<% if meeting.start_time != meeting.end_time %>
|
|
49
|
+
<%= t("decidim.components.posts.calendar.end_time") %>
|
|
50
|
+
<time datetime="<%= meeting.end_time.iso8601 %>">
|
|
51
|
+
<%= l(meeting.end_time, format: "%H:%M") %>
|
|
52
|
+
</time>
|
|
53
|
+
<% end %>
|
|
54
|
+
</div>
|
|
55
|
+
<% if meeting_location != '' %>
|
|
56
|
+
<div class="bg-background p-2 rounded-md font-bold shrink">
|
|
57
|
+
<%= meeting_location %>
|
|
58
|
+
</div>
|
|
59
|
+
<% end %>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
<%= cell("decidim/posts/post_comment", meeting) %>
|
|
64
|
+
<%= cell("decidim/posts/post_metadata", meeting) %>
|
|
65
|
+
</article>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Posts
|
|
5
|
+
class MeetingCell < Decidim::ViewModel
|
|
6
|
+
include PostCellsHelper
|
|
7
|
+
include Decidim::Meetings::MeetingCellsHelper
|
|
8
|
+
include Cell::ViewModel::Partial
|
|
9
|
+
|
|
10
|
+
def show
|
|
11
|
+
render :show
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def meeting
|
|
15
|
+
model
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def meeting_author
|
|
19
|
+
model.decidim_author_id
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def meeting_title
|
|
23
|
+
translated_attribute model.title
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def meeting_description
|
|
27
|
+
translated_attribute model.description
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def meeting_address
|
|
31
|
+
model.address
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def meeting_location
|
|
35
|
+
translated_attribute model.location
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def comments_enabled
|
|
39
|
+
model.comments_enabled?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<%= cell("decidim/posts/post_header", post) %>
|
|
2
|
+
<%= cell("decidim/posts/post_attachments", post) %>
|
|
3
|
+
<div class="card__grid-text">
|
|
4
|
+
<% should_truncate = strip_tags(post_body).length > 300 %>
|
|
5
|
+
<div class="content-block__description editor-content" <%= "data-component='accordion'" if should_truncate %>>
|
|
6
|
+
<% if should_truncate %>
|
|
7
|
+
<% seed = SecureRandom.hex(4) %>
|
|
8
|
+
<div id="panel-view-more-<%= seed %>" aria-hidden="true">
|
|
9
|
+
<%= post_body %>
|
|
10
|
+
</div>
|
|
11
|
+
<button class="button button__sm button__text-secondary mt-2" data-controls="panel-view-more-<%= seed %>" aria-expanded="false">
|
|
12
|
+
<span>
|
|
13
|
+
<%= t("view_more", scope: "layouts.decidim.announcements") %>
|
|
14
|
+
</span>
|
|
15
|
+
<%= icon "arrow-down-s-line" %>
|
|
16
|
+
<span>
|
|
17
|
+
<%= t("view_less", scope: "layouts.decidim.announcements") %>
|
|
18
|
+
</span>
|
|
19
|
+
<%= icon "arrow-up-s-line" %>
|
|
20
|
+
</button>
|
|
21
|
+
<% else %>
|
|
22
|
+
<%= post_body %>
|
|
23
|
+
<% end %>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
<% if post_category == 'survey' %>
|
|
27
|
+
<%= render :survey %>
|
|
28
|
+
<% end %>
|
|
29
|
+
<%= cell("decidim/posts/post_comment", post) %>
|
|
30
|
+
<%= cell("decidim/posts/post_metadata", post) %>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<div class="posts__post_survey" id="post_<%= post.id %>_survey">
|
|
2
|
+
<span class="text-right py-2">
|
|
3
|
+
<%= t("decidim.posts.survey.participated", count: post.survey_responses_count) %>
|
|
4
|
+
</span>
|
|
5
|
+
<% post.questions.each do |question| %>
|
|
6
|
+
<% if question.question_type == "single_choice" %>
|
|
7
|
+
<fieldset class="posts__post_survey-question">
|
|
8
|
+
<legend><%= translated_attribute question.title %></legend>
|
|
9
|
+
<% question.answers.each do |answer| %>
|
|
10
|
+
<div class="posts__post_survey-question-answer">
|
|
11
|
+
<div class="posts__post_survey-question-answerInput">
|
|
12
|
+
<%= radio_button_tag "post[questions][#{question.id}]", answer.id, answer.user_answers.find_by(decidim_posts_answer_id: answer.id, decidim_user_id: current_user.id).present?, class: "survey-answer-checkbox", data: { question_id: question.id, answer_id: answer.id } %>
|
|
13
|
+
<%= label_tag "post_questions_#{question.id}_#{answer.id}" do %>
|
|
14
|
+
<%= translated_attribute answer.title %>
|
|
15
|
+
<% end %>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="posts__post_survey-question-answerProgressbar flex justify-between p-1 border border-gray rounded-full shadow-md">
|
|
18
|
+
<div class="w-full bg-background rounded-full">
|
|
19
|
+
<% percentage = post.survey_responses_count.zero? ? 0 : (answer.user_answers.count.to_f / post.survey_responses_count) * 100 %>
|
|
20
|
+
<div id="answer-<%= answer.id %>-progressbar" class="bg-success h-full rounded-full shadow-md" style="width: <%= percentage %>%"></div>
|
|
21
|
+
</div>
|
|
22
|
+
<span class="text-sm shrink-0 px-2">
|
|
23
|
+
<span id="answer-<%= answer.id %>-counter">
|
|
24
|
+
<%= answer.user_answers.count %>
|
|
25
|
+
</span>
|
|
26
|
+
/
|
|
27
|
+
<span id="answer-<%= answer.id %>-total">
|
|
28
|
+
<%= post.survey_responses_count %>
|
|
29
|
+
</span>
|
|
30
|
+
<span class="sr-only">haben geantwortet</span>
|
|
31
|
+
</span>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
<% end %>
|
|
35
|
+
</fieldset>
|
|
36
|
+
<% elsif question.question_type == "multiple_choice" %>
|
|
37
|
+
<fieldset class="posts__post_survey-question">
|
|
38
|
+
<legend><%= translated_attribute question.title %></legend>
|
|
39
|
+
<% question.answers.each do |answer| %>
|
|
40
|
+
<div class="posts__post_survey-question-answer">
|
|
41
|
+
<div class="posts__post_survey-question-answerInput">
|
|
42
|
+
<%= check_box_tag "post[questions][#{question.id}][#{answer.id}]", answer.id, answer.user_answers.find_by(decidim_posts_answer_id: answer.id, decidim_user_id: current_user.id).present?, class: "survey-answer-checkbox", data: { question_id: question.id, answer_id: answer.id } %>
|
|
43
|
+
<%= label_tag "post_questions_#{question.id}_#{answer.id}" do %>
|
|
44
|
+
<%= translated_attribute answer.title %>
|
|
45
|
+
<% end %>
|
|
46
|
+
</div>
|
|
47
|
+
<div class="posts__post_survey-question-answerProgressbar flex justify-between p-1 border border-gray rounded-full shadow-md">
|
|
48
|
+
<div class="w-full bg-background rounded-full">
|
|
49
|
+
<% percentage = post.survey_responses_count.zero? ? 0 : (answer.user_answers.count.to_f / post.survey_responses_count) * 100 %>
|
|
50
|
+
<div id="answer-<%= answer.id %>-progressbar" class="bg-success h-full rounded-full shadow-md" style="width: <%= percentage %>%"></div>
|
|
51
|
+
</div>
|
|
52
|
+
<span class="text-sm shrink-0 px-2">
|
|
53
|
+
<span id="answer-<%= answer.id %>-counter">
|
|
54
|
+
<%= answer.user_answers.count %>
|
|
55
|
+
</span>
|
|
56
|
+
/
|
|
57
|
+
<span id="answer-<%= answer.id %>-total">
|
|
58
|
+
<%= post.survey_responses_count %>
|
|
59
|
+
</span>
|
|
60
|
+
<span class="sr-only">haben geantwortet</span>
|
|
61
|
+
</span>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
<% end %>
|
|
65
|
+
</fieldset>
|
|
66
|
+
<% end %>
|
|
67
|
+
<% end %>
|
|
68
|
+
</div>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<% if post.attachments.any? %>
|
|
2
|
+
<div class="feeds__attachments py-4 px-2">
|
|
3
|
+
|
|
4
|
+
<div class="flex flex-col items-center">
|
|
5
|
+
<ul id="galleryItems_<%= post.id %>" class="posts__post_gallery flex overflow-hidden">
|
|
6
|
+
<% post.attachments.select { |a| a.url.match(/\.(jpg|jpeg|png|svg|webp|mp4|webm)$/i) }.each_with_index do |attachment, index| %>
|
|
7
|
+
<li class="<%= attachment.url.match(/\.(mp4|webm)$/i) ? 'video' : 'image' %> <%= index.zero? ? 'active' : '' %> aspect-4/3 overflow-hidden flex justify-center items-center" data-src="<%= attachment.url %>">
|
|
8
|
+
<% if attachment.url.match(/\.(mp4|webm)$/i) %>
|
|
9
|
+
<%= video_tag(attachment.url, class: "object-cover w-full h-full", controls: true, preload: "auto") %>
|
|
10
|
+
<% else %>
|
|
11
|
+
<div class="w-full h-full flex justify-center items-center">
|
|
12
|
+
<%= image_tag(attachment.url, class: "max-w-full max-h-full object-contain", alt: translated_attribute(attachment.title), width: '400px', height: '300px' ) %>
|
|
13
|
+
</div>
|
|
14
|
+
<% end %>
|
|
15
|
+
</li>
|
|
16
|
+
<% end %>
|
|
17
|
+
</ul>
|
|
18
|
+
<% if post.attachments.select { |a| a.url.match(/\.(jpg|jpeg|png|svg|webp|mp4|webm)$/i) }.count > 1 %>
|
|
19
|
+
<div id="navDots_<%= post.id %>" class="nav-dots p-1 flex flex-wrap justify-center">
|
|
20
|
+
<% total = post.attachments.select { |a| a.url.match(/\.(jpg|jpeg|png|svg|webp|mp4|webm)$/i) }.count %>
|
|
21
|
+
<% post.attachments.select { |a| a.url.match(/\.(jpg|jpeg|png|svg|webp|mp4|webm)$/i) }.each_with_index do |_, index| %>
|
|
22
|
+
<div class="posts__post_gallery_nav_dot flex justify-center items-center cursor-pointer h-6 w-6" role="button" aria-label="<%= t('decidim.components.posts.gallery.navigation', number: index + 1, total: total) %>" data-target="galleryItems_<%= post.id %>" data-index="<%= index %>">
|
|
23
|
+
<span class="h-2 w-2 rounded-full ring-1 ring-offset-1 ring-feeds-notification <%= index.zero? ? 'bg-feeds-notification' : '' %>"></span>
|
|
24
|
+
</div>
|
|
25
|
+
<% end %>
|
|
26
|
+
</div>
|
|
27
|
+
<% end %>
|
|
28
|
+
</div>
|
|
29
|
+
<% non_media_attachments = post.attachments.reject { |a| a.url.match(/\.(jpg|jpeg|png|svg|webp|mp4|webm)$/i) } %>
|
|
30
|
+
<% if non_media_attachments.any? %>
|
|
31
|
+
<ul class="document-list space-y-2 mt-4">
|
|
32
|
+
<% non_media_attachments.each_with_index do |attachment, index| %>
|
|
33
|
+
<li class="<%= index.even? ? 'bg-feeds-formBody' : '' %> py-1 pl-2 pr-4 flex gap-1 items-center">
|
|
34
|
+
<%= icon "file-2-line" %> <%= link_to File.basename(attachment.url), attachment.url, class: 'text-sm break-all', style: 'overflow-wrap: break-word' %>
|
|
35
|
+
</li>
|
|
36
|
+
<% end %>
|
|
37
|
+
</ul>
|
|
38
|
+
<% end %>
|
|
39
|
+
</div>
|
|
40
|
+
<% end %>
|