decidim-core 0.31.1 → 0.31.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/announcement_cell.rb +10 -2
- data/app/cells/decidim/attachments_file_tab/show.erb +1 -1
- data/app/cells/decidim/content_blocks/participatory_space_metadata/content.erb +2 -2
- data/app/cells/decidim/nav_links/show.erb +3 -3
- data/app/cells/decidim/statistic/show.erb +6 -6
- data/app/cells/decidim/upload_modal/files.erb +12 -8
- data/app/cells/decidim/upload_modal_cell.rb +11 -4
- data/app/controllers/concerns/decidim/direct_upload.rb +2 -12
- data/app/controllers/decidim/devise/sessions_controller.rb +7 -0
- data/app/helpers/concerns/decidim/flash_helper_extensions.rb +2 -2
- data/app/jobs/decidim/export_participatory_space_job.rb +1 -1
- data/app/models/decidim/attachment.rb +22 -1
- data/app/packs/src/decidim/controllers/account_form/controller.js +8 -0
- data/app/packs/src/decidim/controllers/language_change/controller.js +38 -0
- data/app/packs/src/decidim/controllers/language_change/language_change.test.js +105 -0
- data/app/packs/src/decidim/direct_uploads/upload_field.js +1 -1
- data/app/packs/stylesheets/decidim/_flash.scss +1 -1
- data/app/packs/stylesheets/decidim/_modal_update.scss +1 -1
- data/app/packs/stylesheets/decidim/_participatory_spaces.scss +1 -1
- data/app/services/decidim/open_data_exporter.rb +1 -1
- data/app/views/layouts/decidim/header/_main_links_mobile_account.html.erb +1 -1
- data/config/locales/ca-IT.yml +5 -0
- data/config/locales/ca.yml +5 -0
- data/config/locales/cs.yml +37 -0
- data/config/locales/el.yml +1 -0
- data/config/locales/en.yml +5 -0
- data/config/locales/es-MX.yml +5 -0
- data/config/locales/es-PY.yml +5 -0
- data/config/locales/es.yml +5 -0
- data/config/locales/eu.yml +8 -4
- data/config/locales/fr-CA.yml +4 -0
- data/config/locales/fr.yml +5 -0
- data/config/locales/ja.yml +4 -0
- data/config/locales/ro-RO.yml +4 -1
- data/config/locales/sv.yml +284 -43
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/form_builder.rb +41 -7
- metadata +8 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d24b967768820d8eb01abd435e318b7a869af854b0f374ca54c54a6dddbdddb6
|
|
4
|
+
data.tar.gz: f4374ee02ae0c5c9a580c8ad1c371c6552719be39b40e22cdf3d37018464950c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a4baebaa527bd42897989aee6feeb29b4bf2773872b3bb7f8379a230111a94f0ee8565e15b02599fb6a1c20bb83a24feed96707448eecc70b866d74a8dd34bec
|
|
7
|
+
data.tar.gz: 47436bb0abfd556afcebe781b153aaaa9e960653be07fdf19486f11d82bfc40b61472dc24cfbc397838b19638a395bbad3dc3af8e1d791b2277412b3b56e719d
|
|
@@ -68,15 +68,23 @@ module Decidim
|
|
|
68
68
|
def clean_body
|
|
69
69
|
return unless body
|
|
70
70
|
|
|
71
|
-
Array(body).map { |paragraph|
|
|
71
|
+
Array(body).map { |paragraph| clean(paragraph) }.join
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
def clean_announcement
|
|
75
|
+
return if announcement.is_a?(Hash) && announcement.values.all?(&:blank?)
|
|
76
|
+
|
|
75
77
|
clean(announcement)
|
|
76
78
|
end
|
|
77
79
|
|
|
78
80
|
def clean(value)
|
|
79
|
-
|
|
81
|
+
return if value.blank? || value.nil?
|
|
82
|
+
|
|
83
|
+
if value.include?("rich-text-display")
|
|
84
|
+
decidim_sanitize_admin(translated_attribute(value))
|
|
85
|
+
else
|
|
86
|
+
tag.p(decidim_sanitize_admin(translated_attribute(value)))
|
|
87
|
+
end
|
|
80
88
|
end
|
|
81
89
|
end
|
|
82
90
|
end
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
<div class="row column">
|
|
2
|
-
<%= form.upload :file, button_class: "button button__sm button__transparent-secondary" %>
|
|
2
|
+
<%= form.upload :file, attachments: form.object.file.present? ? [form.object.file] : [], button_class: "button button__sm button__transparent-secondary" %>
|
|
3
3
|
</div>
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
<% metadata_valued_items.each do |item| %>
|
|
3
3
|
<div class="participatory-space__metadata-item">
|
|
4
4
|
<div class="participatory-space__metadata-item-title">
|
|
5
|
-
<
|
|
5
|
+
<p><%= item[:title] %></p>
|
|
6
6
|
</div>
|
|
7
|
-
<
|
|
7
|
+
<p><%= item[:value] %></p>
|
|
8
8
|
</div>
|
|
9
9
|
<% end %>
|
|
10
10
|
</div>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<div class="participatory-space__nav-container">
|
|
2
|
-
<button id="dropdown-trigger-participatory-space" data-controller="dropdown" data-target="dropdown-menu-participatory-space" data-auto-close="true" data-scroll-to-menu="true"
|
|
2
|
+
<button id="dropdown-trigger-participatory-space" data-controller="dropdown" data-target="dropdown-menu-participatory-space" data-auto-close="true" data-scroll-to-menu="true">
|
|
3
3
|
<span><%= t("decidim.searches.filters.jump_to") %></span>
|
|
4
4
|
<%= icon "arrow-down-s-line" %>
|
|
5
5
|
<%= icon "arrow-up-s-line" %>
|
|
6
6
|
</button>
|
|
7
|
-
<ul id="dropdown-menu-participatory-space" class="participatory-space__nav">
|
|
7
|
+
<ul id="dropdown-menu-participatory-space" class="participatory-space__nav" aria-hidden="true">
|
|
8
8
|
<% model.each do |item| %>
|
|
9
9
|
<li role="menuitem">
|
|
10
10
|
<%= link_to item[:url], class: "participatory-space__nav-item" do %>
|
|
11
|
-
<%= item[:name] %>
|
|
11
|
+
<%= decidim_escape_translated(item[:name]) %>
|
|
12
12
|
<%= icon "arrow-right-line" %>
|
|
13
13
|
<% end %>
|
|
14
14
|
</li>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<div class="statistic <%= stat_dom_class %>" data-statistic>
|
|
2
2
|
<div class="statistic__header">
|
|
3
3
|
<div class="statistic__metric">
|
|
4
|
-
<
|
|
4
|
+
<p class="statistic__title" title="<%= stat_title %>">
|
|
5
5
|
<%= stat_title %>
|
|
6
|
-
</
|
|
6
|
+
</p>
|
|
7
7
|
<div class="statistic__tooltip">
|
|
8
8
|
<%= information_tooltip %>
|
|
9
9
|
</div>
|
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
</div>
|
|
14
14
|
</div>
|
|
15
15
|
<% if second_stat_number %>
|
|
16
|
-
<
|
|
16
|
+
<p class="statistic__second-number">
|
|
17
17
|
<%= stat_sub_title %>
|
|
18
18
|
<span class="font-semibold"><%= second_stat_number %></span>
|
|
19
|
-
</
|
|
19
|
+
</p>
|
|
20
20
|
<% else %>
|
|
21
21
|
<p class="h-[21px]"></p>
|
|
22
22
|
<% end %>
|
|
23
|
-
<
|
|
23
|
+
<p class="statistic__number">
|
|
24
24
|
<%= stat_number %>
|
|
25
|
-
</
|
|
25
|
+
</p>
|
|
26
26
|
</div>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<div class="upload-modal__files-container upload-container-for-<%= attribute %> <%= with_title %>">
|
|
2
2
|
<div>
|
|
3
|
-
<%= label %>
|
|
3
|
+
<%= options[:paragraph] == true ? paragraph : label %>
|
|
4
4
|
|
|
5
5
|
<% if options[:help_text].present? %>
|
|
6
|
-
<
|
|
6
|
+
<p class="help-text"><%= options[:help_text] %></p>
|
|
7
7
|
<% end %>
|
|
8
8
|
|
|
9
9
|
<%# NOTE: this block is about wrapping a default image for the avatar with the new styles,
|
|
@@ -22,24 +22,28 @@
|
|
|
22
22
|
<div class="upload-modal__files" data-active-uploads="<%= modal_id %>">
|
|
23
23
|
<% attachments.each do |attachment| %>
|
|
24
24
|
<% next if [Array, Hash].any? { |klass| attachment.is_a? klass } %>
|
|
25
|
+
<% is_persisted_attachment = attachment.is_a?(Decidim::Attachment) && attachment.persisted? %>
|
|
26
|
+
<% attachment_blob = blob(attachment) %>
|
|
25
27
|
|
|
26
|
-
<div class="attachment-details" data-attachment-id="<%= attachment.id %>" data-title="<%= title_for(attachment) %>" data-filename="<%= file_name_for(attachment) %>" data-state="uploaded">
|
|
27
|
-
<% if file_attachment_path(attachment) &&
|
|
28
|
+
<div class="attachment-details"<% if is_persisted_attachment %> data-attachment-id="<%= attachment.id %>"<% end %> data-title="<%= title_for(attachment) %>" data-filename="<%= file_name_for(attachment) %>" data-state="uploaded" data-hidden-field="<%= attachment_blob&.signed_id %>">
|
|
29
|
+
<% if file_attachment_path(attachment) && attachment_blob&.image? %>
|
|
28
30
|
<div><%= image_tag(file_attachment_path(attachment), alt: "") %></div>
|
|
29
31
|
<% elsif uploader_default_image_path(attribute).present? %>
|
|
30
32
|
<div><%= image_tag uploader_default_image_path(attribute) %></div>
|
|
31
33
|
<% end %>
|
|
32
34
|
|
|
33
35
|
<% if has_title? %>
|
|
34
|
-
<
|
|
35
|
-
<%= form.hidden_field attribute, multiple: true, value: attachment.id, id: attachment.id %>
|
|
36
|
+
<p><%= title_for(attachment) %></p>
|
|
36
37
|
<% else %>
|
|
37
|
-
<% if
|
|
38
|
-
<
|
|
38
|
+
<% if attachment_blob&.image? %>
|
|
39
|
+
<p><%= title_for(attachment) %></p>
|
|
39
40
|
<% else %>
|
|
40
41
|
<%= link_to title_for(attachment), file_attachment_path(attachment), class: "w-full break-all mb-2" %>
|
|
41
42
|
<% end %>
|
|
42
43
|
<% end %>
|
|
44
|
+
<% if attachment_blob.present? %>
|
|
45
|
+
<%= form.hidden_field attribute, value: attachment_blob.signed_id, id: "hidden_#{attribute}_#{attachment_blob.id}" %>
|
|
46
|
+
<% end %>
|
|
43
47
|
</div>
|
|
44
48
|
<% end %>
|
|
45
49
|
</div>
|
|
@@ -30,6 +30,10 @@ module Decidim
|
|
|
30
30
|
form.send(:custom_label, attribute, options[:label], { required: required?, for: nil })
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
def paragraph
|
|
34
|
+
form.send(:custom_paragraph, attribute, options[:label], { required: required? })
|
|
35
|
+
end
|
|
36
|
+
|
|
33
37
|
def button_label
|
|
34
38
|
return button_edit_label if attachments.count.positive?
|
|
35
39
|
|
|
@@ -71,13 +75,16 @@ module Decidim
|
|
|
71
75
|
end
|
|
72
76
|
|
|
73
77
|
# By default FoundationRailsHelper adds form errors next to input, but since input is in the modal
|
|
74
|
-
# and modal is hidden by default, we
|
|
78
|
+
# and modal is hidden by default, we add a hidden checkbox field to handle HTML5 validation.
|
|
75
79
|
# This should only be necessary when file is required by the form.
|
|
80
|
+
# Note: Validation errors are now displayed in the main form area, not inside the modal.
|
|
76
81
|
def input_validation_field
|
|
77
82
|
object_name = form.object.present? ? "#{form.object.model_name.param_key}[#{add_attribute}_validation]" : "#{add_attribute}_validation"
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
83
|
+
check_box_tag object_name, 1, attachments.present?, class: "reset-defaults", hidden: true, label: false, required: required?, id: validation_field_id
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def validation_field_id
|
|
87
|
+
"#{attribute}_validation"
|
|
81
88
|
end
|
|
82
89
|
|
|
83
90
|
def explanation
|
|
@@ -9,8 +9,6 @@ module Decidim
|
|
|
9
9
|
skip_before_action :verify_organization
|
|
10
10
|
|
|
11
11
|
before_action :check_organization!,
|
|
12
|
-
:check_authenticated!,
|
|
13
|
-
:check_user_belongs_to_organization,
|
|
14
12
|
:validate_direct_upload
|
|
15
13
|
end
|
|
16
14
|
|
|
@@ -42,16 +40,6 @@ module Decidim
|
|
|
42
40
|
head :unauthorized if current_organization.blank? && current_admin.blank?
|
|
43
41
|
end
|
|
44
42
|
|
|
45
|
-
def check_authenticated!
|
|
46
|
-
head :unauthorized if current_user.blank? && current_admin.blank?
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def check_user_belongs_to_organization
|
|
50
|
-
return if current_admin.present?
|
|
51
|
-
|
|
52
|
-
head :unauthorized unless current_organization == current_user.organization
|
|
53
|
-
end
|
|
54
|
-
|
|
55
43
|
def allowed_extensions
|
|
56
44
|
if user_has_elevated_role?
|
|
57
45
|
current_organization.settings.upload_allowed_file_extensions_admin
|
|
@@ -71,6 +59,8 @@ module Decidim
|
|
|
71
59
|
private
|
|
72
60
|
|
|
73
61
|
def user_has_elevated_role?
|
|
62
|
+
return false if current_user.blank? || current_organization.blank? || current_user.organization != current_organization
|
|
63
|
+
|
|
74
64
|
[
|
|
75
65
|
current_user&.admin?,
|
|
76
66
|
defined?(Decidim::Assemblies::AssembliesWithUserRole) && Decidim::Assemblies::AssembliesWithUserRole.for(current_user).any?,
|
|
@@ -9,6 +9,8 @@ module Decidim
|
|
|
9
9
|
|
|
10
10
|
before_action :check_sign_in_enabled, only: :create
|
|
11
11
|
|
|
12
|
+
rescue_from ActionController::InvalidAuthenticityToken, with: :redirect_to_referer_or_path
|
|
13
|
+
|
|
12
14
|
def create
|
|
13
15
|
super do |user|
|
|
14
16
|
if user.admin?
|
|
@@ -44,6 +46,11 @@ module Decidim
|
|
|
44
46
|
|
|
45
47
|
private
|
|
46
48
|
|
|
49
|
+
def redirect_to_referer_or_path
|
|
50
|
+
set_flash_message(:alert, "csrf_token", scope: "devise.failure")
|
|
51
|
+
redirect_back(fallback_location: root_path) && return
|
|
52
|
+
end
|
|
53
|
+
|
|
47
54
|
def check_sign_in_enabled
|
|
48
55
|
redirect_to new_user_session_path unless current_organization.sign_in_enabled?
|
|
49
56
|
end
|
|
@@ -117,9 +117,9 @@ module Decidim
|
|
|
117
117
|
end
|
|
118
118
|
|
|
119
119
|
def message(value)
|
|
120
|
-
return content_tag(:
|
|
120
|
+
return content_tag(:p, value, class: "flash__message") unless value.is_a?(Hash)
|
|
121
121
|
|
|
122
|
-
content_tag(:
|
|
122
|
+
content_tag(:p, class: "flash__message") do
|
|
123
123
|
concat value[:title]
|
|
124
124
|
concat content_tag(:span, value[:body], class: "flash__message-body")
|
|
125
125
|
end
|
|
@@ -11,7 +11,7 @@ module Decidim
|
|
|
11
11
|
manifest.name == name.to_sym
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
collection = export_manifest.collection.call(participatory_space)
|
|
14
|
+
collection = export_manifest.collection.call(participatory_space, user)
|
|
15
15
|
serializer = export_manifest.serializer
|
|
16
16
|
|
|
17
17
|
export_data = Decidim::Exporters.find_exporter(format).new(collection, serializer).export
|
|
@@ -9,7 +9,7 @@ module Decidim
|
|
|
9
9
|
include Traceable
|
|
10
10
|
|
|
11
11
|
before_save :set_content_type_and_size, if: :attached?
|
|
12
|
-
before_validation :set_link_content_type_and_size, if: :
|
|
12
|
+
before_validation :set_link_content_type_and_size, if: :editable_link?
|
|
13
13
|
|
|
14
14
|
translatable_fields :title, :description
|
|
15
15
|
belongs_to :attachment_collection, class_name: "Decidim::AttachmentCollection", optional: true
|
|
@@ -69,6 +69,20 @@ module Decidim
|
|
|
69
69
|
link.present?
|
|
70
70
|
end
|
|
71
71
|
|
|
72
|
+
# Whether this attachment is a link that can be edited or not.
|
|
73
|
+
#
|
|
74
|
+
# Returns Boolean.
|
|
75
|
+
def editable_link?
|
|
76
|
+
!destroyed? && !frozen? && link?
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Whether this attachment has a file or not.
|
|
80
|
+
#
|
|
81
|
+
# Returns Boolean.
|
|
82
|
+
def file?
|
|
83
|
+
file.attached?
|
|
84
|
+
end
|
|
85
|
+
|
|
72
86
|
# Which kind of file this is.
|
|
73
87
|
#
|
|
74
88
|
# Returns String.
|
|
@@ -123,5 +137,12 @@ module Decidim
|
|
|
123
137
|
def self.log_presenter_class_for(_log)
|
|
124
138
|
Decidim::AdminLog::AttachmentPresenter
|
|
125
139
|
end
|
|
140
|
+
|
|
141
|
+
def can_participate?(user)
|
|
142
|
+
return true unless attached_to
|
|
143
|
+
return true unless attached_to.respond_to?(:can_participate?)
|
|
144
|
+
|
|
145
|
+
attached_to.can_participate?(user)
|
|
146
|
+
end
|
|
126
147
|
end
|
|
127
148
|
end
|
|
@@ -42,6 +42,10 @@ export default class extends Controller {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
setupMutationObserver() {
|
|
45
|
+
if (!this.newPasswordPanel) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
45
49
|
this.observer = new MutationObserver(() => {
|
|
46
50
|
let ariaHiddenValue = this.newPasswordPanel.getAttribute("aria-hidden");
|
|
47
51
|
this.newPwVisible = ariaHiddenValue === "false";
|
|
@@ -54,6 +58,10 @@ export default class extends Controller {
|
|
|
54
58
|
}
|
|
55
59
|
|
|
56
60
|
setupEmailChangeListener() {
|
|
61
|
+
if (!this.emailField) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
57
65
|
this.emailField.addEventListener("change", () => {
|
|
58
66
|
this.emailChanged = this.emailField.value !== this.originalEmail;
|
|
59
67
|
this.toggleOldPassword();
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This controller is used to change the active tab when the language is changed in the admin or system panel.
|
|
5
|
+
* It uses a select element to list the languages available in the platform and adds an observer that would set
|
|
6
|
+
* the tab the active tab to what is selected in the select element by toggling the aria-hidden attribute on the
|
|
7
|
+
* tab container.
|
|
8
|
+
*/
|
|
9
|
+
export default class extends Controller {
|
|
10
|
+
connect() {
|
|
11
|
+
this.handleChange = this.handleChange.bind(this);
|
|
12
|
+
this.element.addEventListener("change", this.handleChange);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
disconnect() {
|
|
16
|
+
this.element.removeEventListener("change", this.handleChange)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
handleChange(event) {
|
|
20
|
+
let targetTabPaneSelector = event.target.value;
|
|
21
|
+
let tabsContent = event.target.parentElement.parentElement.nextElementSibling;
|
|
22
|
+
|
|
23
|
+
if (!tabsContent) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let activeTabContent = tabsContent.querySelector(".is-active");
|
|
28
|
+
if (activeTabContent) {
|
|
29
|
+
activeTabContent.ariaHidden = "true";
|
|
30
|
+
activeTabContent.classList.remove("is-active");
|
|
31
|
+
}
|
|
32
|
+
let activePane = tabsContent.querySelector(targetTabPaneSelector);
|
|
33
|
+
if (activePane) {
|
|
34
|
+
activePane.ariaHidden = "false";
|
|
35
|
+
activePane.classList.add("is-active");
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/* global jest */
|
|
2
|
+
/* eslint max-lines: ["error", 360] */
|
|
3
|
+
import { Application } from "@hotwired/stimulus"
|
|
4
|
+
import LanguageChangeController from "src/decidim/controllers/language_change/controller";
|
|
5
|
+
|
|
6
|
+
describe("LanguageChangeController", () => {
|
|
7
|
+
let application = null;
|
|
8
|
+
let controller = null;
|
|
9
|
+
let selectElement = null;
|
|
10
|
+
let tabsContent = null;
|
|
11
|
+
let panel0 = null;
|
|
12
|
+
let panel1 = null;
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
application = Application.start();
|
|
16
|
+
application.register("language-change", LanguageChangeController);
|
|
17
|
+
|
|
18
|
+
document.body.innerHTML = `
|
|
19
|
+
<div class="label--tabs">
|
|
20
|
+
<label for="update_organization_name">Name</label>
|
|
21
|
+
<div>
|
|
22
|
+
<select id="update_organization-name-tabs" class="language-change" data-controller="language-change">
|
|
23
|
+
<option value="#update_organization-name-tabs-name-panel-0">English</option>
|
|
24
|
+
<option value="#update_organization-name-tabs-name-panel-1">Bulgarian</option>
|
|
25
|
+
</select>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
<div class="tabs-content" data-tabs-content="update_organization-name-tabs">
|
|
29
|
+
<div class="tabs-panel is-active" id="update_organization-name-tabs-name-panel-0" aria-hidden="false">
|
|
30
|
+
<input type="text" value="Example" name="update_organization[name_en]" id="update_organization_name_en">
|
|
31
|
+
</div>
|
|
32
|
+
<div class="tabs-panel" id="update_organization-name-tabs-name-panel-1" aria-hidden="true">
|
|
33
|
+
<input type="text" value="Example BG" name="update_organization[name_bg]" id="update_organization_name_bg">
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
selectElement = document.querySelector("select[data-controller='language-change']");
|
|
39
|
+
tabsContent = document.querySelector(".tabs-content");
|
|
40
|
+
panel0 = document.querySelector("#update_organization-name-tabs-name-panel-0");
|
|
41
|
+
panel1 = document.querySelector("#update_organization-name-tabs-name-panel-1");
|
|
42
|
+
|
|
43
|
+
return new Promise((resolve) => {
|
|
44
|
+
setTimeout(() => {
|
|
45
|
+
controller = application.getControllerForElementAndIdentifier(selectElement, "language-change");
|
|
46
|
+
resolve();
|
|
47
|
+
}, 0);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
afterEach(() => {
|
|
52
|
+
application.stop();
|
|
53
|
+
document.body.innerHTML = "";
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe("connect / disconnect", () => {
|
|
57
|
+
it("adds a change listener on connect", () => {
|
|
58
|
+
const addSpy = jest.spyOn(selectElement, "addEventListener");
|
|
59
|
+
|
|
60
|
+
controller.disconnect();
|
|
61
|
+
controller.connect();
|
|
62
|
+
|
|
63
|
+
expect(addSpy).toHaveBeenCalledWith("change", expect.any(Function));
|
|
64
|
+
addSpy.mockRestore();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("removes the change listener on disconnect", () => {
|
|
68
|
+
const removeSpy = jest.spyOn(selectElement, "removeEventListener");
|
|
69
|
+
|
|
70
|
+
controller.disconnect();
|
|
71
|
+
|
|
72
|
+
expect(removeSpy).toHaveBeenCalledWith("change", controller.handleChange);
|
|
73
|
+
removeSpy.mockRestore();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe("handleChange", () => {
|
|
78
|
+
it("toggles active tab panel and aria-hidden", () => {
|
|
79
|
+
selectElement.value = "#update_organization-name-tabs-name-panel-1";
|
|
80
|
+
|
|
81
|
+
controller.handleChange({ target: selectElement });
|
|
82
|
+
|
|
83
|
+
expect(panel0.classList.contains("is-active")).toBe(false);
|
|
84
|
+
expect(panel0.ariaHidden).toBe("true");
|
|
85
|
+
expect(panel1.classList.contains("is-active")).toBe(true);
|
|
86
|
+
expect(panel1.ariaHidden).toBe("false");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("does nothing when tabs content is missing", () => {
|
|
90
|
+
tabsContent.remove();
|
|
91
|
+
|
|
92
|
+
expect(() => controller.handleChange({ target: selectElement })).not.toThrow();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("activates the target panel when no panel is active", () => {
|
|
96
|
+
panel0.classList.remove("is-active");
|
|
97
|
+
|
|
98
|
+
selectElement.value = "#update_organization-name-tabs-name-panel-1";
|
|
99
|
+
controller.handleChange({ target: selectElement });
|
|
100
|
+
|
|
101
|
+
expect(panel1.classList.contains("is-active")).toBe(true);
|
|
102
|
+
expect(panel1.ariaHidden).toBe("false");
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
});
|
|
@@ -79,7 +79,7 @@ const updateActiveUploads = (modal) => {
|
|
|
79
79
|
const template = `
|
|
80
80
|
<div ${attachmentIdOrHiddenField} data-filename="${escapeQuotes(file.name)}" data-title="${escapeQuotes(title)}">
|
|
81
81
|
${(/image/).test(file.type) && "<div><img src=\"data:,\" role=\"presentation\" /></div>" || ""}
|
|
82
|
-
<
|
|
82
|
+
<p>${escapeHtml(title)}</p>
|
|
83
83
|
${hidden}
|
|
84
84
|
</div>
|
|
85
85
|
`
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
@apply divide-y divide-white [&>li]:py-3.5 first:[&>li]:pt-0 last:[&>li]:pb-0;
|
|
100
100
|
|
|
101
101
|
&-container {
|
|
102
|
-
@apply ml-0 md:ml-6 bg-primary p-3 md:p-6 rounded w-full md:w-auto self-start;
|
|
102
|
+
@apply mb-8 ml-0 md:ml-6 bg-primary p-3 md:p-6 rounded w-full md:w-auto self-start;
|
|
103
103
|
|
|
104
104
|
[id*="dropdown-menu"] {
|
|
105
105
|
@apply mx-0;
|
|
@@ -118,7 +118,7 @@ module Decidim
|
|
|
118
118
|
|
|
119
119
|
def data_for_participatory_space(export_manifest)
|
|
120
120
|
collection = participatory_spaces.filter { |space| space.manifest.name == export_manifest.manifest.name }.flat_map do |participatory_space|
|
|
121
|
-
export_manifest.collection.call(participatory_space)
|
|
121
|
+
export_manifest.collection.call(participatory_space, nil)
|
|
122
122
|
end
|
|
123
123
|
|
|
124
124
|
serializer = export_manifest.open_data_serializer.nil? ? export_manifest.serializer : export_manifest.open_data_serializer
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
</div>
|
|
32
32
|
<% end %>
|
|
33
33
|
|
|
34
|
-
<p class="h3 mt-2"><%= t("decidim.
|
|
34
|
+
<p class="h3 mt-2"><%= t("layouts.decidim.header.mobile_account_greeting", user_name: current_user.name) %></p>
|
|
35
35
|
|
|
36
36
|
<ul>
|
|
37
37
|
<%= render partial: "layouts/decidim/header/main_links_dropdown" %>
|
data/config/locales/ca-IT.yml
CHANGED
|
@@ -1057,6 +1057,9 @@ ca-IT:
|
|
|
1057
1057
|
explanation: 'Instruccions per a la imatge:'
|
|
1058
1058
|
message_1: Preferiblement una imatge apaïsada que no tingui cap text.
|
|
1059
1059
|
message_2: El servei retalla la imatge.
|
|
1060
|
+
import_file:
|
|
1061
|
+
explanation: 'Instruccions per al fitxer d''importació:'
|
|
1062
|
+
message_1: Ha de ser un document JSON descarregat mitjançant la funció d'exportació.
|
|
1060
1063
|
file_validation:
|
|
1061
1064
|
allowed_file_extensions: 'Tipus de fitxers admesos: %{extensions}'
|
|
1062
1065
|
max_file_dimension: 'Mides máximes de l''arxiu: %{resolution} pixels'
|
|
@@ -1801,6 +1804,7 @@ ca-IT:
|
|
|
1801
1804
|
send_paranoid_instructions: Si la teva adreça de correu electrònic existeix a la nostra base de dades, rebràs un correu electrònic amb instruccions per confirmar la teva adreça en pocs minuts.
|
|
1802
1805
|
failure:
|
|
1803
1806
|
already_authenticated: Ja has iniciat la sessió.
|
|
1807
|
+
csrf_token: No es pot verificar la teva sol·licitud. Si us plau, torna a provar-ho.
|
|
1804
1808
|
inactive: El teu compte encara no està activat.
|
|
1805
1809
|
invalid: El %{authentication_keys} o la contrasenya no són vàlids.
|
|
1806
1810
|
invited: Tens una invitació pendent, accepta-la per acabar de crear el teu compte.
|
|
@@ -2128,6 +2132,7 @@ ca-IT:
|
|
|
2128
2132
|
confirm_title_close_ephemeral_session: Abans de sortir d'aquesta pàgina…
|
|
2129
2133
|
log_in: Entra
|
|
2130
2134
|
main_menu: Menú principal
|
|
2135
|
+
mobile_account_greeting: Hola %{user_name},
|
|
2131
2136
|
user_menu: Menú d'usuari
|
|
2132
2137
|
impersonation_warning:
|
|
2133
2138
|
close_session: Tanca la sessió
|
data/config/locales/ca.yml
CHANGED
|
@@ -1057,6 +1057,9 @@ ca:
|
|
|
1057
1057
|
explanation: 'Instruccions per a la imatge:'
|
|
1058
1058
|
message_1: Preferiblement una imatge apaïsada que no tingui cap text.
|
|
1059
1059
|
message_2: El servei retalla la imatge.
|
|
1060
|
+
import_file:
|
|
1061
|
+
explanation: 'Instruccions per al fitxer d''importació:'
|
|
1062
|
+
message_1: Ha de ser un document JSON descarregat mitjançant la funció d'exportació.
|
|
1060
1063
|
file_validation:
|
|
1061
1064
|
allowed_file_extensions: 'Tipus de fitxers admesos: %{extensions}'
|
|
1062
1065
|
max_file_dimension: 'Mides máximes de l''arxiu: %{resolution} pixels'
|
|
@@ -1801,6 +1804,7 @@ ca:
|
|
|
1801
1804
|
send_paranoid_instructions: Si la teva adreça de correu electrònic existeix a la nostra base de dades, rebràs un correu electrònic amb instruccions per confirmar la teva adreça en pocs minuts.
|
|
1802
1805
|
failure:
|
|
1803
1806
|
already_authenticated: Ja has iniciat la sessió.
|
|
1807
|
+
csrf_token: No es pot verificar la teva sol·licitud. Si us plau, torna a provar-ho.
|
|
1804
1808
|
inactive: El teu compte encara no està activat.
|
|
1805
1809
|
invalid: El %{authentication_keys} o la contrasenya no són vàlids.
|
|
1806
1810
|
invited: Tens una invitació pendent, accepta-la per acabar de crear el teu compte.
|
|
@@ -2128,6 +2132,7 @@ ca:
|
|
|
2128
2132
|
confirm_title_close_ephemeral_session: Abans de sortir d'aquesta pàgina…
|
|
2129
2133
|
log_in: Entra
|
|
2130
2134
|
main_menu: Menú principal
|
|
2135
|
+
mobile_account_greeting: Hola %{user_name},
|
|
2131
2136
|
user_menu: Menú d'usuari
|
|
2132
2137
|
impersonation_warning:
|
|
2133
2138
|
close_session: Tanca la sessió
|