decidim-core 0.29.1 → 0.29.2
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 +0 -3
- 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 +2 -2
- 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/_labels.scss +1 -1
- 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 +16 -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 +18 -14
- data/config/locales/el.yml +7 -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 +6 -2
- data/config/locales/fr.yml +5 -1
- data/config/locales/ga-IE.yml +9 -0
- data/config/locales/gl.yml +8 -0
- data/config/locales/hu.yml +3 -3
- data/config/locales/id-ID.yml +8 -0
- data/config/locales/is-IS.yml +8 -1
- data/config/locales/it.yml +19 -0
- data/config/locales/ja.yml +15 -13
- data/config/locales/lb.yml +9 -0
- data/config/locales/lt.yml +5 -1
- data/config/locales/lv.yml +8 -0
- data/config/locales/nl.yml +10 -1
- data/config/locales/no.yml +9 -0
- data/config/locales/pl.yml +1 -1
- data/config/locales/pt-BR.yml +2 -1
- data/config/locales/pt.yml +14 -0
- data/config/locales/ro-RO.yml +258 -135
- data/config/locales/ru.yml +8 -0
- data/config/locales/sk.yml +9 -1
- data/config/locales/sv.yml +7 -7
- data/config/locales/tr-TR.yml +10 -1
- data/config/locales/uk.yml +8 -1
- data/config/locales/zh-CN.yml +9 -0
- data/config/locales/zh-TW.yml +8 -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: 83ba22655575833dce2ce20e91060aa195abccf10cd5d185dbadbc04e79fcd93
|
|
4
|
+
data.tar.gz: a53c89d6b0c01046408b2872119406ffbd1a80a50b943256b872c8575b069e4a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 07db0787cc696b27044eb8765477b338a16f7263cd29d9231dfd8e7145f5c4b63b19753a90b4d35c5e7614c1a69d47104435fcb2ecf12badea9a1163709ccbef
|
|
7
|
+
data.tar.gz: 034e07f956b0ad613172afdd3a56cbb3e37e273555537919073bf75b63dfe8b2ab7ec5502ecf87fb224cd5d525ad009a01e0db6742815ce61eec643c0fa1f1ae
|
|
@@ -105,9 +105,6 @@ module Decidim
|
|
|
105
105
|
hash << I18n.locale.to_s
|
|
106
106
|
hash << model.class.name.underscore
|
|
107
107
|
hash << model.cache_key_with_version if model.respond_to?(:cache_key_with_version)
|
|
108
|
-
if (author_cell = author)
|
|
109
|
-
hash.push(Digest::MD5.hexdigest(author_cell.send(:cache_hash)))
|
|
110
|
-
end
|
|
111
108
|
|
|
112
109
|
hash.join(Decidim.cache_key_separator)
|
|
113
110
|
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 %>
|
|
@@ -47,8 +47,26 @@ module Decidim
|
|
|
47
47
|
@context_actions_options ||= options[:context_actions].map(&:to_sym)
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
def profile_minicard
|
|
51
|
+
render
|
|
52
|
+
end
|
|
53
|
+
|
|
50
54
|
private
|
|
51
55
|
|
|
56
|
+
# If the options hash has the demo key it means we are in the decidim-design engine,
|
|
57
|
+
# so it is not a real-world scenario with actual users
|
|
58
|
+
def data
|
|
59
|
+
@data ||= begin
|
|
60
|
+
internal_data = { author: true }
|
|
61
|
+
if has_tooltip? && !options.has_key?(:demo)
|
|
62
|
+
internal_data["remote_tooltip"] = true
|
|
63
|
+
internal_data["tooltip-url"] = decidim.profile_tooltip_path(raw_model.nickname)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
internal_data
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
52
70
|
def layout
|
|
53
71
|
@layout ||= LAYOUTS.include?(options[:layout]) ? options[:layout] : :default
|
|
54
72
|
end
|
|
@@ -160,5 +178,13 @@ module Decidim
|
|
|
160
178
|
def resource_name
|
|
161
179
|
@resource_name ||= from_context.class.name.demodulize.underscore
|
|
162
180
|
end
|
|
181
|
+
|
|
182
|
+
def has_tooltip?
|
|
183
|
+
return false if model.deleted?
|
|
184
|
+
return false if model.respond_to?(:blocked?) && model.blocked?
|
|
185
|
+
return true if options.has_key?(:tooltip)
|
|
186
|
+
|
|
187
|
+
model.has_tooltip?
|
|
188
|
+
end
|
|
163
189
|
end
|
|
164
190
|
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 %>
|
|
@@ -70,6 +70,10 @@ module Decidim
|
|
|
70
70
|
|
|
71
71
|
# DiffRenderer class for the current_version's item; falls back to `BaseDiffRenderer`.
|
|
72
72
|
def diff_renderer_class
|
|
73
|
+
renderer_class = "#{current_version.item_type}DiffRenderer".safe_constantize
|
|
74
|
+
|
|
75
|
+
return renderer_class if renderer_class
|
|
76
|
+
|
|
73
77
|
if current_version.item_type.deconstantize == "Decidim"
|
|
74
78
|
"#{current_version.item_type.pluralize}::DiffRenderer".constantize
|
|
75
79
|
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
|
|
@@ -37,6 +37,9 @@ module Decidim
|
|
|
37
37
|
current_user.name = ""
|
|
38
38
|
current_user.nickname = ""
|
|
39
39
|
current_user.email = ""
|
|
40
|
+
current_user.personal_url = ""
|
|
41
|
+
current_user.about = ""
|
|
42
|
+
current_user.notifications_sending_frequency = "none"
|
|
40
43
|
current_user.delete_reason = @form.delete_reason
|
|
41
44
|
current_user.admin = false if current_user.admin?
|
|
42
45
|
current_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, **)
|
|
42
|
+
renderer = Decidim::ContentProcessor.renderer_klass(:blob).constantize.new(html)
|
|
43
|
+
renderer.render(**)
|
|
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
|
|
@@ -69,6 +69,7 @@ import handleNotificationActions from "src/decidim/notifications_actions"
|
|
|
69
69
|
import RemoteModal from "src/decidim/remote_modal"
|
|
70
70
|
import selectActiveIdentity from "src/decidim/identity_selector_dialog"
|
|
71
71
|
import createTooltip from "src/decidim/tooltips"
|
|
72
|
+
import fetchRemoteTooltip from "src/decidim/remote_tooltips"
|
|
72
73
|
import createToggle from "src/decidim/toggle"
|
|
73
74
|
import {
|
|
74
75
|
createAccordion,
|
|
@@ -195,6 +196,8 @@ const initializer = (element = document) => {
|
|
|
195
196
|
// Initialize data-toggles
|
|
196
197
|
element.querySelectorAll("[data-toggle]").forEach((elem) => createToggle(elem))
|
|
197
198
|
|
|
199
|
+
element.querySelectorAll("[data-remote-tooltip]").forEach((elem) => fetchRemoteTooltip(elem))
|
|
200
|
+
|
|
198
201
|
element.querySelectorAll(".new_report").forEach((elem) => changeReportFormBehavior(elem))
|
|
199
202
|
}
|
|
200
203
|
|
|
@@ -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
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
--warning: #ad4910;
|
|
7
7
|
--bg-warning: #ffeebd;
|
|
8
8
|
|
|
9
|
-
@apply bg-background text-gray-2 rounded inline-flex items-center gap-1 px-2 font-semibold text-sm;
|
|
9
|
+
@apply bg-background text-gray-2 rounded inline-flex items-center gap-1 px-2 py-1 h-min font-semibold text-sm;
|
|
10
10
|
|
|
11
11
|
&.success {
|
|
12
12
|
@apply bg-[var(--bg-success)] text-[var(--success)];
|
|
@@ -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;
|