decidim-core 0.28.4 → 0.28.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/cells/decidim/activity_cell.rb +1 -4
- data/app/cells/decidim/author/show.erb +5 -4
- data/app/cells/decidim/author_cell.rb +26 -0
- data/app/cells/decidim/card_s/show.erb +5 -3
- data/app/cells/decidim/diff_cell.rb +4 -0
- data/app/cells/decidim/newsletter_templates/image_text_cta_cell.rb +1 -1
- data/app/cells/decidim/translation_bar/show.erb +3 -3
- data/app/cells/decidim/translation_bar_cell.rb +1 -1
- data/app/commands/decidim/destroy_account.rb +3 -0
- data/app/controllers/decidim/doorkeeper/credentials_controller.rb +1 -1
- data/app/controllers/decidim/links_controller.rb +1 -1
- data/app/controllers/decidim/profiles_controller.rb +4 -0
- data/app/helpers/concerns/decidim/user_role_checker.rb +46 -0
- data/app/helpers/decidim/cta_button_helper.rb +1 -1
- data/app/helpers/decidim/map_helper.rb +6 -1
- data/app/helpers/decidim/sanitize_helper.rb +11 -2
- data/app/models/decidim/attachment.rb +1 -1
- data/app/packs/src/decidim/append_redirect_url_to_modals.js +14 -6
- data/app/packs/src/decidim/direct_uploads/upload_field.js +21 -8
- data/app/packs/src/decidim/index.js +3 -0
- data/app/packs/src/decidim/remote_tooltips.js +38 -0
- data/app/packs/src/decidim/toggle.js +1 -1
- data/app/packs/src/decidim/tooltips.js +42 -22
- data/app/packs/stylesheets/decidim/_profile.scss +1 -1
- data/app/packs/stylesheets/decidim/_progress-bar.scss +1 -1
- data/app/packs/stylesheets/decidim/legacy/conference-diploma.scss +2 -1
- data/app/presenters/decidim/attachment_presenter.rb +1 -1
- data/app/services/decidim/base_diff_renderer.rb +26 -2
- data/app/services/decidim/email_notification_generator.rb +14 -5
- data/app/views/decidim/pages/_tabbed.html.erb +2 -2
- data/app/views/layouts/decidim/header/_menu_breadcrumb_mobile_tablet.html.erb +1 -1
- data/config/locales/ar.yml +12 -0
- data/config/locales/bn-BD.yml +1 -0
- data/config/locales/bs-BA.yml +98 -0
- data/config/locales/ca.yml +13 -9
- data/config/locales/cs.yml +5 -0
- data/config/locales/de.yml +16 -12
- data/config/locales/el.yml +3 -0
- data/config/locales/en.yml +4 -0
- data/config/locales/es-MX.yml +5 -1
- data/config/locales/es-PY.yml +5 -1
- data/config/locales/es.yml +11 -7
- data/config/locales/eu.yml +198 -181
- data/config/locales/fi-plain.yml +4 -0
- data/config/locales/fi.yml +39 -35
- data/config/locales/fr-CA.yml +5 -1
- data/config/locales/fr.yml +4 -0
- data/config/locales/ga-IE.yml +5 -0
- data/config/locales/gl.yml +4 -0
- data/config/locales/hu.yml +1 -1
- data/config/locales/id-ID.yml +4 -0
- data/config/locales/is-IS.yml +4 -1
- data/config/locales/it.yml +40 -0
- data/config/locales/ja.yml +15 -13
- data/config/locales/lb.yml +5 -0
- data/config/locales/lt.yml +1 -1
- data/config/locales/lv.yml +4 -0
- data/config/locales/nl.yml +6 -1
- data/config/locales/no.yml +5 -0
- data/config/locales/pl.yml +1 -1
- data/config/locales/pt-BR.yml +1 -1
- data/config/locales/pt.yml +11 -0
- data/config/locales/ro-RO.yml +243 -134
- data/config/locales/ru.yml +4 -0
- data/config/locales/sk.yml +5 -1
- data/config/locales/sv.yml +7 -7
- data/config/locales/tr-TR.yml +6 -1
- data/config/locales/uk.yml +4 -1
- data/config/locales/zh-CN.yml +5 -0
- data/config/locales/zh-TW.yml +4 -0
- data/config/routes.rb +1 -0
- data/decidim-core.gemspec +4 -1
- data/lib/decidim/api/functions/component_list.rb +1 -1
- data/lib/decidim/api/functions/participatory_space_finder_base.rb +11 -1
- data/lib/decidim/api/interfaces/participatory_space_interface.rb +1 -1
- data/lib/decidim/api/types/component_type.rb +7 -0
- data/lib/decidim/api/types/user_group_type.rb +4 -0
- data/lib/decidim/api/types/user_type.rb +4 -0
- data/lib/decidim/attributes/rich_text.rb +38 -0
- data/lib/decidim/attributes/time_with_zone.rb +11 -1
- data/lib/decidim/attributes.rb +2 -0
- data/lib/decidim/content_parsers/blob_parser.rb +93 -0
- data/lib/decidim/content_parsers.rb +1 -0
- data/lib/decidim/content_renderers/blob_renderer.rb +90 -0
- data/lib/decidim/content_renderers.rb +1 -0
- data/lib/decidim/core/engine.rb +29 -1
- data/lib/decidim/core/test/factories.rb +28 -0
- data/lib/decidim/core/test/shared_examples/authorable_interface_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +15 -2
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/diffy_extension.rb +18 -0
- data/lib/decidim/form_builder.rb +1 -1
- data/lib/decidim/map/autocomplete.rb +1 -0
- data/lib/decidim/participatory_space_user.rb +4 -0
- data/lib/decidim/query_extensions.rb +0 -26
- data/lib/decidim/settings_manifest.rb +2 -0
- data/lib/decidim/translatable_attributes.rb +6 -1
- data/lib/tasks/upgrade/decidim_fix_categorization.rake +34 -8
- metadata +28 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 30504edbc5451f226b04213804ae8b02392132d8f66f9d5ebe9ea58ad264031e
|
|
4
|
+
data.tar.gz: 0ff217364122ef3812f7aa950e4908364126ceca46f135d0d5dc049b1ee19537
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 897aec8c06d1dd2110a5bd880e07061cab5e12495b707ed175afa81468c5ac162cf3d7a6643879eab83a82a9ca76232ff82dcb0d9b29ccf277d328fec6539a35
|
|
7
|
+
data.tar.gz: 88e9607861160a270e3604733a323fc2b1d359779c335ff8ccce97c9e587062c9c916d07682ad0ddda2b50abe2f718d3ce4baeb5bf77cbf3aab77ea231160014
|
|
@@ -106,10 +106,7 @@ module Decidim
|
|
|
106
106
|
hash << id_prefix
|
|
107
107
|
hash << I18n.locale.to_s
|
|
108
108
|
hash << model.class.name.underscore
|
|
109
|
-
hash << model.cache_key_with_version
|
|
110
|
-
if (author_cell = author)
|
|
111
|
-
hash.push(Digest::MD5.hexdigest(author_cell.send(:cache_hash)))
|
|
112
|
-
end
|
|
109
|
+
hash << model.cache_key_with_version if model.respond_to?(:cache_key_with_version)
|
|
113
110
|
|
|
114
111
|
hash.join(Decidim.cache_key_separator)
|
|
115
112
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
<%# If the options hash has the demo key it means we are in the decidim-design engine, so it is not a real-world scenario with actual users %>
|
|
2
|
+
<% tooltip = options.has_key?(:demo) ? { tooltip: render(:profile_minicard).html_safe } : nil %>
|
|
3
|
+
<%= content_tag(:span, class: :author, data: ) do %>
|
|
4
|
+
<%= content_tag :span, class: "author__container#{" is-compact" if layout == :compact}", data: tooltip do %>
|
|
4
5
|
<% if layout == :compact %>
|
|
5
6
|
<%= render :avatar %>
|
|
6
7
|
|
|
@@ -24,4 +25,4 @@
|
|
|
24
25
|
<%= render action %>
|
|
25
26
|
<% end %>
|
|
26
27
|
<% end %>
|
|
27
|
-
|
|
28
|
+
<% end %>
|
|
@@ -49,8 +49,26 @@ module Decidim
|
|
|
49
49
|
@context_actions_options ||= options[:context_actions].map(&:to_sym)
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
def profile_minicard
|
|
53
|
+
render
|
|
54
|
+
end
|
|
55
|
+
|
|
52
56
|
private
|
|
53
57
|
|
|
58
|
+
# If the options hash has the demo key it means we are in the decidim-design engine,
|
|
59
|
+
# so it is not a real-world scenario with actual users
|
|
60
|
+
def data
|
|
61
|
+
@data ||= begin
|
|
62
|
+
internal_data = { author: true }
|
|
63
|
+
if has_tooltip? && !options.has_key?(:demo)
|
|
64
|
+
internal_data["remote_tooltip"] = true
|
|
65
|
+
internal_data["tooltip-url"] = decidim.profile_tooltip_path(raw_model.nickname)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
internal_data
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
54
72
|
def layout
|
|
55
73
|
@layout ||= LAYOUTS.include?(options[:layout]) ? options[:layout] : :default
|
|
56
74
|
end
|
|
@@ -162,5 +180,13 @@ module Decidim
|
|
|
162
180
|
def resource_name
|
|
163
181
|
@resource_name ||= from_context.class.name.demodulize.underscore
|
|
164
182
|
end
|
|
183
|
+
|
|
184
|
+
def has_tooltip?
|
|
185
|
+
return false if model.deleted?
|
|
186
|
+
return false if model.respond_to?(:blocked?) && model.blocked?
|
|
187
|
+
return true if options.has_key?(:tooltip)
|
|
188
|
+
|
|
189
|
+
model.has_tooltip?
|
|
190
|
+
end
|
|
165
191
|
end
|
|
166
192
|
end
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
<%=
|
|
1
|
+
<%= content_tag :div, id: dom_id(resource), class: "card__search" do %>
|
|
2
2
|
<%= content_tag title_tag, class: "h4 card__search-title" do %>
|
|
3
|
-
<%=
|
|
3
|
+
<%= link_to resource_path, class: "card__search" do %>
|
|
4
|
+
<%= title %>
|
|
5
|
+
<% end %>
|
|
4
6
|
<% end %>
|
|
5
7
|
<% if metadata_cell.present? %>
|
|
6
8
|
<div class="card__search-metadata">
|
|
7
|
-
|
|
9
|
+
<%= cell metadata_cell, resource, links: false %>
|
|
8
10
|
</div>
|
|
9
11
|
<% end %>
|
|
10
12
|
<% end %>
|
|
@@ -71,6 +71,10 @@ module Decidim
|
|
|
71
71
|
|
|
72
72
|
# DiffRenderer class for the current_version's item; falls back to `BaseDiffRenderer`.
|
|
73
73
|
def diff_renderer_class
|
|
74
|
+
renderer_class = "#{current_version.item_type}DiffRenderer".safe_constantize
|
|
75
|
+
|
|
76
|
+
return renderer_class if renderer_class
|
|
77
|
+
|
|
74
78
|
if current_version.item_type.deconstantize == "Decidim"
|
|
75
79
|
"#{current_version.item_type.pluralize}::DiffRenderer".constantize
|
|
76
80
|
else
|
|
@@ -50,7 +50,7 @@ module Decidim
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def main_image_url
|
|
53
|
-
newsletter.template.images_container.attached_uploader(:main_image).url
|
|
53
|
+
newsletter.template.images_container.attached_uploader(:main_image).url
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def organization_primary_color
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
<div
|
|
2
|
-
<div class="
|
|
1
|
+
<div>
|
|
2
|
+
<div class="pt-4 pb-4 text-center bg-background">
|
|
3
3
|
<%= link %>
|
|
4
|
-
<span class="translation-button-help"><%= help_text %></span>
|
|
4
|
+
<span class="translation-button-help ml-4"><%= help_text %></span>
|
|
5
5
|
</div>
|
|
6
6
|
</div>
|
|
@@ -35,6 +35,9 @@ module Decidim
|
|
|
35
35
|
@user.name = ""
|
|
36
36
|
@user.nickname = ""
|
|
37
37
|
@user.email = ""
|
|
38
|
+
@user.personal_url = ""
|
|
39
|
+
@user.about = ""
|
|
40
|
+
@user.notifications_sending_frequency = "none"
|
|
38
41
|
@user.delete_reason = @form.delete_reason
|
|
39
42
|
@user.admin = false if @user.admin?
|
|
40
43
|
@user.deleted_at = Time.current
|
|
@@ -28,7 +28,7 @@ module Decidim
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def avatar_url
|
|
31
|
-
avatar_url = current_resource_owner.attached_uploader(:avatar).url
|
|
31
|
+
avatar_url = current_resource_owner.attached_uploader(:avatar).url
|
|
32
32
|
return unless avatar_url
|
|
33
33
|
|
|
34
34
|
unless %r{^https?://}.match? avatar_url
|
|
@@ -41,7 +41,7 @@ module Decidim
|
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
def escape_url(external_url)
|
|
44
|
-
before_fragment, fragment = external_url.split("#", 2)
|
|
44
|
+
before_fragment, fragment = URI.decode_www_form_component(external_url).split("#", 2)
|
|
45
45
|
escaped_before_fragment = URI::Parser.new.escape(before_fragment)
|
|
46
46
|
|
|
47
47
|
if fragment
|
|
@@ -27,6 +27,10 @@ module Decidim
|
|
|
27
27
|
redirect_to profile_activity_path(nickname: params[:nickname])
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
def tooltip
|
|
31
|
+
render json: { data: cell("decidim/author", profile_holder.presenter).profile_minicard }
|
|
32
|
+
end
|
|
33
|
+
|
|
30
34
|
def following
|
|
31
35
|
@content_cell = "decidim/following"
|
|
32
36
|
@title_key = "following"
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module UserRoleChecker
|
|
5
|
+
# Shared behaviour for signed_in admins
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def user_has_any_role?(user, participatory_space = nil, broad_check: false)
|
|
11
|
+
return false unless user
|
|
12
|
+
|
|
13
|
+
[
|
|
14
|
+
user.admin,
|
|
15
|
+
user.roles.any?,
|
|
16
|
+
participatory_process_user_role?(user, participatory_space, broad_check:),
|
|
17
|
+
assembly_user_role?(user, participatory_space, broad_check:),
|
|
18
|
+
conference_user_role?(user, participatory_space, broad_check:)
|
|
19
|
+
].any?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def participatory_process_user_role?(user, participatory_process = nil, broad_check: false)
|
|
23
|
+
return false unless Decidim.module_installed?(:participatory_processes)
|
|
24
|
+
return Decidim::ParticipatoryProcessUserRole.exists?(user:) if broad_check
|
|
25
|
+
return false unless participatory_process.is_a?(Decidim::ParticipatoryProcess)
|
|
26
|
+
|
|
27
|
+
Decidim::ParticipatoryProcessUserRole.exists?(user:, participatory_process:)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def assembly_user_role?(user, assembly = nil, broad_check: false)
|
|
31
|
+
return false unless Decidim.module_installed?(:assemblies)
|
|
32
|
+
return Decidim::AssemblyUserRole.exists?(user:) if broad_check
|
|
33
|
+
return false unless assembly.is_a?(Decidim::Assembly)
|
|
34
|
+
|
|
35
|
+
Decidim::AssemblyUserRole.exists?(user:, assembly:)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def conference_user_role?(user, conference = nil, broad_check: false)
|
|
39
|
+
return false unless Decidim.module_installed?(:conferences)
|
|
40
|
+
return Decidim::ConferenceUserRole.exists?(user:) if broad_check
|
|
41
|
+
return false unless conference.is_a?(Decidim::Conference)
|
|
42
|
+
|
|
43
|
+
Decidim::ConferenceUserRole.exists?(user:, conference:)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -16,7 +16,7 @@ module Decidim
|
|
|
16
16
|
# Finds the CTA button path to reuse it in other places.
|
|
17
17
|
def cta_button_path
|
|
18
18
|
if current_organization.cta_button_path.present?
|
|
19
|
-
current_organization.cta_button_path
|
|
19
|
+
"/#{current_organization.cta_button_path}"
|
|
20
20
|
elsif Decidim::ParticipatoryProcess.where(organization: current_organization).published.any?
|
|
21
21
|
decidim_participatory_processes.participatory_processes_path
|
|
22
22
|
elsif current_user
|
|
@@ -35,7 +35,12 @@ module Decidim
|
|
|
35
35
|
data: { "external-link": "text-only" }
|
|
36
36
|
}.merge(map_html_options)
|
|
37
37
|
return link_to(map_url, html_options) do
|
|
38
|
-
|
|
38
|
+
# We also add the latitude and the longitude to prevent the Workbox cache to be overly aggressive when updating a map
|
|
39
|
+
image_tag decidim.static_map_path(
|
|
40
|
+
sgid: resource.to_sgid.to_s,
|
|
41
|
+
latitude: resource.latitude,
|
|
42
|
+
longitude: resource.longitude
|
|
43
|
+
), alt: "#{map_service_brand} - #{address_text}"
|
|
39
44
|
end
|
|
40
45
|
end
|
|
41
46
|
end
|
|
@@ -37,13 +37,22 @@ module Decidim
|
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
# Converts the blob and blob variant references to blob URLs.
|
|
41
|
+
def decidim_rich_text(html, options = {})
|
|
42
|
+
renderer = Decidim::ContentProcessor.renderer_klass(:blob).constantize.new(html)
|
|
43
|
+
renderer.render(options)
|
|
44
|
+
end
|
|
45
|
+
|
|
40
46
|
def decidim_sanitize_editor(html, options = {})
|
|
41
47
|
content_tag(:div, decidim_sanitize(html, options), class: %w(rich-text-display))
|
|
42
48
|
end
|
|
43
49
|
|
|
44
50
|
def decidim_sanitize_editor_admin(html, options = {})
|
|
45
51
|
html = Decidim::IframeDisabler.new(html, options).perform
|
|
46
|
-
decidim_sanitize_editor(
|
|
52
|
+
decidim_sanitize_editor(
|
|
53
|
+
decidim_rich_text(html),
|
|
54
|
+
{ scrubber: Decidim::AdminInputScrubber.new }.merge(options)
|
|
55
|
+
)
|
|
47
56
|
end
|
|
48
57
|
|
|
49
58
|
def decidim_html_escape(text)
|
|
@@ -51,7 +60,7 @@ module Decidim
|
|
|
51
60
|
end
|
|
52
61
|
|
|
53
62
|
def decidim_url_escape(text)
|
|
54
|
-
decidim_html_escape(text).sub(
|
|
63
|
+
decidim_html_escape(text).sub(/^\s*javascript:/, "")
|
|
55
64
|
end
|
|
56
65
|
|
|
57
66
|
def decidim_sanitize_translated(text)
|
|
@@ -53,10 +53,18 @@ $(() => {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
$(document).on("click.zf.trigger", (event) => {
|
|
56
|
-
|
|
57
|
-
const
|
|
56
|
+
// Try to get the <a> directly or find the closest parent <a>
|
|
57
|
+
const $target = $(event.target).closest("a");
|
|
58
58
|
|
|
59
|
-
if
|
|
59
|
+
// Check if an <a> was found
|
|
60
|
+
if (!$target) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const dialogTarget = `#${$target.data("dialog-open")}`;
|
|
65
|
+
const redirectUrl = $target.data("redirectUrl");
|
|
66
|
+
|
|
67
|
+
if (!dialogTarget || !redirectUrl) {
|
|
60
68
|
return;
|
|
61
69
|
}
|
|
62
70
|
|
|
@@ -64,10 +72,10 @@ $(() => {
|
|
|
64
72
|
attr("id", "redirect_url").
|
|
65
73
|
attr("name", "redirect_url").
|
|
66
74
|
attr("value", redirectUrl).
|
|
67
|
-
appendTo(`${
|
|
75
|
+
appendTo(`${dialogTarget} form`);
|
|
68
76
|
|
|
69
|
-
$(`${
|
|
70
|
-
const querystring = jQuery.param({
|
|
77
|
+
$(`${dialogTarget} a`).attr("href", (index, href) => {
|
|
78
|
+
const querystring = jQuery.param({"redirect_url": redirectUrl});
|
|
71
79
|
return href + (href.match(/\?/) ? "&" : "?") + querystring;
|
|
72
80
|
});
|
|
73
81
|
});
|
|
@@ -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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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 (
|
|
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 =
|
|
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
|
|
@@ -68,6 +68,7 @@ import markAsReadNotifications from "src/decidim/notifications"
|
|
|
68
68
|
import RemoteModal from "src/decidim/remote_modal"
|
|
69
69
|
import selectActiveIdentity from "src/decidim/identity_selector_dialog"
|
|
70
70
|
import createTooltip from "src/decidim/tooltips"
|
|
71
|
+
import fetchRemoteTooltip from "src/decidim/remote_tooltips"
|
|
71
72
|
import createToggle from "src/decidim/toggle"
|
|
72
73
|
import {
|
|
73
74
|
createAccordion,
|
|
@@ -189,6 +190,8 @@ const initializer = (element = document) => {
|
|
|
189
190
|
// Initialize data-toggles
|
|
190
191
|
element.querySelectorAll("[data-toggle]").forEach((elem) => createToggle(elem))
|
|
191
192
|
|
|
193
|
+
element.querySelectorAll("[data-remote-tooltip]").forEach((elem) => fetchRemoteTooltip(elem))
|
|
194
|
+
|
|
192
195
|
element.querySelectorAll(".new_report").forEach((elem) => changeReportFormBehavior(elem))
|
|
193
196
|
}
|
|
194
197
|
|
|
@@ -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
|
+
}
|
|
@@ -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
|
|
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
|
-
|
|
67
|
-
|
|
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
|
-
|
|
115
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
}
|
|
@@ -37,7 +37,6 @@
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
.conference-diploma .diploma__logo {
|
|
40
|
-
border: 1px solid #333;
|
|
41
40
|
padding: 2rem;
|
|
42
41
|
}
|
|
43
42
|
|
|
@@ -47,10 +46,12 @@
|
|
|
47
46
|
max-height: 100%;
|
|
48
47
|
max-width: 100%;
|
|
49
48
|
margin: 0;
|
|
49
|
+
padding-top: 10%;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
.conference-diploma .diploma__border {
|
|
53
53
|
margin: 0;
|
|
54
|
+
margin-top: 15%;
|
|
54
55
|
-moz-border-image: url("../images/decidim/pattern.png") 20 repeat;
|
|
55
56
|
-webkit-border-image: url("../images/decidim/pattern.png") 20 repeat;
|
|
56
57
|
-o-border-image: url("../images/decidim/pattern.png") 20 repeat;
|
|
@@ -41,7 +41,7 @@ module Decidim
|
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
def parse_i18n_changeset(attribute, values, type, diff)
|
|
44
|
-
values.last.keys.each do |locale, _value|
|
|
44
|
+
(values.last.keys - ["machine_translations"]).each do |locale, _value|
|
|
45
45
|
first_value = values.first.try(:[], locale)
|
|
46
46
|
last_value = values.last.try(:[], locale)
|
|
47
47
|
next if first_value == last_value
|
|
@@ -56,6 +56,27 @@ module Decidim
|
|
|
56
56
|
}
|
|
57
57
|
)
|
|
58
58
|
end
|
|
59
|
+
|
|
60
|
+
return diff unless values.last.has_key?("machine_translations")
|
|
61
|
+
|
|
62
|
+
values.last.fetch("machine_translations").each_key do |locale, _value|
|
|
63
|
+
next unless I18n.available_locales.include?(locale.to_sym)
|
|
64
|
+
|
|
65
|
+
first_value = values.first.try(:[], "machine_translations").try(:[], locale)
|
|
66
|
+
last_value = values.last.try(:[], "machine_translations").try(:[], locale)
|
|
67
|
+
|
|
68
|
+
attribute_locale = :"#{attribute}_machine_translations_#{locale}"
|
|
69
|
+
|
|
70
|
+
diff.update(
|
|
71
|
+
attribute_locale => {
|
|
72
|
+
type:,
|
|
73
|
+
label: generate_i18n_label(attribute, locale, "decidim.machine_translations.automatic"),
|
|
74
|
+
old_value: first_value,
|
|
75
|
+
new_value: last_value
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
end
|
|
79
|
+
|
|
59
80
|
diff
|
|
60
81
|
end
|
|
61
82
|
|
|
@@ -108,7 +129,8 @@ module Decidim
|
|
|
108
129
|
end
|
|
109
130
|
|
|
110
131
|
# Returns a String.
|
|
111
|
-
|
|
132
|
+
# i18n-tasks-use t("decidim.machine_translations.automatic")
|
|
133
|
+
def generate_i18n_label(attribute, locale, postfix = "")
|
|
112
134
|
label = I18n.t(attribute, scope: i18n_scope)
|
|
113
135
|
locale_name = if I18n.available_locales.include?(locale.to_sym)
|
|
114
136
|
I18n.t("locale.name", locale:)
|
|
@@ -116,6 +138,8 @@ module Decidim
|
|
|
116
138
|
locale
|
|
117
139
|
end
|
|
118
140
|
|
|
141
|
+
locale_name = I18n.t(postfix, locale_name:, locale:) if postfix.present?
|
|
142
|
+
|
|
119
143
|
"#{label} (#{locale_name})"
|
|
120
144
|
end
|
|
121
145
|
|