decidim-posts 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE-AGPLv3.txt +661 -0
  3. data/README.md +40 -0
  4. data/Rakefile +9 -0
  5. data/app/cells/decidim/posts/comments/add_comment.erb +15 -0
  6. data/app/cells/decidim/posts/comments/comments_loading.erb +1 -0
  7. data/app/cells/decidim/posts/comments/order_control.erb +13 -0
  8. data/app/cells/decidim/posts/comments/show.erb +31 -0
  9. data/app/cells/decidim/posts/comments_cell.rb +158 -0
  10. data/app/cells/decidim/posts/content_blocks/posts/show.erb +3 -0
  11. data/app/cells/decidim/posts/content_blocks/posts_cell.rb +50 -0
  12. data/app/cells/decidim/posts/content_blocks/posts_settings_form/show.erb +3 -0
  13. data/app/cells/decidim/posts/content_blocks/posts_settings_form_cell.rb +23 -0
  14. data/app/cells/decidim/posts/feed_dropdown_metadata_cell.rb +19 -0
  15. data/app/cells/decidim/posts/meeting/show.erb +65 -0
  16. data/app/cells/decidim/posts/meeting_cell.rb +44 -0
  17. data/app/cells/decidim/posts/post/show.erb +30 -0
  18. data/app/cells/decidim/posts/post/survey.erb +68 -0
  19. data/app/cells/decidim/posts/post_attachments/show.erb +40 -0
  20. data/app/cells/decidim/posts/post_attachments_cell.rb +17 -0
  21. data/app/cells/decidim/posts/post_cell.rb +44 -0
  22. data/app/cells/decidim/posts/post_comment/show.erb +17 -0
  23. data/app/cells/decidim/posts/post_comment_cell.rb +49 -0
  24. data/app/cells/decidim/posts/post_header/show.erb +53 -0
  25. data/app/cells/decidim/posts/post_header_cell.rb +79 -0
  26. data/app/cells/decidim/posts/post_host/show.erb +74 -0
  27. data/app/cells/decidim/posts/post_host_cell.rb +73 -0
  28. data/app/cells/decidim/posts/post_metadata/show.erb +9 -0
  29. data/app/cells/decidim/posts/post_metadata_cell.rb +67 -0
  30. data/app/cells/decidim/posts/reaction_menu/show.erb +18 -0
  31. data/app/cells/decidim/posts/reaction_menu/styles.erb +7 -0
  32. data/app/cells/decidim/posts/reaction_menu_cell.rb +26 -0
  33. data/app/cells/decidim/posts/reactions/show.erb +8 -0
  34. data/app/cells/decidim/posts/reactions_cell.rb +22 -0
  35. data/app/commands/decidim/posts/add_reaction_to_resource.rb +90 -0
  36. data/app/commands/decidim/posts/create_post.rb +112 -0
  37. data/app/commands/decidim/posts/destroy_post.rb +20 -0
  38. data/app/commands/decidim/posts/remove_reaction_from_resource.rb +41 -0
  39. data/app/commands/decidim/posts/update_post.rb +72 -0
  40. data/app/controllers/concerns/decidim/posts/admin/filterable.rb +46 -0
  41. data/app/controllers/concerns/decidim/posts/reactionable.rb +31 -0
  42. data/app/controllers/decidim/posts/admin/application_controller.rb +26 -0
  43. data/app/controllers/decidim/posts/admin/posts_controller.rb +93 -0
  44. data/app/controllers/decidim/posts/application_controller.rb +18 -0
  45. data/app/controllers/decidim/posts/meetings_controller.rb +176 -0
  46. data/app/controllers/decidim/posts/posts_controller.rb +202 -0
  47. data/app/controllers/decidim/posts/reactions_controller.rb +54 -0
  48. data/app/controllers/decidim/posts/user_answers_controller.rb +36 -0
  49. data/app/events/decidim/posts/resource_reacted_event.rb +38 -0
  50. data/app/forms/decidim/posts/answer_form.rb +13 -0
  51. data/app/forms/decidim/posts/post_form.rb +121 -0
  52. data/app/forms/decidim/posts/question_form.rb +20 -0
  53. data/app/helpers/decidim/posts/admin/posts_helper.rb +8 -0
  54. data/app/helpers/decidim/posts/application_helper.rb +20 -0
  55. data/app/helpers/decidim/posts/post_cells_helper.rb +35 -0
  56. data/app/helpers/decidim/posts/posts_helper.rb +34 -0
  57. data/app/helpers/decidim/posts/reaction_helper.rb +22 -0
  58. data/app/models/decidim/posts/answer.rb +13 -0
  59. data/app/models/decidim/posts/application_record.rb +10 -0
  60. data/app/models/decidim/posts/post.rb +116 -0
  61. data/app/models/decidim/posts/question.rb +17 -0
  62. data/app/models/decidim/posts/reaction.rb +22 -0
  63. data/app/models/decidim/posts/reaction_type.rb +13 -0
  64. data/app/models/decidim/posts/user_answer.rb +11 -0
  65. data/app/packs/entrypoints/decidim_posts.js +5 -0
  66. data/app/packs/entrypoints/decidim_posts.scss +1 -0
  67. data/app/packs/images/decidim/posts/icon.svg +1 -0
  68. data/app/packs/src/decidim/posts/carousel.js +112 -0
  69. data/app/packs/src/decidim/posts/host_status.js +75 -0
  70. data/app/packs/src/decidim/posts/newFeeds.js +98 -0
  71. data/app/packs/src/decidim/posts/posts.js +272 -0
  72. data/app/packs/src/decidim/posts/submenu.js +46 -0
  73. data/app/packs/src/decidim/posts/survey.js +94 -0
  74. data/app/packs/stylesheets/decidim/posts/_variables.scss +10 -0
  75. data/app/packs/stylesheets/decidim/posts/posts.scss +415 -0
  76. data/app/permissions/decidim/posts/admin/permissions.rb +23 -0
  77. data/app/permissions/decidim/posts/permissions.rb +101 -0
  78. data/app/presenters/decidim/posts/post_presenter.rb +45 -0
  79. data/app/views/decidim/posts/admin/posts/_post-tr.html.erb +45 -0
  80. data/app/views/decidim/posts/admin/posts/index.html.erb +54 -0
  81. data/app/views/decidim/posts/meetings/edit.html.erb +24 -0
  82. data/app/views/decidim/posts/posts/_admin_options.html.erb +30 -0
  83. data/app/views/decidim/posts/posts/_attachment.html.erb +24 -0
  84. data/app/views/decidim/posts/posts/_edit_form.html.erb +16 -0
  85. data/app/views/decidim/posts/posts/_feed.html.erb +8 -0
  86. data/app/views/decidim/posts/posts/_form.html.erb +104 -0
  87. data/app/views/decidim/posts/posts/_index.html.erb +49 -0
  88. data/app/views/decidim/posts/posts/_meeting_form.erb +18 -0
  89. data/app/views/decidim/posts/posts/_new.html.erb +33 -0
  90. data/app/views/decidim/posts/posts/_new_survey.html.erb +20 -0
  91. data/app/views/decidim/posts/posts/_new_survey_answer.html.erb +11 -0
  92. data/app/views/decidim/posts/posts/_new_survey_question.html.erb +17 -0
  93. data/app/views/decidim/posts/posts/_post.html.erb +11 -0
  94. data/app/views/decidim/posts/posts/_post_form.html.erb +5 -0
  95. data/app/views/decidim/posts/posts/_sidebar.html.erb +36 -0
  96. data/app/views/decidim/posts/posts/edit.html.erb +34 -0
  97. data/app/views/decidim/posts/posts/index.html.erb +1 -0
  98. data/app/views/decidim/posts/posts/show.html.erb +12 -0
  99. data/app/views/decidim/posts/reactions/_update_buttons_and_counters.html.erb +1 -0
  100. data/config/assets.rb +9 -0
  101. data/config/i18n-tasks.yml +10 -0
  102. data/config/locales/bs.yml +215 -0
  103. data/config/locales/de.yml +217 -0
  104. data/config/locales/en.yml +216 -0
  105. data/config/locales/hr.yml +219 -0
  106. data/config/locales/it.yml +215 -0
  107. data/config/locales/sr.yml +220 -0
  108. data/config/locales/tr.yml +219 -0
  109. data/lib/decidim/posts/admin.rb +10 -0
  110. data/lib/decidim/posts/admin_engine.rb +25 -0
  111. data/lib/decidim/posts/component.rb +59 -0
  112. data/lib/decidim/posts/content_blocks/content_blocks_homepage.rb +19 -0
  113. data/lib/decidim/posts/engine.rb +84 -0
  114. data/lib/decidim/posts/test/factories.rb +14 -0
  115. data/lib/decidim/posts/version.rb +9 -0
  116. data/lib/decidim/posts.rb +13 -0
  117. metadata +183 -0
@@ -0,0 +1,116 @@
1
+ module Decidim
2
+ module Posts
3
+ class Post < Feeds::ApplicationRecord
4
+ include Decidim::Resourceable
5
+ include Decidim::Authorable
6
+ include Decidim::Reportable
7
+ include Decidim::HasAttachments
8
+ include Decidim::Comments::Commentable
9
+ include Decidim::Searchable
10
+ include Decidim::Endorsable
11
+ include Decidim::TranslatableResource
12
+ include Decidim::TranslatableAttributes
13
+ include Decidim::Fingerprintable
14
+ include Decidim::HasComponent
15
+ include Decidim::FilterableResource
16
+ include Decidim::Posts::Reactionable
17
+ # include Decidim::Loggable
18
+ # include Decidim::DownloadYourData
19
+ # include Decidim::Randomable
20
+ # include Decidim::ScopableResource
21
+ # include Decidim::HasReference
22
+ # include Decidim::HasCategory
23
+ # include Decidim::Followable
24
+ # include Decidim::Traceable
25
+ # include Decidim::NewsletterParticipant
26
+
27
+ # belongs_to :organization, class_name: "Decidim::Organization"
28
+
29
+ has_many :questions, class_name: "Decidim::Posts::Question", dependent: :destroy, foreign_key: "decidim_posts_post_id"
30
+ # accepts_nested_attributes_for :questions, reject_if: ->(attributes){ attributes['name'].blank? }, allow_destroy: true
31
+
32
+ component_manifest_name "posts"
33
+
34
+ translatable_fields :body
35
+
36
+ fingerprint fields: [:body]
37
+
38
+ validates :body, presence: true
39
+
40
+ searchable_fields(
41
+ {
42
+ participatory_space: { component: :participatory_space },
43
+ A: :body,
44
+ datetime: :created_at
45
+ },
46
+ index_on_create: true,
47
+ index_on_update: true
48
+ )
49
+
50
+ scope :filter_category, ->(category) { where(category: category) if category.present? }
51
+
52
+ # Posts don't have a title, but Commentable requires it, so let's extract the first words of each translation of the body
53
+ def title
54
+ truncated_body = {}
55
+ body.each do |locale, translations|
56
+ if locale == "machine_translations"
57
+ truncated_body[locale] = {}
58
+ translations.each do |key, value|
59
+ next if value.class != String
60
+ truncated_body[locale][key] = value.truncate_words(4)
61
+ end
62
+ else
63
+ next if translations.class != String
64
+ truncated_body[locale] = translations.truncate_words(4)
65
+ end
66
+ end
67
+ truncated_body
68
+ end
69
+
70
+ def editable_by?(user)
71
+ user == author
72
+ end
73
+
74
+ def deleteable_by?(user)
75
+ user == author || user.admin?
76
+ end
77
+
78
+ # Public: Overrides the `reported_content_url` Reportable concern method.
79
+ def reported_content_url
80
+ ResourceLocatorPresenter.new(self).url
81
+ end
82
+
83
+ # Public: Overrides the `reported_attributes` Reportable concern method.
84
+ def reported_attributes
85
+ [:body]
86
+ end
87
+
88
+ # Public: Overrides the `reported_searchable_content_extras` Reportable concern method.
89
+ def reported_searchable_content_extras
90
+ [author.name]
91
+ end
92
+
93
+ def survey_responses_count
94
+ # questions.includes(answers: :user_answers).map(&:answers).flatten.map(&:user_answers).flatten.pluck(:decidim_user_id).uniq.count
95
+ answer_ids = questions.includes(:answers).map(&:answers).flatten.pluck(:id)
96
+ @survey_responses_count ||= UserAnswer.where(decidim_posts_answer_id: answer_ids).distinct.count(:decidim_user_id)
97
+ end
98
+
99
+ # Public: Overrides the `comments_have_alignment?` Commentable concern method.
100
+ # Whether the object's comments can have alignment or not. It enables the
101
+ # alignment selector in the add new comment form.
102
+ def comments_have_alignment?
103
+ false
104
+ end
105
+
106
+ # Public: Overrides the `comments_have_votes?` Commentable concern method.
107
+ def comments_have_votes?
108
+ true
109
+ end
110
+
111
+ def users_to_notify_on_comment_created
112
+ [author]
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,17 @@
1
+ module Decidim
2
+ module Posts
3
+ class Question < Feeds::ApplicationRecord
4
+ include Decidim::TranslatableResource
5
+ include Decidim::TranslatableAttributes
6
+
7
+ belongs_to :post, class_name: "Decidim::Posts::Post", foreign_key: "decidim_posts_post_id"
8
+ has_many :answers, class_name: "Decidim::Posts::Answer", dependent: :destroy, foreign_key: "decidim_posts_question_id"
9
+ # accepts_nested_attributes_for :answers, allow_destroy: true
10
+
11
+ enum question_type: { single_choice: 0, multiple_choice: 1 }
12
+
13
+ translatable_fields :title
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Posts
5
+ class Reaction < ApplicationRecord
6
+ include Decidim::Authorable
7
+
8
+ belongs_to :resource, polymorphic: true, counter_cache: true#, touch: true
9
+ belongs_to :reaction_type, class_name: "Decidim::Posts::ReactionType"
10
+
11
+ validates :reaction_type, presence: true
12
+
13
+ def self.reaction_types
14
+ Decidim::Posts::ReactionType.all
15
+ end
16
+
17
+ def organization
18
+ resource&.component&.organization
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Posts
5
+ # A reaction type for posts.
6
+ class ReactionType < Decidim::ApplicationRecord
7
+ has_many :reactions, dependent: :destroy
8
+
9
+ validates :name, presence: true, uniqueness: true
10
+ validates :icon_name, presence: true
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module Decidim
2
+ module Posts
3
+ class UserAnswer < Feeds::ApplicationRecord
4
+ belongs_to :decidim_posts_answer, class_name: 'Decidim::Posts::Answer', foreign_key: "decidim_posts_answer_id"
5
+ belongs_to :decidim_user, class_name: 'Decidim::User', foreign_key: "decidim_user_id"
6
+
7
+ # validate combination of user and answer
8
+ validates :decidim_user_id, uniqueness: { scope: :decidim_posts_answer_id }
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ import 'src/decidim/posts/posts.js';
2
+
3
+ require.context('../images', true);
4
+
5
+ import 'entrypoints/decidim_posts.scss';
@@ -0,0 +1 @@
1
+ @import 'stylesheets/decidim/posts/posts';
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 35 35"><path d="M17.5 35A17.5 17.5 0 1 1 35 17.5 17.52 17.52 0 0 1 17.5 35zm0-33.06A15.56 15.56 0 1 0 33.06 17.5 15.57 15.57 0 0 0 17.5 1.94zm9.5 13.7H8a1 1 0 0 1 0-1.94h19a1 1 0 0 1 0 1.94zm0 3.68H8a1 1 0 0 1 0-1.94h19a1 1 0 0 1 0 1.94zM22.26 23H8a1 1 0 0 1 0-1.94h14.26a1 1 0 0 1 0 1.94z"/></svg>
@@ -0,0 +1,112 @@
1
+ const carousel = (() => {
2
+ let startX;
3
+
4
+ const setActiveItem = (galleryId, index, direction = null) => {
5
+ const galleryItems = document.querySelectorAll(`#${galleryId} li`);
6
+ const navDots = document.querySelectorAll(
7
+ `.posts__post_gallery_nav_dot[data-target="${galleryId}"]`
8
+ );
9
+ let activeIndex = index;
10
+
11
+ if (direction) {
12
+ const currentIndex = Array.from(galleryItems).findIndex((item) =>
13
+ item.classList.contains('active')
14
+ );
15
+
16
+ if (direction === 'left' && currentIndex < galleryItems.length - 1) {
17
+ activeIndex = currentIndex + 1;
18
+ } else if (direction === 'right' && currentIndex > 0) {
19
+ activeIndex = currentIndex - 1;
20
+ }
21
+ }
22
+
23
+ galleryItems.forEach((item, idx) => {
24
+ if (idx === activeIndex) {
25
+ item.classList.add('active');
26
+ } else {
27
+ item.classList.remove('active');
28
+ }
29
+ });
30
+
31
+ navDots.forEach((dot, idx) => {
32
+ const innerSpan = dot.querySelector('span');
33
+ if (innerSpan) {
34
+ if (idx === activeIndex) {
35
+ innerSpan.classList.add('bg-feeds-notification');
36
+ } else {
37
+ innerSpan.classList.remove('bg-feeds-notification');
38
+ }
39
+ }
40
+ });
41
+
42
+ // Show only the first 8 dots and update the visible range as the user navigates
43
+ const visibleRange = 8;
44
+ let start = 0;
45
+ let end = visibleRange;
46
+
47
+ if (activeIndex >= end - 1) {
48
+ start = activeIndex - visibleRange + 2;
49
+ end = activeIndex + 2;
50
+ }
51
+
52
+ start = Math.max(0, start);
53
+ end = Math.min(navDots.length, end);
54
+
55
+ navDots.forEach((dot, idx) => {
56
+ if (idx >= start && idx < end) {
57
+ dot.style.display = 'flex';
58
+ } else {
59
+ dot.style.display = 'none';
60
+ }
61
+ });
62
+ };
63
+
64
+ const attachSwipeListeners = (galleryId) => {
65
+ const gallery = document.getElementById(galleryId);
66
+
67
+ gallery.addEventListener('touchstart', (e) => {
68
+ startX = e.touches[0].clientX;
69
+ });
70
+
71
+ gallery.addEventListener('touchend', (e) => {
72
+ const endX = e.changedTouches[0].clientX;
73
+ const galleryItems = document.querySelectorAll(`#${galleryId} li`);
74
+ const currentIndex = Array.from(galleryItems).findIndex((item) =>
75
+ item.classList.contains('active')
76
+ );
77
+
78
+ if (startX - endX > 50 && currentIndex < galleryItems.length - 1) {
79
+ setActiveItem(galleryId, null, 'left');
80
+ } else if (startX - endX < -50 && currentIndex > 0) {
81
+ setActiveItem(galleryId, null, 'right');
82
+ }
83
+ });
84
+ };
85
+
86
+ const attachEventListenersToDots = () => {
87
+ document.querySelectorAll('.posts__post_gallery_nav_dot').forEach((dot) => {
88
+ dot.addEventListener('click', function () {
89
+ const targetGalleryId = this.getAttribute('data-target');
90
+ const targetIndex = parseInt(this.getAttribute('data-index'), 10);
91
+ setActiveItem(targetGalleryId, targetIndex);
92
+ });
93
+ });
94
+ };
95
+
96
+ const init = () => {
97
+ attachEventListenersToDots();
98
+ // Initialize swipe listeners for each gallery
99
+ document.querySelectorAll('.posts__post_gallery').forEach((gallery) => {
100
+ attachSwipeListeners(gallery.id);
101
+ });
102
+ // Initialize the visible dots for each gallery
103
+ document.querySelectorAll('.posts__post_gallery_nav_dot').forEach((dot) => {
104
+ const targetGalleryId = dot.getAttribute('data-target');
105
+ setActiveItem(targetGalleryId, 0);
106
+ });
107
+ };
108
+
109
+ return { init };
110
+ })();
111
+
112
+ export default carousel;
@@ -0,0 +1,75 @@
1
+ export function host_status() {
2
+ const changeStatusButtons = document.querySelectorAll('.changeStatusButton');
3
+
4
+ changeStatusButtons.forEach(function (button) {
5
+ button.addEventListener('click', handleStatusChange);
6
+ });
7
+
8
+ const cancelButton = document.getElementById(
9
+ 'confirmationModal__cancelButton'
10
+ );
11
+ cancelButton.addEventListener('click', function () {
12
+ const confirmationModal = document.getElementById('confirmationModal');
13
+ confirmationModal.close();
14
+ });
15
+
16
+ function handleStatusChange(event) {
17
+ const button = event.currentTarget;
18
+ const postId = button.dataset.postId;
19
+ const newStatus = button.dataset.postStatus;
20
+ const confirmationModalMsg = button.dataset.dialogmsg;
21
+
22
+ const confirmationModal = document.getElementById('confirmationModal');
23
+ const confirmButton = document.getElementById(
24
+ 'confirmationModal__confirmButton'
25
+ );
26
+ const confirmButtons = confirmationModal.querySelector(
27
+ '.confirmationModal__buttons'
28
+ );
29
+ const confirmationModalResponse = confirmationModal.querySelector(
30
+ '.confirmationModal__response'
31
+ );
32
+
33
+ confirmationModalResponse.innerHTML = confirmationModalMsg;
34
+ confirmationModal.showModal();
35
+
36
+ const confirmClickHandler = function () {
37
+ confirmButtons.style.display = 'none';
38
+ confirmationModalResponse.innerHTML =
39
+ window.translations.dialog.dialogBodyResponse;
40
+ const params = new URLSearchParams({
41
+ id: postId,
42
+ status: newStatus,
43
+ });
44
+ Rails.ajax({
45
+ url: 'change_status/?' + params.toString(),
46
+ type: 'GET',
47
+ success: function (response) {
48
+ confirmationModal.close();
49
+ confirmButtons.style.display = 'flex';
50
+ confirmationModalResponse.innerText =
51
+ window.translations.dialog.dialogBodyMsg;
52
+
53
+ const postElement = document.getElementById(`feeds_post-${postId}`);
54
+ postElement.innerHTML = 'updating status...';
55
+ postElement.innerHTML = response.new_content;
56
+
57
+ const updatedButtons = postElement.querySelectorAll(
58
+ '.changeStatusButton'
59
+ );
60
+ updatedButtons.forEach(function (updatedButton) {
61
+ updatedButton.addEventListener('click', handleStatusChange);
62
+ });
63
+ },
64
+ error: function (error) {
65
+ console.error('Error changing status:', error);
66
+ },
67
+ });
68
+
69
+ confirmButton.removeEventListener('click', confirmClickHandler);
70
+ };
71
+
72
+ confirmButton.removeEventListener('click', confirmClickHandler);
73
+ confirmButton.addEventListener('click', confirmClickHandler);
74
+ }
75
+ }
@@ -0,0 +1,98 @@
1
+ const newFeed = document.getElementById('posts__post_newElement');
2
+ const newFeedOpener = document.querySelectorAll(
3
+ '.posts__post_newElement-opener'
4
+ );
5
+ const newFeedCloser = newFeed.querySelector('.posts__post_newElement-closer');
6
+ let lastFocusedButton = null;
7
+
8
+ newFeedOpener.forEach(function (opener) {
9
+ opener.addEventListener('click', function () {
10
+ let isExpanded = opener.getAttribute('aria-expanded') === 'true';
11
+ opener.setAttribute('aria-expanded', !isExpanded);
12
+ const activeFilter = newFeed.getAttribute('data-active-filter');
13
+ const buttonToActivate = activeFilter
14
+ ? Array.from(categoryButtons).find(
15
+ (button) => button.getAttribute('data-category') === activeFilter
16
+ )
17
+ : categoryButtons[0];
18
+ activateCategory(buttonToActivate || categoryButtons[0]);
19
+ newFeed.classList.toggle('open');
20
+ lastFocusedButton = this;
21
+ document.getElementById('post_body').focus();
22
+ document.body.style.overflow = 'hidden';
23
+ });
24
+ });
25
+
26
+ newFeed.addEventListener('click', function (event) {
27
+ if (event.target === newFeed) {
28
+ closeDialog();
29
+ }
30
+ });
31
+
32
+ newFeedCloser.addEventListener('click', closeDialog);
33
+
34
+ document.addEventListener('keydown', function (event) {
35
+ if (event.key === 'Escape') {
36
+ closeDialog();
37
+ }
38
+ });
39
+
40
+ const categoryButtons = document.querySelectorAll('.category-selection button');
41
+ const meetingForm = document.querySelector('.meetings_form');
42
+ const postForm = document.querySelector('.posts_form');
43
+ const surveyDiv = document.getElementById('extraFieldsForSurvey');
44
+ const newFeedLiveRegion = document.getElementById(
45
+ 'posts__post_newElement_Form-LiveRegion'
46
+ );
47
+
48
+ categoryButtons.forEach((button) => {
49
+ button.addEventListener('click', function () {
50
+ activateCategory(this);
51
+ });
52
+ });
53
+
54
+ function hideAllForms() {
55
+ meetingForm.classList.remove('open');
56
+ postForm.classList.remove('open');
57
+ surveyDiv.classList.remove('open');
58
+ newFeedLiveRegion.innerHTML = '';
59
+ categoryButtons.forEach(function (button) {
60
+ button.classList.remove('active');
61
+ button.setAttribute('aria-pressed', 'false');
62
+ });
63
+ }
64
+
65
+ function closeDialog() {
66
+ newFeedOpener.forEach(function (opener) {
67
+ opener.setAttribute('aria-expanded', 'false');
68
+ newFeed.classList.remove('open');
69
+ lastFocusedButton.focus();
70
+ document.body.style.overflow = 'auto';
71
+ });
72
+ }
73
+
74
+ function activateCategory(button) {
75
+ hideAllForms();
76
+ button.classList.add('active');
77
+ button.setAttribute('aria-pressed', 'true');
78
+ const category = button.getAttribute('data-category');
79
+ newFeedLiveRegion.innerHTML = window.translations.newFeedLiveRegion[category];
80
+
81
+ const postBody = document.getElementById('post_body');
82
+ const meetingTitle = document.getElementById('meeting_title');
83
+ if (category === 'calendar') {
84
+ meetingForm.classList.add('open');
85
+ meetingForm.querySelector('.form-error').classList.remove('is-visible');
86
+ meetingTitle.classList.remove('is-invalid-input');
87
+ document.getElementById('meeting_title').focus();
88
+ } else {
89
+ postForm.classList.add('open');
90
+ postForm.querySelector('.form-error').classList.remove('is-visible');
91
+ postBody.classList.remove('is-invalid-input');
92
+ postBody.focus();
93
+ document.getElementById('post_category').value = category;
94
+ if (category === 'survey') surveyDiv.classList.add('open');
95
+ }
96
+ }
97
+
98
+ export { closeDialog, activateCategory, hideAllForms };