decidim-core 0.29.1 → 0.30.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (517) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/activity_cell.rb +0 -3
  3. data/app/cells/decidim/amendable/amend_button_card/show.erb +6 -4
  4. data/app/cells/decidim/amendable/amend_button_card_cell.rb +8 -0
  5. data/app/cells/decidim/amendable/amendments/show.erb +1 -1
  6. data/app/cells/decidim/amendable/promote_button_card/show.erb +2 -0
  7. data/app/cells/decidim/author/show.erb +5 -4
  8. data/app/cells/decidim/author_cell.rb +27 -1
  9. data/app/cells/decidim/card_l/extra_data.erb +1 -0
  10. data/app/cells/decidim/card_metadata_cell.rb +9 -16
  11. data/app/cells/decidim/card_s/show.erb +5 -3
  12. data/app/cells/decidim/comments_button_cell.rb +14 -2
  13. data/app/cells/decidim/content_blocks/highlighted_elements_cell.rb +2 -0
  14. data/app/cells/decidim/content_blocks/highlighted_elements_with_cell_for_list_cell.rb +1 -1
  15. data/app/cells/decidim/diff_cell.rb +4 -0
  16. data/app/cells/decidim/endorsement_block/show.erb +0 -1
  17. data/app/cells/decidim/endorsement_block_cell.rb +6 -0
  18. data/app/cells/decidim/endorsement_buttons/button_content.erb +1 -1
  19. data/app/cells/decidim/endorsement_buttons/select_identity_button.erb +1 -1
  20. data/app/cells/decidim/endorsement_buttons/show.erb +7 -7
  21. data/app/cells/decidim/endorsement_buttons/verification_modal.erb +4 -2
  22. data/app/cells/decidim/endorsers_list/empty.erb +3 -0
  23. data/app/cells/decidim/endorsers_list/full.erb +17 -5
  24. data/app/cells/decidim/endorsers_list/show.erb +19 -10
  25. data/app/cells/decidim/endorsers_list_cell.rb +19 -6
  26. data/app/cells/decidim/follow_button/show.erb +1 -2
  27. data/app/cells/decidim/follow_button_cell.rb +5 -0
  28. data/app/cells/decidim/map/show.erb +3 -0
  29. data/app/cells/decidim/map/template.erb +14 -0
  30. data/app/cells/decidim/map_cell.rb +39 -0
  31. data/app/cells/decidim/newsletter_templates/image_text_cta_cell.rb +1 -1
  32. data/app/cells/decidim/notification_actions/buttons_cell.rb +1 -1
  33. data/app/cells/decidim/onboarding_action_message/show.erb +15 -0
  34. data/app/cells/decidim/onboarding_action_message_cell.rb +81 -0
  35. data/app/cells/decidim/participatory_space_private_user/show.erb +23 -0
  36. data/app/cells/decidim/participatory_space_private_user_cell.rb +21 -0
  37. data/app/cells/decidim/progress_bar/show.erb +2 -2
  38. data/app/cells/decidim/report_button_cell.rb +1 -0
  39. data/app/cells/decidim/resource_history/show.erb +20 -0
  40. data/app/cells/decidim/resource_history_cell.rb +66 -0
  41. data/app/cells/decidim/share_button_cell.rb +0 -4
  42. data/app/cells/decidim/share_widget/modal.erb +26 -0
  43. data/app/cells/decidim/share_widget/show.erb +2 -0
  44. data/app/cells/decidim/share_widget_cell.rb +20 -0
  45. data/app/cells/decidim/tags/show.erb +7 -4
  46. data/app/cells/decidim/tags_cell.rb +11 -72
  47. data/app/cells/decidim/translation_bar/show.erb +2 -2
  48. data/app/cells/decidim/translation_bar_cell.rb +1 -1
  49. data/app/commands/decidim/amendable/create_draft.rb +2 -2
  50. data/app/commands/decidim/create_ephemeral_user.rb +52 -0
  51. data/app/commands/decidim/create_omniauth_registration.rb +13 -3
  52. data/app/commands/decidim/create_report.rb +1 -5
  53. data/app/commands/decidim/create_user_group.rb +6 -2
  54. data/app/commands/decidim/destroy_account.rb +3 -0
  55. data/app/commands/decidim/destroy_ephemeral_user.rb +47 -0
  56. data/app/commands/decidim/update_account.rb +11 -3
  57. data/app/commands/decidim/update_notifications_settings.rb +1 -0
  58. data/app/commands/decidim/update_resources_taxonomies.rb +67 -0
  59. data/app/commands/decidim/update_user_group.rb +7 -1
  60. data/app/constraints/decidim/current_component.rb +1 -1
  61. data/app/controllers/concerns/decidim/ajax_permission_handler.rb +21 -0
  62. data/app/controllers/concerns/decidim/devise_authentication_methods.rb +3 -6
  63. data/app/controllers/concerns/decidim/devise_controllers.rb +2 -0
  64. data/app/controllers/concerns/decidim/disable_redirection_to_external_host.rb +1 -1
  65. data/app/controllers/concerns/decidim/ephemeral_session_checker.rb +87 -0
  66. data/app/controllers/concerns/decidim/filter_resource.rb +4 -2
  67. data/app/controllers/concerns/decidim/has_members_page.rb +25 -0
  68. data/app/controllers/concerns/decidim/headers/browser_feature_permissions.rb +50 -0
  69. data/app/controllers/concerns/decidim/locale_switcher.rb +2 -2
  70. data/app/controllers/concerns/decidim/needs_password_change.rb +0 -1
  71. data/app/controllers/concerns/decidim/needs_permission.rb +2 -1
  72. data/app/controllers/concerns/decidim/needs_tos_accepted.rb +4 -5
  73. data/app/controllers/concerns/decidim/onboarding_action_methods.rb +52 -0
  74. data/app/controllers/decidim/application_controller.rb +10 -0
  75. data/app/controllers/decidim/authorization_modals_controller.rb +8 -2
  76. data/app/controllers/decidim/components/base_controller.rb +3 -7
  77. data/app/controllers/decidim/devise/confirmations_controller.rb +4 -0
  78. data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +8 -1
  79. data/app/controllers/decidim/devise/registrations_controller.rb +1 -1
  80. data/app/controllers/decidim/devise/sessions_controller.rb +2 -0
  81. data/app/controllers/decidim/doorkeeper/credentials_controller.rb +1 -1
  82. data/app/controllers/decidim/download_your_data_controller.rb +33 -2
  83. data/app/controllers/decidim/editor_images_controller.rb +1 -11
  84. data/app/controllers/decidim/follows_controller.rb +1 -1
  85. data/app/controllers/decidim/geolocation_controller.rb +19 -0
  86. data/app/controllers/decidim/homepage_controller.rb +0 -1
  87. data/app/controllers/decidim/links_controller.rb +1 -1
  88. data/app/controllers/decidim/open_data_controller.rb +33 -8
  89. data/app/controllers/decidim/profiles_controller.rb +4 -0
  90. data/app/controllers/decidim/user_conversations_controller.rb +1 -11
  91. data/app/events/decidim/soft_delete_resource_event.rb +15 -0
  92. data/app/forms/decidim/amendable/form.rb +4 -2
  93. data/app/forms/decidim/ephemeral_user_form.rb +22 -0
  94. data/app/forms/decidim/notifications_settings_form.rb +1 -0
  95. data/app/forms/decidim/omniauth_registration_form.rb +14 -1
  96. data/app/helpers/concerns/decidim/flash_helper_extensions.rb +17 -2
  97. data/app/helpers/concerns/decidim/user_role_checker.rb +46 -0
  98. data/app/helpers/decidim/action_authorization_helper.rb +75 -14
  99. data/app/helpers/decidim/amendments_helper.rb +0 -9
  100. data/app/helpers/decidim/application_helper.rb +6 -2
  101. data/app/helpers/decidim/breadcrumb_helper.rb +6 -0
  102. data/app/helpers/decidim/cache_helper.rb +1 -1
  103. data/app/helpers/decidim/check_boxes_tree_helper.rb +25 -53
  104. data/app/helpers/decidim/cta_button_helper.rb +1 -1
  105. data/app/helpers/decidim/decidim_form_helper.rb +0 -44
  106. data/app/helpers/decidim/endorsable_helper.rb +0 -10
  107. data/app/helpers/decidim/layout_helper.rb +6 -0
  108. data/app/helpers/decidim/map_helper.rb +6 -1
  109. data/app/helpers/decidim/messaging/conversation_helper.rb +2 -3
  110. data/app/helpers/decidim/meta_tags_helper.rb +32 -23
  111. data/app/helpers/decidim/modal_helper.rb +23 -0
  112. data/app/helpers/decidim/omniauth_helper.rb +5 -5
  113. data/app/helpers/decidim/onboarding_action_helper.rb +13 -0
  114. data/app/helpers/decidim/passwords_helper.rb +2 -2
  115. data/app/helpers/decidim/sanitize_helper.rb +11 -2
  116. data/app/helpers/decidim/taxonomies_helper.rb +40 -0
  117. data/app/jobs/decidim/download_your_data_export_job.rb +2 -19
  118. data/app/jobs/decidim/event_publisher_job.rb +18 -9
  119. data/app/jobs/decidim/export_job.rb +5 -1
  120. data/app/jobs/decidim/export_participatory_space_job.rb +4 -1
  121. data/app/jobs/decidim/open_data_job.rb +4 -4
  122. data/app/mailers/decidim/export_mailer.rb +7 -12
  123. data/app/models/decidim/action_log.rb +11 -0
  124. data/app/models/decidim/attachment.rb +1 -1
  125. data/app/models/decidim/category.rb +4 -0
  126. data/app/models/decidim/component.rb +25 -3
  127. data/app/models/decidim/metric.rb +2 -1
  128. data/app/models/decidim/moderation.rb +16 -0
  129. data/app/models/decidim/newsletter.rb +12 -8
  130. data/app/models/decidim/organization.rb +7 -3
  131. data/app/models/decidim/participatory_space_private_user.rb +20 -0
  132. data/app/models/decidim/private_export.rb +24 -0
  133. data/app/models/decidim/push_notification_message.rb +1 -1
  134. data/app/models/decidim/scope.rb +4 -0
  135. data/app/models/decidim/share_token.rb +36 -10
  136. data/app/models/decidim/taxonomization.rb +23 -0
  137. data/app/models/decidim/taxonomy.rb +139 -0
  138. data/app/models/decidim/taxonomy_filter.rb +130 -0
  139. data/app/models/decidim/taxonomy_filter_item.rb +33 -0
  140. data/app/models/decidim/user.rb +9 -23
  141. data/app/models/decidim/user_base_entity.rb +12 -0
  142. data/app/models/decidim/user_moderation.rb +9 -0
  143. data/app/models/decidim/user_report.rb +4 -0
  144. data/app/packs/entrypoints/decidim_core.js +1 -0
  145. data/app/packs/entrypoints/decidim_geocoding.js +2 -0
  146. data/app/packs/images/decidim/brands/facebook.svg +10 -0
  147. data/app/packs/images/decidim/brands/google.svg +7 -1
  148. data/app/packs/images/decidim/brands/twitter-x.svg +3 -0
  149. data/app/packs/src/decidim/append_redirect_url_to_modals.js +14 -6
  150. data/app/packs/src/decidim/check_boxes_tree.js +0 -1
  151. data/app/packs/src/decidim/clipboard.js +18 -9
  152. data/app/packs/src/decidim/confirm.js +79 -59
  153. data/app/packs/src/decidim/decidim_application.js +1 -0
  154. data/app/packs/src/decidim/direct_uploads/upload_field.js +21 -8
  155. data/app/packs/src/decidim/form_remote.js +1 -1
  156. data/app/packs/src/decidim/geocoding/reverse_geocoding.js +60 -0
  157. data/app/packs/src/decidim/impersonation.js +1 -1
  158. data/app/packs/src/decidim/index.js +14 -1
  159. data/app/packs/src/decidim/onboarding_pending_action.js +24 -0
  160. data/app/packs/src/decidim/remote_tooltips.js +38 -0
  161. data/app/packs/src/decidim/session_timeouter.js +1 -1
  162. data/app/packs/src/decidim/sticky_footer.js +29 -0
  163. data/app/packs/src/decidim/sticky_header.js +6 -31
  164. data/app/packs/src/decidim/toggle.js +1 -1
  165. data/app/packs/src/decidim/tooltips.js +42 -22
  166. data/app/packs/src/decidim/user_registrations.js +13 -0
  167. data/app/packs/src/decidim/utilities/dom.js +148 -0
  168. data/app/packs/stylesheets/decidim/_accordion.scss +30 -0
  169. data/app/packs/stylesheets/decidim/_buttons.scss +19 -0
  170. data/app/packs/stylesheets/decidim/_dropdown.scss +1 -1
  171. data/app/packs/stylesheets/decidim/_endorsers_list.scss +26 -20
  172. data/app/packs/stylesheets/decidim/_forms.scss +2 -2
  173. data/app/packs/stylesheets/decidim/_header.scss +5 -3
  174. data/app/packs/stylesheets/decidim/_labels.scss +1 -1
  175. data/app/packs/stylesheets/decidim/_layout.scss +32 -2
  176. data/app/packs/stylesheets/decidim/_login.scss +53 -6
  177. data/app/packs/stylesheets/decidim/_modal.scss +42 -0
  178. data/app/packs/stylesheets/decidim/_modal_tos_refuse.scss +4 -0
  179. data/app/packs/stylesheets/decidim/_participatory_spaces.scss +46 -0
  180. data/app/packs/stylesheets/decidim/_profile.scss +2 -2
  181. data/app/packs/stylesheets/decidim/_progress-bar.scss +1 -1
  182. data/app/packs/stylesheets/decidim/_success_image.scss +64 -0
  183. data/app/packs/stylesheets/decidim/_tribute.scss +36 -0
  184. data/app/packs/stylesheets/decidim/application.scss +1 -0
  185. data/app/packs/stylesheets/decidim/geocoding_addons.scss +5 -0
  186. data/app/packs/stylesheets/decidim/legacy/conference-diploma.scss +2 -1
  187. data/app/packs/stylesheets/decidim/map.scss +7 -10
  188. data/app/packs/stylesheets/decidim/resource_history.scss +31 -0
  189. data/app/permissions/decidim/permissions.rb +8 -2
  190. data/app/presenters/decidim/admin_log/base_user_presenter.rb +67 -0
  191. data/app/presenters/decidim/admin_log/component_presenter.rb +32 -3
  192. data/app/presenters/decidim/admin_log/moderation_presenter.rb +30 -3
  193. data/app/presenters/decidim/admin_log/share_token_presenter.rb +39 -0
  194. data/app/presenters/decidim/admin_log/taxonomy_filter_presenter.rb +57 -0
  195. data/app/presenters/decidim/admin_log/taxonomy_presenter.rb +48 -0
  196. data/app/presenters/decidim/admin_log/user_group_presenter.rb +6 -6
  197. data/app/presenters/decidim/admin_log/user_presenter.rb +4 -18
  198. data/app/presenters/decidim/attachment_presenter.rb +1 -1
  199. data/app/presenters/decidim/log/value_types/date_presenter.rb +1 -0
  200. data/app/presenters/decidim/log/value_types/taxonomy_presenter.rb +29 -0
  201. data/app/presenters/decidim/participatory_space_private_user_presenter.rb +50 -0
  202. data/app/presenters/decidim/taxonomy_filter_presenter.rb +19 -0
  203. data/app/presenters/decidim/taxonomy_presenter.rb +14 -0
  204. data/app/queries/decidim/metrics/blocked_users_metric_manage.rb +2 -2
  205. data/app/queries/decidim/metrics/users_metric_manage.rb +2 -2
  206. data/app/queries/decidim/public_activities.rb +1 -12
  207. data/app/queries/decidim/stats_users_count.rb +2 -2
  208. data/app/resolvers/decidim/meta_image_url_resolver.rb +128 -0
  209. data/app/serializers/decidim/exporters/open_data_blocked_user_serializer.rb +25 -0
  210. data/app/serializers/decidim/exporters/open_data_metric_serializer.rb +22 -0
  211. data/app/serializers/decidim/exporters/open_data_moderation_serializer.rb +30 -0
  212. data/app/serializers/decidim/exporters/open_data_taxonomy_serializer.rb +30 -0
  213. data/app/serializers/decidim/exporters/open_data_user_group_serializer.rb +38 -0
  214. data/app/serializers/decidim/exporters/open_data_user_serializer.rb +39 -0
  215. data/app/serializers/decidim/exporters/participatory_space_serializer.rb +104 -0
  216. data/app/serializers/decidim/exporters/serializer.rb +25 -0
  217. data/app/serializers/decidim/schema_org_breadcrumb_list_serializer.rb +52 -0
  218. data/app/services/decidim/action_authorizer.rb +32 -3
  219. data/app/services/decidim/base_diff_renderer.rb +27 -3
  220. data/app/services/decidim/download_your_data_exporter.rb +58 -24
  221. data/app/services/decidim/email_notification_generator.rb +14 -5
  222. data/app/services/decidim/onboarding_manager.rb +272 -0
  223. data/app/services/decidim/open_data_exporter.rb +139 -13
  224. data/app/services/decidim/traceability.rb +13 -0
  225. data/app/uploaders/decidim/application_uploader.rb +1 -1
  226. data/app/validators/etiquette_validator.rb +9 -2
  227. data/app/validators/passthru_validator.rb +1 -1
  228. data/app/validators/translated_etiquette_validator.rb +32 -0
  229. data/app/views/decidim/account/_password_fields.html.erb +2 -2
  230. data/app/views/decidim/application/_accordion_section.html.erb +14 -0
  231. data/app/views/decidim/application/_collection.html.erb +30 -18
  232. data/app/views/decidim/devise/omniauth_registrations/new.html.erb +5 -1
  233. data/app/views/decidim/devise/omniauth_registrations/new_tos_fields.html.erb +29 -0
  234. data/app/views/decidim/devise/registrations/new.html.erb +10 -22
  235. data/app/views/decidim/devise/sessions/new.html.erb +24 -29
  236. data/app/views/decidim/devise/shared/_omniauth_buttons.html.erb +2 -4
  237. data/app/views/decidim/devise/shared/_tos_fields.html.erb +16 -0
  238. data/app/views/decidim/download_your_data/_export.html.erb +15 -0
  239. data/app/views/decidim/download_your_data/show.html.erb +51 -5
  240. data/app/views/decidim/endorsements/update_buttons_and_counters.js.erb +16 -19
  241. data/app/views/decidim/export_mailer/download_your_data_export.html.erb +2 -2
  242. data/app/views/decidim/export_mailer/export.html.erb +5 -1
  243. data/app/views/decidim/notifications_settings/show.html.erb +22 -0
  244. data/app/views/decidim/open_data/_how_to_open_accordion_section.html.erb +15 -0
  245. data/app/views/decidim/open_data/index.html.erb +108 -0
  246. data/app/views/decidim/pages/_tabbed.html.erb +2 -2
  247. data/app/views/decidim/pages/show.html.erb +2 -1
  248. data/app/views/decidim/participatory_space_private_users/_participatory_space_private_user.html.erb +1 -0
  249. data/app/views/decidim/shared/_login_modal.html.erb +26 -20
  250. data/app/views/decidim/shared/_resource_actions.html.erb +21 -0
  251. data/app/views/decidim/shared/filters/_check_boxes_tree.html.erb +1 -2
  252. data/app/views/decidim/shared/filters/_collection.html.erb +1 -1
  253. data/app/views/decidim/shared/filters/_dropdown_label.html.erb +7 -4
  254. data/app/views/layouts/decidim/_application.html.erb +0 -1
  255. data/app/views/layouts/decidim/_js_configuration.html.erb +1 -0
  256. data/app/views/layouts/decidim/_logo.html.erb +1 -1
  257. data/app/views/layouts/decidim/_logo_mobile.html.erb +1 -1
  258. data/app/views/layouts/decidim/_meta_tags_config.html.erb +6 -11
  259. data/app/views/layouts/decidim/_schema_org_breadcrumb_list.html.erb +3 -0
  260. data/app/views/layouts/decidim/_wrapper.html.erb +15 -9
  261. data/app/views/layouts/decidim/footer/_main_links.html.erb +1 -1
  262. data/app/views/layouts/decidim/header/_close_ephemeral_session.html.erb +25 -0
  263. data/app/views/layouts/decidim/header/_main.html.erb +14 -10
  264. data/app/views/layouts/decidim/header/_menu_breadcrumb_items.html.erb +2 -0
  265. data/app/views/layouts/decidim/header/_menu_breadcrumb_mobile_tablet.html.erb +1 -1
  266. data/app/views/layouts/decidim/shared/_layout_item.html.erb +1 -1
  267. data/config/assets.rb +2 -1
  268. data/config/locales/ar.yml +38 -54
  269. data/config/locales/bg.yml +3 -64
  270. data/config/locales/bn-BD.yml +1 -0
  271. data/config/locales/bs-BA.yml +98 -0
  272. data/config/locales/ca.yml +380 -69
  273. data/config/locales/cs.yml +369 -55
  274. data/config/locales/de.yml +371 -67
  275. data/config/locales/el.yml +5 -45
  276. data/config/locales/en.yml +365 -54
  277. data/config/locales/eo.yml +0 -2
  278. data/config/locales/es-MX.yml +366 -58
  279. data/config/locales/es-PY.yml +366 -58
  280. data/config/locales/es.yml +375 -64
  281. data/config/locales/eu.yml +547 -223
  282. data/config/locales/fi-plain.yml +361 -57
  283. data/config/locales/fi.yml +400 -93
  284. data/config/locales/fr-CA.yml +181 -55
  285. data/config/locales/fr.yml +182 -53
  286. data/config/locales/ga-IE.yml +4 -16
  287. data/config/locales/gl.yml +5 -30
  288. data/config/locales/hu.yml +3 -55
  289. data/config/locales/id-ID.yml +5 -30
  290. data/config/locales/is-IS.yml +4 -13
  291. data/config/locales/it.yml +10 -46
  292. data/config/locales/ja.yml +230 -69
  293. data/config/locales/lb.yml +5 -47
  294. data/config/locales/lt.yml +5 -59
  295. data/config/locales/lv.yml +5 -36
  296. data/config/locales/nl.yml +5 -48
  297. data/config/locales/no.yml +6 -47
  298. data/config/locales/pl.yml +4 -66
  299. data/config/locales/pt-BR.yml +12 -52
  300. data/config/locales/pt.yml +11 -47
  301. data/config/locales/ro-RO.yml +448 -247
  302. data/config/locales/ru.yml +4 -16
  303. data/config/locales/sk.yml +5 -37
  304. data/config/locales/sv.yml +108 -64
  305. data/config/locales/tr-TR.yml +5 -45
  306. data/config/locales/uk.yml +4 -15
  307. data/config/locales/zh-CN.yml +5 -45
  308. data/config/locales/zh-TW.yml +5 -50
  309. data/config/routes.rb +5 -10
  310. data/db/migrate/20181025082245_add_timestamps_to_components.rb +2 -0
  311. data/db/migrate/20240628111905_add_visible_to_components.rb +7 -0
  312. data/db/migrate/20240704115429_create_decidim_taxonomies.rb +23 -0
  313. data/db/migrate/20240717093514_add_registered_only_to_decidim_share_tokens.rb +7 -0
  314. data/db/migrate/20240722215500_change_object_changes_on_versions.rb +39 -0
  315. data/db/migrate/20240806065417_create_decidim_taxonomy_filters.rb +23 -0
  316. data/db/migrate/20240822161348_add_deleted_at_to_decidim_components.rb +8 -0
  317. data/db/migrate/20240906162524_add_part_of_to_taxonomies.rb +26 -0
  318. data/db/migrate/20241001135825_add_role_to_participatory_space_private_users.rb +7 -0
  319. data/db/migrate/20241001140408_add_published_to_participatory_space_private_users.rb +7 -0
  320. data/db/migrate/20241022002600_create_private_exports.rb +18 -0
  321. data/db/migrate/20241028114430_add_component_counter_to_taxonomy_filters.rb +7 -0
  322. data/db/migrate/20241111104357_add_names_and_space_boolean_to_taxonomy_filters.rb +9 -0
  323. data/db/migrate/20241127093708_add_taxonomy_to_metrics.rb +7 -0
  324. data/db/migrate/20241204121445_add_participatory_space_manifests_from_taxonomy_filters.rb +9 -0
  325. data/decidim-core.gemspec +18 -18
  326. data/lib/decidim/action_authorization.rb +3 -2
  327. data/lib/decidim/amendable.rb +1 -1
  328. data/lib/decidim/api/functions/component_list.rb +1 -1
  329. data/lib/decidim/api/functions/participatory_space_finder_base.rb +11 -1
  330. data/lib/decidim/api/input_filters/category_input_filter.rb +5 -3
  331. data/lib/decidim/api/input_filters/component_input_filter.rb +33 -20
  332. data/lib/decidim/api/input_filters/user_entity_input_filter.rb +53 -44
  333. data/lib/decidim/api/input_sorts/component_input_sort.rb +15 -13
  334. data/lib/decidim/api/input_sorts/user_entity_input_sort.rb +4 -4
  335. data/lib/decidim/api/interfaces/author_interface.rb +3 -2
  336. data/lib/decidim/api/interfaces/coauthorable_interface.rb +5 -5
  337. data/lib/decidim/api/interfaces/endorsable_interface.rb +2 -2
  338. data/lib/decidim/api/interfaces/participatory_space_interface.rb +5 -10
  339. data/lib/decidim/api/interfaces/taxonomizable_interface.rb +13 -0
  340. data/lib/decidim/api/types/amendment_type.rb +5 -7
  341. data/lib/decidim/api/types/area_api_type.rb +3 -3
  342. data/lib/decidim/api/types/attachment_type.rb +3 -3
  343. data/lib/decidim/api/types/category_type.rb +2 -2
  344. data/lib/decidim/api/types/component_type.rb +7 -0
  345. data/lib/decidim/api/types/decidim_type.rb +5 -1
  346. data/lib/decidim/api/types/fingerprint_type.rb +1 -1
  347. data/lib/decidim/api/types/localized_string_type.rb +1 -1
  348. data/lib/decidim/api/types/metric_history_type.rb +2 -0
  349. data/lib/decidim/api/types/metric_type.rb +1 -1
  350. data/lib/decidim/api/types/organization_type.rb +5 -0
  351. data/lib/decidim/api/types/participatory_space_link_type.rb +2 -2
  352. data/lib/decidim/api/types/participatory_space_manifest_type.rb +1 -1
  353. data/lib/decidim/api/types/quantifiable_translated_field_type.rb +1 -1
  354. data/lib/decidim/api/types/scope_api_type.rb +2 -3
  355. data/lib/decidim/api/types/session_type.rb +1 -2
  356. data/lib/decidim/api/types/taxonomy_type.rb +15 -0
  357. data/lib/decidim/api/types/trace_version_type.rb +2 -2
  358. data/lib/decidim/api/types/translated_field_type.rb +3 -5
  359. data/lib/decidim/api/types/user_group_type.rb +11 -20
  360. data/lib/decidim/api/types/user_type.rb +9 -18
  361. data/lib/decidim/asset_router/storage.rb +4 -4
  362. data/lib/decidim/assets/tailwind/tailwind.config.js.erb +2 -1
  363. data/lib/decidim/attachment_attributes.rb +1 -1
  364. data/lib/decidim/attribute_encryptor.rb +1 -1
  365. data/lib/decidim/attribute_object/nested_validator.rb +1 -1
  366. data/lib/decidim/attributes/integer_with_units.rb +27 -0
  367. data/lib/decidim/attributes/rich_text.rb +38 -0
  368. data/lib/decidim/attributes/time_with_zone.rb +11 -1
  369. data/lib/decidim/attributes.rb +4 -0
  370. data/lib/decidim/authorization_form_builder.rb +0 -7
  371. data/lib/decidim/coauthorable.rb +1 -1
  372. data/lib/decidim/command.rb +3 -3
  373. data/lib/decidim/commands/destroy_resource.rb +5 -1
  374. data/lib/decidim/commands/resource_handler.rb +2 -2
  375. data/lib/decidim/commands/restore_resource.rb +45 -0
  376. data/lib/decidim/commands/soft_delete_resource.rb +63 -0
  377. data/lib/decidim/component_manifest.rb +7 -0
  378. data/lib/decidim/content_parsers/blob_parser.rb +93 -0
  379. data/lib/decidim/content_parsers.rb +1 -0
  380. data/lib/decidim/content_renderers/blob_renderer.rb +90 -0
  381. data/lib/decidim/content_renderers.rb +1 -0
  382. data/lib/decidim/core/api.rb +2 -0
  383. data/lib/decidim/core/engine.rb +50 -8
  384. data/lib/decidim/core/menu.rb +0 -5
  385. data/lib/decidim/core/seeds.rb +42 -2
  386. data/lib/decidim/core/test/factories.rb +133 -2
  387. data/lib/decidim/core/test/shared_examples/admin_resource_gallery_examples.rb +85 -0
  388. data/lib/decidim/core/test/shared_examples/authorable_interface_examples.rb +1 -1
  389. data/lib/decidim/core/test/shared_examples/comments_examples.rb +408 -40
  390. data/lib/decidim/core/test/shared_examples/components_controller_hide_shared_examples.rb +11 -0
  391. data/lib/decidim/core/test/shared_examples/components_controller_reorder_shared_examples.rb +21 -0
  392. data/lib/decidim/core/test/shared_examples/download_open_data_shared_context.rb +36 -0
  393. data/lib/decidim/core/test/shared_examples/download_open_data_shared_examples.rb +45 -0
  394. data/lib/decidim/core/test/shared_examples/download_your_data_shared_examples.rb +17 -0
  395. data/lib/decidim/core/test/shared_examples/etiquette_validator_examples.rb +25 -0
  396. data/lib/decidim/core/test/shared_examples/follows_examples.rb +43 -0
  397. data/lib/decidim/core/test/shared_examples/has_taxonomies.rb +94 -0
  398. data/lib/decidim/core/test/shared_examples/manage_share_tokens_examples.rb +237 -0
  399. data/lib/decidim/core/test/shared_examples/map_examples.rb +2 -0
  400. data/lib/decidim/core/test/shared_examples/open_data_exporter_examples.rb +102 -0
  401. data/lib/decidim/core/test/shared_examples/participatory_space_members_page_examples.rb +46 -0
  402. data/lib/decidim/core/test/shared_examples/participatory_space_search_examples.rb +98 -0
  403. data/lib/decidim/core/test/shared_examples/permissions.rb +7 -7
  404. data/lib/decidim/core/test/shared_examples/preview_with_share_token_examples.rb +94 -0
  405. data/lib/decidim/core/test/shared_examples/reports_examples.rb +9 -5
  406. data/lib/decidim/core/test/shared_examples/resource_endorsed_event_examples.rb +2 -2
  407. data/lib/decidim/core/test/shared_examples/resource_search_examples.rb +75 -69
  408. data/lib/decidim/core/test/shared_examples/searchable_resources_shared_context.rb +1 -1
  409. data/lib/decidim/core/test/shared_examples/simple_event.rb +33 -19
  410. data/lib/decidim/core/test/shared_examples/social_share_examples.rb +25 -0
  411. data/lib/decidim/core/test/shared_examples/softdeleteable_components_examples.rb +173 -0
  412. data/lib/decidim/core/test/shared_examples/system_endorse_resource_examples.rb +54 -8
  413. data/lib/decidim/core/test/shared_examples/taxonomizable_interface_examples.rb +20 -0
  414. data/lib/decidim/core/test/shared_examples/taxonomizable_resource_examples.rb +37 -0
  415. data/lib/decidim/core/test/shared_examples/taxonomy_settings.rb +49 -0
  416. data/lib/decidim/core/test/shared_examples/translated_event_examples.rb +1 -1
  417. data/lib/decidim/core/test/shared_examples/versions_controller_examples.rb +2 -2
  418. data/lib/decidim/core/test/shared_examples/with_endorsable_permissions_examples.rb +1 -1
  419. data/lib/decidim/core/test.rb +9 -5
  420. data/lib/decidim/core/version.rb +1 -1
  421. data/lib/decidim/core.rb +58 -0
  422. data/lib/decidim/diffy_extension.rb +18 -0
  423. data/lib/decidim/download_your_data_serializers/download_your_data_identity_serializer.rb +0 -4
  424. data/lib/decidim/download_your_data_serializers/download_your_data_participatory_space_private_user_serializer.rb +3 -1
  425. data/lib/decidim/download_your_data_serializers/download_your_data_report_serializer.rb +2 -1
  426. data/lib/decidim/download_your_data_serializers/download_your_data_user_serializer.rb +6 -7
  427. data/lib/decidim/download_your_data_serializers.rb +19 -0
  428. data/lib/decidim/exporters/csv.rb +6 -0
  429. data/lib/decidim/exporters/export_manifest.rb +14 -0
  430. data/lib/decidim/exporters/pdf.rb +26 -22
  431. data/lib/decidim/filter_form_builder.rb +12 -15
  432. data/lib/decidim/form_builder.rb +7 -130
  433. data/lib/decidim/has_category.rb +5 -1
  434. data/lib/decidim/has_private_users.rb +4 -0
  435. data/lib/decidim/has_taxonomy_settings.rb +47 -0
  436. data/lib/decidim/has_upload_validations.rb +1 -1
  437. data/lib/decidim/legacy_form_builder.rb +118 -0
  438. data/lib/decidim/maintenance/import_models/application_record.rb +93 -0
  439. data/lib/decidim/maintenance/import_models/area.rb +82 -0
  440. data/lib/decidim/maintenance/import_models/area_type.rb +12 -0
  441. data/lib/decidim/maintenance/import_models/assembly_type.rb +49 -0
  442. data/lib/decidim/maintenance/import_models/categorization.rb +14 -0
  443. data/lib/decidim/maintenance/import_models/category.rb +107 -0
  444. data/lib/decidim/maintenance/import_models/participatory_process_type.rb +21 -0
  445. data/lib/decidim/maintenance/import_models/scope.rb +163 -0
  446. data/lib/decidim/maintenance/import_models.rb +19 -0
  447. data/lib/decidim/maintenance/taxonomy_importer.rb +132 -0
  448. data/lib/decidim/maintenance/taxonomy_plan.rb +78 -0
  449. data/lib/decidim/maintenance.rb +12 -0
  450. data/lib/decidim/map/autocomplete.rb +53 -8
  451. data/lib/decidim/map/dynamic_map.rb +1 -1
  452. data/lib/decidim/map/provider/geocoding/here.rb +9 -3
  453. data/lib/decidim/map.rb +3 -6
  454. data/lib/decidim/moderation_tools.rb +14 -3
  455. data/lib/decidim/newsletter_encryptor.rb +1 -1
  456. data/lib/decidim/paddable.rb +1 -1
  457. data/lib/decidim/participable.rb +10 -10
  458. data/lib/decidim/participatory_space_user.rb +14 -0
  459. data/lib/decidim/private_download_helper.rb +15 -0
  460. data/lib/decidim/query_extensions.rb +0 -26
  461. data/lib/decidim/record_encryptor.rb +51 -46
  462. data/lib/decidim/resourceable.rb +16 -0
  463. data/lib/decidim/seeds.rb +18 -20
  464. data/lib/decidim/settings_manifest.rb +36 -1
  465. data/lib/decidim/soft_deletable.rb +17 -0
  466. data/lib/decidim/taxonomizable.rb +72 -0
  467. data/lib/decidim/translatable_attributes.rb +6 -1
  468. data/lib/decidim/view_model.rb +0 -1
  469. data/lib/tasks/decidim_download_your_data_tasks.rake +2 -4
  470. data/lib/tasks/decidim_procfile.rake +6 -0
  471. data/lib/tasks/decidim_tasks.rake +1 -0
  472. data/lib/tasks/decidim_taxonomies.rake +155 -0
  473. data/lib/tasks/upgrade/{decidim_fix_categorization.rake → clean.rake} +52 -19
  474. data/lib/tasks/upgrade/decidim_active_storage_migration_tasks.rake +1 -1
  475. data/lib/tasks/upgrade/migrations.rake +91 -0
  476. metadata +217 -103
  477. data/app/cells/decidim/amendable/amenders_list/show.erb +0 -0
  478. data/app/cells/decidim/content_blocks/base/content.erb +0 -0
  479. data/app/cells/decidim/endorsers_list/full_endorsers_list.erb +0 -3
  480. data/app/cells/decidim/endorsers_list_button/content.erb +0 -1
  481. data/app/cells/decidim/endorsers_list_button_cell.rb +0 -15
  482. data/app/cells/decidim/scopes_picker/scope_picker_prompt.erb +0 -3
  483. data/app/cells/decidim/scopes_picker/scope_picker_values.erb +0 -5
  484. data/app/cells/decidim/scopes_picker/show.erb +0 -14
  485. data/app/cells/decidim/scopes_picker_cell.rb +0 -92
  486. data/app/commands/decidim/update_user_interests.rb +0 -41
  487. data/app/controllers/decidim/scopes_controller.rb +0 -84
  488. data/app/controllers/decidim/user_interests_controller.rb +0 -30
  489. data/app/forms/decidim/user_interest_scope_form.rb +0 -25
  490. data/app/forms/decidim/user_interests_form.rb +0 -17
  491. data/app/helpers/decidim/categories_helper.rb +0 -26
  492. data/app/helpers/decidim/scopes_helper.rb +0 -105
  493. data/app/packs/images/decidim/vendor/leaflet/layers-2x.png +0 -0
  494. data/app/packs/images/decidim/vendor/leaflet/layers.png +0 -0
  495. data/app/packs/images/decidim/vendor/leaflet/marker-icon-2x.png +0 -0
  496. data/app/packs/images/decidim/vendor/leaflet/marker-icon.png +0 -0
  497. data/app/packs/images/decidim/vendor/leaflet/marker-shadow.png +0 -0
  498. data/app/packs/stylesheets/decidim/legacy/MarkerCluster.Default.scss +0 -67
  499. data/app/packs/stylesheets/decidim/legacy/MarkerCluster.scss +0 -18
  500. data/app/packs/stylesheets/decidim/legacy/leaflet.scss +0 -705
  501. data/app/validators/scope_belongs_to_component_validator.rb +0 -16
  502. data/app/views/decidim/account/_user_groups.html.erb +0 -0
  503. data/app/views/decidim/scopes/_scopes_picker_input.html.erb +0 -19
  504. data/app/views/decidim/scopes/picker.html.erb +0 -53
  505. data/app/views/decidim/shared/_comments.html.erb +0 -0
  506. data/app/views/decidim/shared/_share_modal.html.erb +0 -26
  507. data/app/views/decidim/shared/_tags.html.erb +0 -1
  508. data/app/views/decidim/user_interests/_areas.html.erb +0 -14
  509. data/app/views/decidim/user_interests/_scopes.html.erb +0 -22
  510. data/app/views/decidim/user_interests/show.html.erb +0 -22
  511. data/config/initializers/foundation_rails_helper.rb +0 -4
  512. data/lib/decidim/core/test/shared_examples/has_category.rb +0 -38
  513. data/lib/decidim/core/test/shared_examples/has_scope.rb +0 -11
  514. data/lib/decidim/core/test/shared_examples/manage_component_share_tokens.rb +0 -83
  515. data/lib/decidim/core/test/shared_examples/preview_component_with_share_token_examples.rb +0 -49
  516. data/lib/decidim/core/test/shared_examples/scope_helper_examples.rb +0 -93
  517. data/lib/decidim/seven_zip_wrapper.rb +0 -29
@@ -21,6 +21,7 @@ const updateActiveUploads = (modal) => {
21
21
  const files = document.querySelector(`[data-active-uploads=${modal.modal.id}]`)
22
22
  const previousId = Array.from(files.querySelectorAll("[type=hidden][id]"))
23
23
  const isMultiple = modal.options.multiple
24
+ const isTitled = modal.options.titled
24
25
 
25
26
  // fastest way to clean children nodes
26
27
  files.textContent = ""
@@ -34,16 +35,26 @@ const updateActiveUploads = (modal) => {
34
35
  let hidden = ""
35
36
  if (file.hiddenField) {
36
37
  // if there is hiddenField, this file is new
37
- const fileField = isMultiple
38
- ? `${modal.options.resourceName}[${modal.options.addAttribute}][${ix}][file]`
39
- : `${modal.options.resourceName}[${modal.options.addAttribute}]`
38
+ let fileField = null;
39
+ if (isMultiple) {
40
+ fileField = `${modal.options.resourceName}[${modal.options.addAttribute}][${ix}][file]`
41
+ } else if (isTitled) {
42
+ fileField = `${modal.options.resourceName}[${modal.options.addAttribute}][file]`
43
+ } else {
44
+ fileField = `${modal.options.resourceName}[${modal.options.addAttribute}]`;
45
+ }
40
46
 
41
47
  hidden = `<input type="hidden" name="${fileField}" value="${file.hiddenField}" />`
42
48
  } else {
43
49
  // otherwise, we keep the attachmentId
44
- const fileField = isMultiple
45
- ? `${modal.options.resourceName}[${modal.options.addAttribute}][${ix}][id]`
46
- : `${modal.options.resourceName}[${modal.options.addAttribute}]`
50
+ let fileField = null;
51
+ if (isMultiple) {
52
+ fileField = `${modal.options.resourceName}[${modal.options.addAttribute}][${ix}][id]`;
53
+ } else if (isTitled) {
54
+ fileField = `${modal.options.resourceName}[${modal.options.addAttribute}][id]`;
55
+ } else {
56
+ fileField = `${modal.options.resourceName}[${modal.options.addAttribute}]`;
57
+ }
47
58
 
48
59
  // convert all node attributes to string
49
60
  const attributes = Array.from(previousId.find(({ id }) => id === file.attachmentId).attributes).reduce((acc, { name, value }) => `${acc} ${name}="${value}"`, "")
@@ -51,10 +62,12 @@ const updateActiveUploads = (modal) => {
51
62
  hidden += `<input type="hidden" name="${fileField}" value="${file.attachmentId}" />`
52
63
  }
53
64
 
54
- if (modal.options.titled) {
65
+ if (isTitled) {
55
66
  const titleValue = modal.modal.querySelectorAll('input[type="text"]')[ix].value
56
67
  // NOTE - Renaming the attachment is not supported when multiple uploader is disabled
57
- const titleField = `${modal.options.resourceName}[${modal.options.addAttribute}][${ix}][title]`
68
+ const titleField = isMultiple
69
+ ? `${modal.options.resourceName}[${modal.options.addAttribute}][${ix}][title]`
70
+ : `${modal.options.resourceName}[${modal.options.addAttribute}][title]`
58
71
  hidden += `<input type="hidden" name="${titleField}" value="${escapeQuotes(titleValue)}" />`
59
72
 
60
73
  title = titleValue
@@ -1,4 +1,4 @@
1
- import Rails from "@rails/ujs";
1
+ const { Rails } = window;
2
2
 
3
3
  // Make the remote form submit buttons disabled when the form is being
4
4
  // submitted to avoid multiple submits.
@@ -0,0 +1,60 @@
1
+ document.addEventListener("DOMContentLoaded", () => {
2
+ const info = (target, msg) => {
3
+ const label = target.closest("label");
4
+ label.querySelectorAll(".form-error").forEach((el) => el.remove());
5
+ if (msg) {
6
+ const error = document.createElement("span");
7
+ error.className = "form-error";
8
+ error.textContent = msg;
9
+ label.appendChild(error);
10
+ error.style.display = "block";
11
+ }
12
+ };
13
+
14
+ const setLocating = (button, enable) => {
15
+ if (enable) {
16
+ button.setAttribute("disabled", true);
17
+ } else {
18
+ button.removeAttribute("disabled");
19
+ }
20
+ };
21
+
22
+ document.querySelectorAll(".user-device-location button").forEach((button) => {
23
+ button.addEventListener("click", (event) => {
24
+ const target = event.target;
25
+ if (target.disabled) {
26
+ return;
27
+ }
28
+
29
+ const input = document.getElementById(target.dataset.input);
30
+ const errorNoLocation = target.dataset.errorNoLocation;
31
+ const errorUnsupported = target.dataset.errorUnsupported;
32
+ const url = target.dataset.url;
33
+
34
+ if (navigator.geolocation) {
35
+ setLocating(target, true);
36
+ navigator.geolocation.getCurrentPosition((position) => {
37
+ const coordinates = [position.coords.latitude, position.coords.longitude];
38
+
39
+ // reverse geolocation
40
+ $.post(url, { latitude: coordinates[0], longitude: coordinates[1] }, (data) => {
41
+ input.value = data.address;
42
+ $(input).trigger("geocoder-suggest-coordinates.decidim", [coordinates]);
43
+ }).fail((xhr, status, error) => {
44
+ info(input, `${errorNoLocation} ${error}`);
45
+ });
46
+
47
+ setLocating(target, false);
48
+
49
+ }, (evt) => {
50
+ info(input, `${errorNoLocation} ${evt.message}`);
51
+ target.removeAttribute("disabled");
52
+ }, {
53
+ enableHighAccuracy: true
54
+ });
55
+ } else {
56
+ info(input, errorUnsupported);
57
+ }
58
+ });
59
+ });
60
+ });
@@ -15,7 +15,7 @@ $(() => {
15
15
  }, 1000);
16
16
 
17
17
  // Prevent reload when page is already unloading, otherwise it may cause infinite reloads.
18
- window.addEventListener("beforeunload", () => {
18
+ window.addEventListener("pagehide", () => {
19
19
  clearInterval(exitInterval);
20
20
  return;
21
21
  });
@@ -8,6 +8,7 @@
8
8
  import "core-js/stable";
9
9
  import "regenerator-runtime/runtime";
10
10
  import "jquery"
11
+ import "chartkick/chart.js"
11
12
 
12
13
  // REDESIGN_PENDING: deprecated
13
14
  import "foundation-sites";
@@ -41,7 +42,6 @@ import "src/decidim/vizzs"
41
42
  import "src/decidim/responsive_horizontal_tabs"
42
43
  import "src/decidim/security/selfxss_warning"
43
44
  import "src/decidim/session_timeouter"
44
- import "src/decidim/confirm"
45
45
  import "src/decidim/results_listing"
46
46
  import "src/decidim/impersonation"
47
47
  import "src/decidim/gallery"
@@ -50,9 +50,11 @@ import "src/decidim/data_consent"
50
50
  import "src/decidim/abide_form_validator_fixer"
51
51
  import "src/decidim/sw"
52
52
  import "src/decidim/sticky_header"
53
+ import "src/decidim/sticky_footer"
53
54
  import "src/decidim/attachments"
54
55
 
55
56
  // local deps that require initialization
57
+ import ConfirmDialog, { initializeConfirm } from "src/decidim/confirm"
56
58
  import formDatePicker from "src/decidim/datepicker/form_datepicker"
57
59
  import Configuration from "src/decidim/configuration"
58
60
  import ExternalLink from "src/decidim/external_link"
@@ -69,6 +71,7 @@ import handleNotificationActions from "src/decidim/notifications_actions"
69
71
  import RemoteModal from "src/decidim/remote_modal"
70
72
  import selectActiveIdentity from "src/decidim/identity_selector_dialog"
71
73
  import createTooltip from "src/decidim/tooltips"
74
+ import fetchRemoteTooltip from "src/decidim/remote_tooltips"
72
75
  import createToggle from "src/decidim/toggle"
73
76
  import {
74
77
  createAccordion,
@@ -78,6 +81,7 @@ import {
78
81
  Dialogs
79
82
  } from "src/decidim/a11y"
80
83
  import changeReportFormBehavior from "src/decidim/change_report_form_behavior"
84
+ import setOnboardingAction from "src/decidim/onboarding_pending_action"
81
85
 
82
86
  // bad practice: window namespace should avoid be populated as much as possible
83
87
  // rails-translations could be referenced through a single Decidim.I18n object
@@ -89,6 +93,7 @@ window.Decidim = window.Decidim || {
89
93
  addInputEmoji,
90
94
  EmojiButton,
91
95
  Dialogs,
96
+ ConfirmDialog,
92
97
  announceForScreenReader
93
98
  };
94
99
 
@@ -121,6 +126,8 @@ window.initFoundation = (element) => {
121
126
  });
122
127
  };
123
128
 
129
+ // Confirm initialization needs to happen before Rails.start()
130
+ initializeConfirm();
124
131
  Rails.start()
125
132
 
126
133
  /**
@@ -195,7 +202,13 @@ const initializer = (element = document) => {
195
202
  // Initialize data-toggles
196
203
  element.querySelectorAll("[data-toggle]").forEach((elem) => createToggle(elem))
197
204
 
205
+ element.querySelectorAll("[data-remote-tooltip]").forEach((elem) => fetchRemoteTooltip(elem))
206
+
198
207
  element.querySelectorAll(".new_report").forEach((elem) => changeReportFormBehavior(elem))
208
+
209
+ element.querySelectorAll("[data-onboarding-action]").forEach((elem) => setOnboardingAction(elem))
210
+
211
+ document.dispatchEvent(new CustomEvent("decidim:loaded", { detail: { element } }));
199
212
  }
200
213
 
201
214
  // If no jQuery is used the Tribute feature used in comments to autocomplete
@@ -0,0 +1,24 @@
1
+ import Cookies from "js-cookie";
2
+
3
+ const ONBOARDING_COOKIE_EXPIRY = 365;
4
+
5
+ // The same key is set in the Decidim::OnboardingManager class to retrieve the data from the cookie and store it in the extended data attribute
6
+ const DATA_KEY = "onboarding";
7
+
8
+ /**
9
+ * @param {DOMElement} element Element which provides the information for cookie about action to perform.
10
+ * @return {Void} Nothing
11
+ */
12
+ export default function setOnboardingAction(element) {
13
+ // the dialog-open data attribute is stealing the click event
14
+ element.addEventListener("mousedown", () => {
15
+ const action = element.dataset.onboardingAction;
16
+ const model = element.dataset.onboardingModel;
17
+ const permissionsHolder = element.dataset.onboardingPermissionsHolder;
18
+ const redirectPath = element.dataset.onboardingRedirectPath;
19
+
20
+ Cookies.set(DATA_KEY, JSON.stringify({ action, model, permissionsHolder, redirectPath }), {
21
+ expires: ONBOARDING_COOKIE_EXPIRY
22
+ });
23
+ });
24
+ }
@@ -0,0 +1,38 @@
1
+ import createTooltip from "src/decidim/tooltips"
2
+
3
+ /**
4
+ * Given the following HTML structure,
5
+ * <span data-remote-tooltip="true" tooltip-url="some url" data-author="true">
6
+ * <span></span>
7
+ * </span>
8
+ *
9
+ * This function will check if the HTMLElement where is attached to has a child, and will add a data tooltip attribute
10
+ * to the respective child in order to attach the fetched HTML content fetched under a json key as the content of the
11
+ * HTML tooltip. The DOM structure is expected to be like follows:
12
+ *
13
+ * <span data-remote-tooltip="true" tooltip-url="some url" data-author="true">
14
+ * <span data-tooltip="HTML content from json data field"></span>
15
+ * </span>
16
+ *
17
+ * @param {HTMLElement} node The element holding the initialization data
18
+ * @returns {void}
19
+ */
20
+ export default async function(node) {
21
+ const container = node.firstElementChild;
22
+
23
+ if (container) {
24
+ const response = await fetch(node.dataset.tooltipUrl, {
25
+ headers: {
26
+ "Content-Type": "application/json"
27
+ }
28
+ });
29
+ if (response.ok) {
30
+ const json = await response.json();
31
+
32
+ container.dataset.tooltip = json.data;
33
+ createTooltip(container);
34
+ } else {
35
+ console.error(response.status, response.statusText);
36
+ }
37
+ }
38
+ }
@@ -127,7 +127,7 @@ $(() => {
127
127
  setTimer(timeoutInSeconds);
128
128
  });
129
129
 
130
- window.addEventListener("beforeunload", () => {
130
+ window.addEventListener("pagehide", () => {
131
131
  clearInterval(exitInterval);
132
132
  return;
133
133
  });
@@ -0,0 +1,29 @@
1
+ // This script add margin to the footer when the sticky CTA Buttons are shown on mobile devices,
2
+ // so the footer is always visible.
3
+ //
4
+ // The sticky buttons show some of the main Call to Actions (CTAs) so that they remain accessible on the
5
+ // screen as the participant scrolls through the detailed view of the Meetings, Proposals, Surveys, and Budgets
6
+ // components.
7
+ //
8
+
9
+ const footer = document.querySelector("footer");
10
+ const stickyButtons = document.querySelector("[data-sticky-buttons]");
11
+
12
+ const adjustCtasButtons = () => {
13
+ if (!stickyButtons) {
14
+ return;
15
+ }
16
+
17
+ const marginBottom = stickyButtons.offsetHeight;
18
+ footer.style.marginBottom = `${marginBottom}px`;
19
+ };
20
+
21
+ if (stickyButtons) {
22
+ document.addEventListener("scroll", () => {
23
+ adjustCtasButtons();
24
+ });
25
+
26
+ document.addEventListener("on:toggle", () => {
27
+ adjustCtasButtons();
28
+ });
29
+ }
@@ -1,33 +1,14 @@
1
- // This script implements the sticky header and the sticky buttons. The sticky header hides when participants scroll down and shows when they scroll up.
2
- // Sticky headers allow users to quickly access the navigation, search, and utility-navigation elements without scrolling up to the top of the page. They increase the discoverability of the elements in the header.
3
- // The sticky buttons in the other hand, those are some of the main Call to Actions (CTAs) that remain accessible on the screen as the user scrolls through the detailed view of the Meetings, Proposals, Surveys, and Budgets components.
1
+ // This script implements the sticky header on mobile devices.
2
+ //
3
+ // The sticky header hides when participants scroll down and shows when they scroll up.
4
+ // Sticky headers allow users to quickly access the navigation, search, and utility-navigation
5
+ // elements without scrolling up to the top of the page. They increase the discoverability of the elements in the header.
6
+ //
4
7
 
5
8
  import { screens } from "tailwindcss/defaultTheme"
6
9
 
7
10
  let prevScroll = window.scrollY;
8
11
  const stickyHeader = document.querySelector("[data-sticky-header]");
9
- const footer = document.querySelector("footer");
10
- const stickyButtons = document.querySelectorAll("[data-sticky-buttons]");
11
-
12
- const isElementInViewport = (element) => {
13
- const rect = element.getBoundingClientRect();
14
- return rect.top >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight);
15
- };
16
-
17
- const adjustCtasButtons = () => {
18
- if (!stickyButtons || !stickyButtons.length) {
19
- return;
20
- }
21
-
22
- let visibleButtons = Array.from(stickyButtons).filter(isElementInViewport);
23
-
24
- if (visibleButtons.length > 0) {
25
- const marginBottom = Math.max(...visibleButtons.map((ctasButton) => ctasButton.offsetHeight));
26
- footer.style.marginBottom = `${marginBottom}px`;
27
- } else {
28
- footer.style.marginBottom = 0;
29
- }
30
- };
31
12
 
32
13
  // Fix the menu bar container margin top when there are multiple elements in the sticky header
33
14
  // As there could be different heights and we cannot know beforehand, we need to adjust this in a dynamic way
@@ -76,12 +57,6 @@ if (stickyHeader) {
76
57
  }
77
58
  prevScroll = currentScroll;
78
59
  }
79
-
80
- adjustCtasButtons();
81
60
  }
82
61
  });
83
-
84
- document.addEventListener("on:toggle", () => {
85
- adjustCtasButtons();
86
- });
87
62
  };
@@ -9,7 +9,7 @@ export default function createToggle(component) {
9
9
  const { toggle } = component.dataset
10
10
 
11
11
  if (!component.id) {
12
- // when component has no id, we enforce to have it one
12
+ // when component has no id, we enforce it to have one
13
13
  component.id = `toggle-${Math.random().toString(36).substring(7)}`
14
14
  }
15
15
 
@@ -63,9 +63,32 @@ export default function(node) {
63
63
  // append to dom hidden, to apply css transitions
64
64
  tooltip.setAttribute("aria-hidden", true)
65
65
 
66
- const append = () => {
67
- // do nothing if the tooltip is already present at the DOM
66
+ // used to detect if the user is on a mobile device by checking the user agent
67
+ const useMobile = (/Mobi|Android/i).test(navigator.userAgent);
68
+
69
+ // used not to collapse tooltip
70
+ let removeTooltip = () => {
71
+ tooltip.setAttribute("aria-hidden", "true");
72
+ }
73
+
74
+ // used to allow clicks outside the tooltip to take place on the page or device
75
+ const OutsideClick = (event) => {
76
+ if (!tooltip.contains(event.target) && event.target !== node) {
77
+ removeTooltip();
78
+ }
79
+ }
80
+
81
+ // function called again to allow clicks outside the tooltip to collapse the tooltip
82
+ removeTooltip = () => {
83
+ tooltip.setAttribute("aria-hidden", "true");
84
+ document.removeEventListener("click", OutsideClick)
85
+ }
86
+
87
+ const toggleTooltip = (event) => {
88
+ event.preventDefault();
89
+ // if the tooltip is visible in the DOM, hide it otherwise display
68
90
  if (tooltip.getAttribute("aria-hidden") === "false") {
91
+ tooltip.setAttribute("aria-hidden", "true");
69
92
  return
70
93
  }
71
94
 
@@ -106,27 +129,24 @@ export default function(node) {
106
129
  tooltip.style.left = `${positionX}px`
107
130
 
108
131
  tooltip.setAttribute("aria-hidden", false)
109
- }
110
-
111
- // in order to revoke the remove event when the mouse is over the trigger/tooltip
112
- let cancelRemove = false
113
132
 
114
- const remove = () => {
115
- cancelRemove = false
116
- // give some sleep time before hiding the element from the DOM
117
- setTimeout(() => !cancelRemove && tooltip.setAttribute("aria-hidden", true), 500);
133
+ // sleep time before hiding the element from the DOM
134
+ setTimeout(() => document.addEventListener("click", OutsideClick))
118
135
  }
119
136
 
120
- // keyboard listener is at root-level
121
- window.addEventListener("keydown", (event) => event.key === "Escape" && remove())
122
-
123
- node.addEventListener("mouseenter", append)
124
- node.addEventListener("mouseleave", remove)
125
- node.addEventListener("focus", append)
126
- node.addEventListener("blur", remove)
127
- tooltip.addEventListener("mouseenter", () => tooltip.setAttribute("aria-hidden", false))
128
- tooltip.addEventListener("mouseleave", remove)
129
-
130
- node.addEventListener("mouseover", () => (cancelRemove = true))
131
- tooltip.addEventListener("mouseover", () => (cancelRemove = true))
137
+ if (useMobile) {
138
+ // mobile use to click and toggle the tooltip
139
+ node.addEventListener("click", toggleTooltip);
140
+ window.addEventListener("keydown", (event) => event.key === "Escape" && removeTooltip())
141
+ } else {
142
+ // desktop use for hover and blur over tooltip
143
+ node.addEventListener("mouseenter", toggleTooltip)
144
+ node.addEventListener("mouseleave", removeTooltip)
145
+ node.addEventListener("focus", toggleTooltip)
146
+ node.addEventListener("blur", removeTooltip)
147
+
148
+ // tooltip hover listeners to prevent hiding when hovered
149
+ tooltip.addEventListener("mouseenter", () => tooltip.setAttribute("aria-hidden", false))
150
+ tooltip.addEventListener("mouseleave", removeTooltip)
151
+ }
132
152
  }
@@ -2,6 +2,7 @@ import PasswordToggler from "src/decidim/password_toggler";
2
2
 
3
3
  $(() => {
4
4
  const $userRegistrationForm = $("#register-form");
5
+ const $userOmniauthRegistrationForm = $("#omniauth-register-form");
5
6
  const $userGroupFields = $userRegistrationForm.find(".user-group-fields");
6
7
  const userPassword = document.querySelector(".user-password");
7
8
  const inputSelector = 'input[name="user[sign_up_as]"]';
@@ -19,9 +20,11 @@ $(() => {
19
20
 
20
21
  const checkNewsletter = (check) => {
21
22
  $userRegistrationForm.find(newsletterSelector).prop("checked", check);
23
+ $userOmniauthRegistrationForm.find(newsletterSelector).prop("checked", check);
22
24
  $newsletterModal.data("continue", true);
23
25
  window.Decidim.currentDialogs["sign-up-newsletter-modal"].close()
24
26
  $userRegistrationForm.submit();
27
+ $userOmniauthRegistrationForm.submit();
25
28
  }
26
29
 
27
30
  setGroupFieldsVisibility($userRegistrationForm.find(`${inputSelector}:checked`).val());
@@ -42,6 +45,16 @@ $(() => {
42
45
  }
43
46
  });
44
47
 
48
+ $userOmniauthRegistrationForm.on("submit", (event) => {
49
+ const newsletterChecked = $userOmniauthRegistrationForm.find(newsletterSelector);
50
+ if (!$newsletterModal.data("continue")) {
51
+ if (!newsletterChecked.prop("checked")) {
52
+ event.preventDefault();
53
+ window.Decidim.currentDialogs["sign-up-newsletter-modal"].open()
54
+ }
55
+ }
56
+ });
57
+
45
58
  $newsletterModal.find("[data-check]").on("click", (event) => {
46
59
  checkNewsletter($(event.target).data("check"));
47
60
  });
@@ -0,0 +1,148 @@
1
+ import confirmAction from "src/decidim/confirm"
2
+ import { getMessages } from "src/decidim/i18n"
3
+
4
+ const { Rails } = window;
5
+
6
+ const createUnloadPreventer = () => {
7
+ const preventUnloadConditions = [];
8
+
9
+ const confirmMessage = getMessages("confirmUnload") || "Are you sure you want to leave this page?";
10
+
11
+ const canUnload = (event) => !preventUnloadConditions.some((condition) => condition(event));
12
+
13
+ // TLDR:
14
+ // The beforeunload event does not work during tests due to the deprecation of
15
+ // the unload event and ChromeDriver automatically accepting these dialogs.
16
+ // ---
17
+ //
18
+ // Even when there are custom listeners on links and forms, the beforeunload
19
+ // event is to ensure that the user does not accidentally reload the page or
20
+ // close the browser or the tab. Note that this does not work during the tests
21
+ // with ChromeDriver due to the deprecation of the unload event and
22
+ // ChromeDriver automatically accepting these dialogs. For the time being,
23
+ // this should work when a real user interacts with the browser along with the
24
+ // "Permissions-Policy" header set by the backend. For more information about
25
+ // the header, see Decidim::Headers::BrowserFeaturePermissions).
26
+ const unloadListener = (event) => {
27
+ if (canUnload(event)) {
28
+ return;
29
+ }
30
+
31
+ // According to:
32
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
33
+ //
34
+ // > [...] best practice is to trigger the dialog by invoking
35
+ // > preventDefault() on the event object, while also setting returnValue to
36
+ // > support legacy cases.
37
+ event.preventDefault();
38
+ event.returnValue = true;
39
+ };
40
+
41
+ // The beforeunload event listener has to be registered AFTER a user
42
+ // interaction which is why it is wrapped around the next click event that
43
+ // happens after the first unload listener was registered. Otherwise it might
44
+ // not work due to the deprecation of the unload APIs in Chromium based
45
+ // browsers and possibly in the web standards in the future.
46
+ //
47
+ // According to:
48
+ // https://developer.chrome.com/docs/web-platform/page-lifecycle-api#the_beforeunload_event
49
+ //
50
+ // > Never add a beforeunload listener unconditionally or use it as an
51
+ // > end-of-session signal. Only add it when a user has unsaved work, and
52
+ // > remove it as soon as that work has been saved.
53
+ const registerBeforeUnload = () => {
54
+ window.removeEventListener("click", registerBeforeUnload);
55
+ window.addEventListener("beforeunload", unloadListener);
56
+ };
57
+
58
+ const disableBeforeUnload = () => {
59
+ window.removeEventListener("click", registerBeforeUnload);
60
+ window.removeEventListener("beforeunload", unloadListener);
61
+ };
62
+
63
+ const linkClickListener = (ev) => {
64
+ const link = ev.target?.closest("a");
65
+ if (!link) {
66
+ return;
67
+ }
68
+
69
+ if (canUnload(ev)) {
70
+ disableBeforeUnload();
71
+ document.removeEventListener("click", linkClickListener);
72
+ return;
73
+ }
74
+
75
+ window.exitUrl = link.href;
76
+
77
+ ev.preventDefault();
78
+ ev.stopPropagation();
79
+
80
+ confirmAction(confirmMessage, link).then((answer) => {
81
+ if (!answer) {
82
+ return;
83
+ }
84
+
85
+ disableBeforeUnload();
86
+ document.removeEventListener("click", linkClickListener);
87
+ link.click();
88
+ });
89
+ };
90
+
91
+ const formSubmitListener = (ev) => {
92
+ const source = ev.target?.closest("form");
93
+ if (!source) {
94
+ return;
95
+ }
96
+
97
+ if (canUnload(ev)) {
98
+ disableBeforeUnload();
99
+ document.removeEventListener("submit", formSubmitListener);
100
+ return;
101
+ }
102
+
103
+ const button = source.closest(Rails.formSubmitSelector);
104
+ if (!button) {
105
+ return;
106
+ }
107
+
108
+ ev.preventDefault();
109
+ ev.stopImmediatePropagation();
110
+ ev.stopPropagation();
111
+
112
+ confirmAction(confirmMessage, button).then((answer) => {
113
+ if (!answer) {
114
+ return;
115
+ }
116
+
117
+ disableBeforeUnload();
118
+ document.removeEventListener("submit", formSubmitListener);
119
+ source.submit();
120
+ });
121
+ };
122
+
123
+ const registerPreventUnloadListeners = () => {
124
+ window.addEventListener("click", registerBeforeUnload);
125
+ document.addEventListener("click", linkClickListener);
126
+ document.addEventListener("submit", formSubmitListener);
127
+ };
128
+
129
+ return {
130
+ addPreventCondition: (condition) => {
131
+ if (typeof condition !== "function") {
132
+ return;
133
+ }
134
+
135
+ if (preventUnloadConditions.length < 1) {
136
+ // The unload listeners are global, so only the first call to this
137
+ // function should result to registering these listeners.
138
+ registerPreventUnloadListeners();
139
+ }
140
+
141
+ preventUnloadConditions.push(condition);
142
+ }
143
+ };
144
+ };
145
+
146
+ const unloadPreventer = createUnloadPreventer();
147
+
148
+ export const preventUnload = (condition) => unloadPreventer.addPreventCondition(condition);
@@ -11,3 +11,33 @@
11
11
  [id*="comment"][class="comment-reply"][aria-hidden="false"] {
12
12
  display: block;
13
13
  }
14
+
15
+ .card-accordion {
16
+ @apply border-b border-gray-3 mt-6;
17
+
18
+ &-title {
19
+ @apply text-primary font-semibold text-xl inline-block;
20
+ }
21
+
22
+ &-divider-button {
23
+ @apply flex items-center justify-between items-end w-full;
24
+
25
+ svg {
26
+ @apply inline-block w-6 h-6 fill-primary;
27
+ }
28
+
29
+ &[aria-expanded="true"] {
30
+ svg {
31
+ @apply rotate-180 transition-transform;
32
+ }
33
+ }
34
+ }
35
+
36
+ &-section {
37
+ @apply pb-8;
38
+
39
+ ul {
40
+ @apply mb-0;
41
+ }
42
+ }
43
+ }