decidim-posts 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 %>
|