decidim-core 0.28.1 → 0.28.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/cells/decidim/address/online.erb +2 -2
- data/app/cells/decidim/address_cell.rb +4 -0
- data/app/cells/decidim/announcement/show.erb +2 -2
- data/app/cells/decidim/author/show.erb +5 -5
- data/app/cells/decidim/card/show.erb +1 -1
- data/app/cells/decidim/card_g/show.erb +1 -1
- data/app/cells/decidim/card_g_cell.rb +5 -2
- data/app/cells/decidim/card_l/image.erb +2 -2
- data/app/cells/decidim/card_l_cell.rb +5 -2
- data/app/cells/decidim/card_metadata/show.erb +2 -2
- data/app/cells/decidim/content_blocks/hero_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/highlighted_content_banner/show.erb +1 -1
- data/app/cells/decidim/content_blocks/participatory_space_hero_cell.rb +2 -2
- data/app/cells/decidim/data_consent/category.erb +1 -1
- data/app/cells/decidim/nav_links/show.erb +2 -2
- data/app/cells/decidim/notification/moderated.erb +12 -0
- data/app/cells/decidim/notification_cell.rb +5 -1
- data/app/cells/decidim/profile/details.erb +1 -1
- data/app/cells/decidim/progress_bar/show.erb +1 -1
- data/app/cells/decidim/progress_bar_cell.rb +2 -0
- data/app/cells/decidim/report_button/flag_modal.erb +5 -1
- data/app/cells/decidim/resource_types_filter/show.erb +3 -3
- data/app/cells/decidim/statistic/show.erb +2 -2
- data/app/cells/decidim/upload_modal/modal.erb +3 -4
- data/app/commands/decidim/create_omniauth_registration.rb +10 -4
- data/app/controllers/concerns/decidim/devise_controllers.rb +1 -0
- data/app/controllers/concerns/decidim/force_authentication.rb +1 -1
- data/app/controllers/concerns/decidim/paginable.rb +1 -1
- data/app/controllers/concerns/decidim/use_organization_time_zone.rb +1 -1
- data/app/controllers/decidim/application_controller.rb +1 -0
- data/app/controllers/decidim/gamification/badges_controller.rb +2 -0
- data/app/controllers/decidim/links_controller.rb +15 -2
- data/app/helpers/concerns/decidim/flash_helper_extensions.rb +2 -2
- data/app/helpers/decidim/check_boxes_tree_helper.rb +1 -2
- data/app/helpers/decidim/paginate_helper.rb +3 -5
- data/app/mailers/decidim/application_mailer.rb +40 -6
- data/app/models/decidim/attachment.rb +3 -3
- data/app/models/decidim/component.rb +4 -1
- data/app/models/decidim/content_block.rb +2 -2
- data/app/models/decidim/user.rb +12 -12
- data/app/packs/src/decidim/a11y.js +14 -0
- data/app/packs/src/decidim/abide_form_validator_fixer.js +44 -0
- data/app/packs/src/decidim/direct_uploads/upload_modal.js +2 -6
- data/app/packs/src/decidim/index.js +29 -1
- data/app/packs/src/decidim/input_character_counter.js +1 -1
- data/app/packs/stylesheets/decidim/_accordion.scss +2 -2
- data/app/packs/stylesheets/decidim/_cards.scss +2 -2
- data/app/packs/stylesheets/decidim/_dropdown.scss +9 -9
- data/app/packs/stylesheets/decidim/_forms.scss +4 -4
- data/app/packs/stylesheets/decidim/_layout.scss +3 -3
- data/app/packs/stylesheets/decidim/_modal_update.scss +1 -3
- data/app/packs/stylesheets/decidim/_tooltip.scss +10 -10
- data/app/packs/stylesheets/decidim/editor.scss +1 -1
- data/app/presenters/decidim/admin_log/organization_presenter.rb +1 -1
- data/app/presenters/decidim/log/resource_presenter.rb +7 -1
- data/app/services/decidim/download_your_data_exporter.rb +36 -25
- data/app/services/decidim/log/diff_changeset_calculator.rb +1 -1
- data/app/services/decidim/open_data_exporter.rb +8 -7
- data/app/views/decidim/account/show.html.erb +2 -2
- data/app/views/decidim/application/_document.html.erb +2 -2
- data/app/views/decidim/endorsements/update_buttons_and_counters.js.erb +2 -1
- data/app/views/decidim/gamification/badges/index.html.erb +34 -33
- data/app/views/decidim/links/_modal.html.erb +1 -1
- data/app/views/decidim/links/new.html.erb +3 -1
- data/app/views/decidim/manifests/show.json.erb +5 -5
- data/app/views/decidim/messaging/conversations/create.js.erb +1 -1
- data/app/views/decidim/notifications_settings/show.html.erb +6 -6
- data/app/views/decidim/pages/_tabbed.html.erb +2 -2
- data/app/views/decidim/searches/_filters.html.erb +2 -2
- data/app/views/decidim/shared/_filters.html.erb +2 -2
- data/app/views/decidim/shared/_orders.html.erb +2 -2
- data/app/views/decidim/shared/filters/_collection.html.erb +5 -3
- data/app/views/decidim/shared/filters/_dropdown_label.html.erb +21 -19
- data/app/views/layouts/decidim/_logo.html.erb +1 -1
- data/app/views/layouts/decidim/_wrapper.html.erb +1 -1
- data/app/views/layouts/decidim/footer/_main_intro.html.erb +1 -1
- data/app/views/layouts/decidim/footer/_main_links.html.erb +3 -1
- data/app/views/layouts/decidim/header/_main_links_desktop.html.erb +5 -3
- data/app/views/layouts/decidim/header/_main_links_mobile_account.html.erb +1 -1
- data/app/views/layouts/decidim/header/_menu_breadcrumb_items.html.erb +2 -0
- data/app/views/layouts/decidim/shared/_layout_user_profile.html.erb +2 -2
- data/config/locales/ar.yml +1 -5
- data/config/locales/bg.yml +878 -1
- data/config/locales/ca.yml +5 -3
- data/config/locales/cs.yml +3 -1
- data/config/locales/de.yml +3 -1
- data/config/locales/el.yml +8 -1
- data/config/locales/en.yml +3 -1
- data/config/locales/es-MX.yml +8 -6
- data/config/locales/es-PY.yml +8 -6
- data/config/locales/es.yml +32 -30
- data/config/locales/eu.yml +4 -2
- data/config/locales/fi-plain.yml +6 -4
- data/config/locales/fi.yml +32 -30
- data/config/locales/fr-CA.yml +2 -0
- data/config/locales/fr.yml +2 -0
- data/config/locales/ga-IE.yml +8 -0
- data/config/locales/gl.yml +1 -0
- data/config/locales/hu.yml +1 -2
- data/config/locales/is-IS.yml +3 -0
- data/config/locales/it.yml +7 -1
- data/config/locales/ja.yml +3 -1
- data/config/locales/kaa.yml +5 -0
- data/config/locales/lb.yml +7 -1
- data/config/locales/lt.yml +8 -2
- data/config/locales/lv.yml +8 -1
- data/config/locales/nl.yml +7 -1
- data/config/locales/no.yml +7 -1
- data/config/locales/pl.yml +35 -0
- data/config/locales/pt-BR.yml +0 -1
- data/config/locales/pt.yml +7 -1
- data/config/locales/ro-RO.yml +8 -0
- data/config/locales/ru.yml +8 -0
- data/config/locales/sk.yml +8 -1
- data/config/locales/sl.yml +8 -0
- data/config/locales/sv.yml +132 -88
- data/config/locales/tr-TR.yml +21 -4
- data/config/locales/uk.yml +10 -0
- data/config/locales/zh-CN.yml +0 -1
- data/config/locales/zh-TW.yml +8 -1
- data/db/migrate/20181025082245_add_timestamps_to_components.rb +5 -1
- data/decidim-core.gemspec +0 -1
- data/lib/decidim/asset_router/storage.rb +214 -11
- data/lib/decidim/core/engine.rb +8 -0
- data/lib/decidim/core/seeds.rb +1 -1
- data/lib/decidim/core/test/shared_examples/attachable_interface_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +76 -6
- data/lib/decidim/core/test/shared_examples/follows_examples.rb +8 -3
- data/lib/decidim/core/test/shared_examples/logo_email.rb +2 -2
- data/lib/decidim/core/test/shared_examples/paginated_resource_examples.rb +5 -5
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/core.rb +6 -1
- data/lib/decidim/events/base_event.rb +4 -0
- data/lib/decidim/organization_settings.rb +10 -2
- data/lib/decidim/seven_zip_wrapper.rb +29 -0
- data/lib/tasks/upgrade/decidim_fix_categorization.rake +101 -1
- metadata +13 -25
- data/app/services/decidim/zip_stream/writer.rb +0 -39
data/app/models/decidim/user.rb
CHANGED
@@ -278,6 +278,18 @@ module Decidim
|
|
278
278
|
false
|
279
279
|
end
|
280
280
|
|
281
|
+
def after_confirmation
|
282
|
+
return unless organization.send_welcome_notification?
|
283
|
+
|
284
|
+
Decidim::EventsManager.publish(
|
285
|
+
event: "decidim.events.core.welcome_notification",
|
286
|
+
event_class: WelcomeNotificationEvent,
|
287
|
+
resource: self,
|
288
|
+
affected_users: [self],
|
289
|
+
extra: { force_email: true }
|
290
|
+
)
|
291
|
+
end
|
292
|
+
|
281
293
|
protected
|
282
294
|
|
283
295
|
# Overrides devise email required validation.
|
@@ -296,18 +308,6 @@ module Decidim
|
|
296
308
|
super
|
297
309
|
end
|
298
310
|
|
299
|
-
def after_confirmation
|
300
|
-
return unless organization.send_welcome_notification?
|
301
|
-
|
302
|
-
Decidim::EventsManager.publish(
|
303
|
-
event: "decidim.events.core.welcome_notification",
|
304
|
-
event_class: WelcomeNotificationEvent,
|
305
|
-
resource: self,
|
306
|
-
affected_users: [self],
|
307
|
-
extra: { force_email: true }
|
308
|
-
)
|
309
|
-
end
|
310
|
-
|
311
311
|
private
|
312
312
|
|
313
313
|
# Changes default Devise behaviour to use ActiveJob to send async emails.
|
@@ -104,6 +104,20 @@ const createDropdown = (component) => {
|
|
104
104
|
});
|
105
105
|
}
|
106
106
|
|
107
|
+
// Disable focus on children elements so we can pass the AXE accessibility tests
|
108
|
+
const dropdownMenu = document.getElementById(dropdownOptions.dropdown);
|
109
|
+
if (dropdownMenu.getAttribute("aria-hidden") === "true") {
|
110
|
+
dropdownMenu.
|
111
|
+
querySelectorAll("a, input, button").
|
112
|
+
forEach((element) => { element.tabIndex = -1 })
|
113
|
+
}
|
114
|
+
|
115
|
+
component.addEventListener("click", () => {
|
116
|
+
dropdownMenu.
|
117
|
+
querySelectorAll("a, input, button").
|
118
|
+
forEach((element) => { element.tabIndex = 0 })
|
119
|
+
})
|
120
|
+
|
107
121
|
Dropdowns.render(component.id, dropdownOptions);
|
108
122
|
}
|
109
123
|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
/**
|
2
|
+
* This script modifies the behavior of Abide form validation to address the issue of form validation errors
|
3
|
+
* appearing prematurely in input fields.
|
4
|
+
*
|
5
|
+
* The primary goal is to hide error messages until the input field loses focus.
|
6
|
+
*/
|
7
|
+
|
8
|
+
class AbideFormValidatorFixer {
|
9
|
+
initialize() {
|
10
|
+
const forms = document.querySelectorAll("main [data-live-validate='true']");
|
11
|
+
|
12
|
+
forms.forEach((form) => {
|
13
|
+
if (this.isElementVisible(form)) {
|
14
|
+
this.setupForm(form);
|
15
|
+
}
|
16
|
+
});
|
17
|
+
}
|
18
|
+
|
19
|
+
isElementVisible(element) {
|
20
|
+
return element.offsetParent !== null && getComputedStyle(element).display !== "none";
|
21
|
+
}
|
22
|
+
|
23
|
+
setupForm(form) {
|
24
|
+
const inputs = form.querySelectorAll("input");
|
25
|
+
|
26
|
+
inputs.forEach((input) => {
|
27
|
+
const errorElement = input.closest("label")?.querySelector(".form-error") || input.parentElement.querySelector(".form-error");
|
28
|
+
if (!errorElement) {
|
29
|
+
return;
|
30
|
+
}
|
31
|
+
form.removeAttribute("data-live-validate");
|
32
|
+
input.addEventListener("input", this.hideErrorElement.bind(this, errorElement));
|
33
|
+
});
|
34
|
+
}
|
35
|
+
|
36
|
+
hideErrorElement(errorElement) {
|
37
|
+
errorElement.classList.remove("is-visible");
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
document.addEventListener("DOMContentLoaded", () => {
|
42
|
+
const validatorFixer = new AbideFormValidatorFixer();
|
43
|
+
validatorFixer.initialize();
|
44
|
+
});
|
@@ -154,20 +154,16 @@ export default class UploadModal {
|
|
154
154
|
// Disabled save button when any children have data-state="error"
|
155
155
|
this.saveButton.disabled = Array.from(files).filter(({ dataset: { state } }) => state === STATUS.ERROR).length > 0;
|
156
156
|
|
157
|
-
const dataSelectFileButton = this.emptyItems.querySelector("[data-select-file-button]");
|
158
|
-
|
159
157
|
// Only allow to continue the upload when the multiple option is true (default: false)
|
160
158
|
const continueUpload = !files.length || this.options.multiple
|
161
159
|
this.input.disabled = !continueUpload
|
162
160
|
if (continueUpload) {
|
163
161
|
this.emptyItems.classList.remove("is-disabled");
|
164
|
-
|
162
|
+
this.emptyItems.querySelector("label").removeAttribute("disabled");
|
165
163
|
} else {
|
166
164
|
this.emptyItems.classList.add("is-disabled");
|
167
|
-
|
165
|
+
this.emptyItems.querySelector("label").disabled = true;
|
168
166
|
}
|
169
|
-
|
170
|
-
dataSelectFileButton.addEventListener("click", () => this.input.click());
|
171
167
|
}
|
172
168
|
|
173
169
|
createUploadItem(file, errors, opts = {}) {
|
@@ -50,6 +50,7 @@ import "src/decidim/impersonation"
|
|
50
50
|
import "src/decidim/gallery"
|
51
51
|
import "src/decidim/direct_uploads/upload_field"
|
52
52
|
import "src/decidim/data_consent"
|
53
|
+
import "src/decidim/abide_form_validator_fixer"
|
53
54
|
import "src/decidim/sw"
|
54
55
|
|
55
56
|
// local deps that require initialization
|
@@ -90,6 +91,33 @@ window.Decidim = window.Decidim || {
|
|
90
91
|
|
91
92
|
window.morphdom = morphdom
|
92
93
|
|
94
|
+
// REDESIGN_PENDING: deprecated
|
95
|
+
window.initFoundation = (element) => {
|
96
|
+
$(element).foundation();
|
97
|
+
|
98
|
+
// Fix compatibility issue with the `a11y-accordion-component` package that
|
99
|
+
// uses the `data-open` attribute to indicate the open state for the accordion
|
100
|
+
// trigger.
|
101
|
+
//
|
102
|
+
// In Foundation, these listeners are initiated on the document node always,
|
103
|
+
// regardless of the element for which foundation is initiated. Therefore, we
|
104
|
+
// need the document node here instead of the `element` passed to this
|
105
|
+
// function.
|
106
|
+
const $document = $(document);
|
107
|
+
|
108
|
+
$document.off("click.zf.trigger", window.Foundation.Triggers.Listeners.Basic.openListener);
|
109
|
+
$document.on("click.zf.trigger", "[data-open]", (ev, ...restArgs) => {
|
110
|
+
// Do not apply for the accordion triggers.
|
111
|
+
const accordion = ev.currentTarget?.closest("[data-component='accordion']");
|
112
|
+
if (accordion) {
|
113
|
+
return;
|
114
|
+
}
|
115
|
+
|
116
|
+
// Otherwise call the original implementation
|
117
|
+
Reflect.apply(window.Foundation.Triggers.Listeners.Basic.openListener, ev.currentTarget, [ev, ...restArgs]);
|
118
|
+
});
|
119
|
+
};
|
120
|
+
|
93
121
|
Rails.start()
|
94
122
|
|
95
123
|
/**
|
@@ -104,7 +132,7 @@ const initializer = (element = document) => {
|
|
104
132
|
window.focusGuard = window.focusGuard || new FocusGuard(document.body);
|
105
133
|
|
106
134
|
// REDESIGN_PENDING: deprecated
|
107
|
-
|
135
|
+
window.initFoundation(element);
|
108
136
|
|
109
137
|
svg4everybody();
|
110
138
|
|
@@ -74,7 +74,7 @@ export default class InputCharacterCounter {
|
|
74
74
|
|
75
75
|
// If input is a hidden for WYSIWYG editor add it at the end
|
76
76
|
if (this.$input.parent().is(".editor")) {
|
77
|
-
this.$input.parent().
|
77
|
+
this.$input.parent().append(container);
|
78
78
|
} else {
|
79
79
|
const wrapper = document.createElement("span")
|
80
80
|
wrapper.className = "input-character-counter"
|
@@ -4,10 +4,10 @@
|
|
4
4
|
|
5
5
|
[data-component="accordion"]
|
6
6
|
[id*="comment"][class="comment-reply"][aria-hidden="true"] {
|
7
|
-
display:
|
7
|
+
display: none;
|
8
8
|
}
|
9
9
|
|
10
10
|
[data-component="accordion"]
|
11
11
|
[id*="comment"][class="comment-reply"][aria-hidden="false"] {
|
12
|
-
display:
|
12
|
+
display: block;
|
13
13
|
}
|
@@ -134,7 +134,7 @@
|
|
134
134
|
&-month,
|
135
135
|
&-day,
|
136
136
|
&-year {
|
137
|
-
@apply inline-flex items-center justify-evenly empty:[&>
|
137
|
+
@apply inline-flex items-center justify-evenly empty:[&>div]:hidden;
|
138
138
|
}
|
139
139
|
}
|
140
140
|
|
@@ -143,7 +143,7 @@
|
|
143
143
|
&__list-metadata {
|
144
144
|
@apply mt-auto inline-flex flex-wrap gap-x-4 md:gap-0;
|
145
145
|
|
146
|
-
& >
|
146
|
+
& > div {
|
147
147
|
@apply inline-flex items-center gap-1 px-0 md:px-6 border-gray-3 border-0 md:border-r first:pl-0 last:pr-0 last:border-r-0 text-sm text-gray-2;
|
148
148
|
|
149
149
|
& > svg {
|
@@ -36,6 +36,15 @@
|
|
36
36
|
.dropdown {
|
37
37
|
@apply absolute border-2 border-gray-3 rounded min-w-max p-4 drop-shadow-md text-left z-10;
|
38
38
|
|
39
|
+
/*
|
40
|
+
NOTE: the calculated value is the sum of the arrow offset position plus the half of the arrow size:
|
41
|
+
- offset position: 20%
|
42
|
+
- arrow size: 1.5rem
|
43
|
+
*/
|
44
|
+
--arrow-offset: 20%;
|
45
|
+
--arrow-size: 1.5rem;
|
46
|
+
--arrow-visible-size: var(--arrow-size) * 0.5;
|
47
|
+
|
39
48
|
& > * {
|
40
49
|
@apply relative z-10 p-3.5 first:pt-1.5 last:pb-1.5;
|
41
50
|
}
|
@@ -54,15 +63,6 @@
|
|
54
63
|
}
|
55
64
|
}
|
56
65
|
|
57
|
-
/*
|
58
|
-
NOTE: the calculated value is the sum of the arrow offset position plus the half of the arrow size:
|
59
|
-
- offset position: 20%
|
60
|
-
- arrow size: 1.5rem
|
61
|
-
*/
|
62
|
-
--arrow-offset: 20%;
|
63
|
-
--arrow-size: 1.5rem;
|
64
|
-
--arrow-visible-size: var(--arrow-size) * 0.5;
|
65
|
-
|
66
66
|
&__bottom {
|
67
67
|
@apply top-full right-0 mt-3 translate-x-[calc(var(--arrow-offset)-var(--arrow-visible-size))] before:content-[''] before:absolute before:right-[var(--arrow-offset)] before:-top-2 before:w-[var(--arrow-size)] before:h-[var(--arrow-size)] before:rotate-45 before:bg-white before:rounded before:border-2 before:border-gray-3 after:content-[''] after:absolute after:left-0 after:top-0 after:w-full after:h-full after:bg-white;
|
68
68
|
}
|
@@ -45,16 +45,16 @@
|
|
45
45
|
}
|
46
46
|
|
47
47
|
select {
|
48
|
-
&:not(.reset-defaults) {
|
49
|
-
@apply pr-8;
|
50
|
-
}
|
51
|
-
|
52
48
|
@apply appearance-none;
|
53
49
|
|
54
50
|
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 12 8'%3e%3cpath fill='%233E4C5C' d='M5.99962 4.97656L10.1246 0.851562L11.303 2.0299L5.99962 7.33323L0.696289 2.0299L1.87462 0.851562L5.99962 4.97656Z'/%3e%3c/svg%3e");
|
55
51
|
background-position: right 1rem center;
|
56
52
|
background-repeat: no-repeat;
|
57
53
|
background-size: 0.75rem;
|
54
|
+
|
55
|
+
&:not(.reset-defaults) {
|
56
|
+
@apply pr-8;
|
57
|
+
}
|
58
58
|
}
|
59
59
|
}
|
60
60
|
|
@@ -6,7 +6,7 @@
|
|
6
6
|
}
|
7
7
|
|
8
8
|
[data-content] {
|
9
|
-
@apply
|
9
|
+
@apply relative flex flex-col;
|
10
10
|
}
|
11
11
|
}
|
12
12
|
|
@@ -31,14 +31,14 @@
|
|
31
31
|
}
|
32
32
|
|
33
33
|
.layout-2col {
|
34
|
-
@apply md:grid grid-cols-12 container grow
|
34
|
+
@apply md:grid grid-cols-12 container grow auto-rows-max;
|
35
35
|
|
36
36
|
&__aside {
|
37
37
|
@apply col-span-4 lg:col-span-3 md:pr-16 py-6 md:py-12 gap-6 md:gap-12 flex flex-col justify-between items-start md:justify-start before:content-[''] before:absolute before:top-0 before:left-0 before:h-full before:w-1/2 before:-z-10 md:before:bg-background;
|
38
38
|
}
|
39
39
|
|
40
40
|
&__main {
|
41
|
-
@apply col-span-8 lg:col-span-9 bg-white md:pl-16 py-6 md:py-12;
|
41
|
+
@apply col-span-8 lg:col-span-9 bg-white md:pl-16 py-6 md:py-12 min-h-[60vh];
|
42
42
|
}
|
43
43
|
|
44
44
|
&__reverse &__aside {
|
@@ -1,6 +1,16 @@
|
|
1
1
|
[role="tooltip"] {
|
2
2
|
@apply absolute bg-black z-10 px-4 py-2 w-max max-w-xs rounded text-left text-white;
|
3
3
|
|
4
|
+
/*
|
5
|
+
NOTE: the calculated value is the sum of the arrow offset position plus the half of the arrow size:
|
6
|
+
- offset position: 20%
|
7
|
+
- arrow size: 16px
|
8
|
+
*/
|
9
|
+
--arrow-offset: 20%;
|
10
|
+
--arrow-size: 16px;
|
11
|
+
--arrow-visible-size: var(--arrow-size) * 0.5;
|
12
|
+
--arrow-margin: var(--arrow-visible-size) * 1.4142135623730951; // due to the rotation, the margin is SQRT2 times the visible size
|
13
|
+
|
4
14
|
& > * {
|
5
15
|
@apply relative z-20;
|
6
16
|
}
|
@@ -41,16 +51,6 @@
|
|
41
51
|
}
|
42
52
|
}
|
43
53
|
|
44
|
-
/*
|
45
|
-
NOTE: the calculated value is the sum of the arrow offset position plus the half of the arrow size:
|
46
|
-
- offset position: 20%
|
47
|
-
- arrow size: 16px
|
48
|
-
*/
|
49
|
-
--arrow-offset: 20%;
|
50
|
-
--arrow-size: 16px;
|
51
|
-
--arrow-visible-size: var(--arrow-size) * 0.5;
|
52
|
-
--arrow-margin: var(--arrow-visible-size) * 1.4142135623730951; // due to the rotation, the margin is SQRT2 times the visible size
|
53
|
-
|
54
54
|
&.top {
|
55
55
|
@apply -translate-x-[calc(100%-var(--arrow-offset))] -translate-y-[calc(100%+var(--arrow-margin))] before:content-[''] before:absolute before:-z-10 before:right-[calc(var(--arrow-offset)-var(--arrow-visible-size))] before:-bottom-[var(--arrow-visible-size)] before:w-[var(--arrow-size)] before:h-[var(--arrow-size)] before:rotate-45 before:bg-black before:rounded-br;
|
56
56
|
}
|
@@ -21,7 +21,7 @@
|
|
21
21
|
}
|
22
22
|
|
23
23
|
.editor-container {
|
24
|
-
@apply editor-props editor-suggestions-props flex flex-col
|
24
|
+
@apply editor-props editor-suggestions-props flex flex-col mt-4 border editor-border;
|
25
25
|
|
26
26
|
&.editor-disabled {
|
27
27
|
.editor-input .ProseMirror {
|
@@ -10,6 +10,8 @@ module Decidim
|
|
10
10
|
# overwrite `BasePresenter#resource_presenter` to return your custom resource presenter.
|
11
11
|
# The only requirement for custom renderers is that they should respond to `present`.
|
12
12
|
class ResourcePresenter
|
13
|
+
include Decidim::SanitizeHelper
|
14
|
+
|
13
15
|
# Public: Initializes the presenter.
|
14
16
|
#
|
15
17
|
# resource - An instance of a model that can be located by
|
@@ -65,7 +67,11 @@ module Decidim
|
|
65
67
|
#
|
66
68
|
# Returns an HTML-safe String.
|
67
69
|
def present_resource_name
|
68
|
-
|
70
|
+
if resource.present? && resource.respond_to?(:presenter) && resource.presenter.respond_to?(:title)
|
71
|
+
resource.presenter.title(html_escape: true)
|
72
|
+
else
|
73
|
+
decidim_escape_translated(extra["title"]).html_safe
|
74
|
+
end
|
69
75
|
end
|
70
76
|
end
|
71
77
|
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
4
|
-
require "zip"
|
5
|
-
require_relative "zip_stream/writer"
|
3
|
+
require "decidim/seven_zip_wrapper"
|
6
4
|
|
7
5
|
module Decidim
|
8
6
|
# Public: Generates a 7z(seven zip) file with data files ready to be persisted
|
@@ -10,8 +8,6 @@ module Decidim
|
|
10
8
|
#
|
11
9
|
# In fact, the 7z file wraps a ZIP file which finally contains the data files.
|
12
10
|
class DownloadYourDataExporter
|
13
|
-
include ::Decidim::ZipStream::Writer
|
14
|
-
|
15
11
|
DEFAULT_EXPORT_FORMAT = "CSV"
|
16
12
|
ZIP_FILE_NAME = "download-your-data.zip"
|
17
13
|
|
@@ -29,36 +25,25 @@ module Decidim
|
|
29
25
|
end
|
30
26
|
|
31
27
|
def export
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
39
|
-
end
|
28
|
+
tmpdir = Dir.mktmpdir("temporary-download-your-data-dir")
|
29
|
+
user_data, user_attachments = data_and_attachments_for_user
|
30
|
+
save_user_data(tmpdir, user_data)
|
31
|
+
save_user_attachments(tmpdir, user_attachments)
|
32
|
+
|
33
|
+
SevenZipWrapper.compress_and_encrypt(filename: @path, password: @password, input_directory: tmpdir)
|
40
34
|
end
|
41
35
|
|
42
36
|
private
|
43
37
|
|
44
|
-
|
45
|
-
buffer = Zip::OutputStream.write_buffer do |out|
|
46
|
-
user_data, attachments = data_for(@user, @export_format)
|
38
|
+
attr_reader :user, :export_format
|
47
39
|
|
48
|
-
|
49
|
-
add_attachments_to_zip_stream(out, attachments)
|
50
|
-
end
|
51
|
-
|
52
|
-
buffer.string
|
53
|
-
end
|
54
|
-
|
55
|
-
def data_for(user, format)
|
40
|
+
def data_and_attachments_for_user
|
56
41
|
export_data = []
|
57
42
|
export_attachments = []
|
58
43
|
|
59
44
|
download_your_data_entities.each do |object|
|
60
45
|
klass = Object.const_get(object)
|
61
|
-
export_data << [klass.model_name.name.parameterize.pluralize, Exporters.find_exporter(
|
46
|
+
export_data << [klass.model_name.name.parameterize.pluralize, Exporters.find_exporter(export_format).new(klass.user_collection(user), klass.export_serializer).export]
|
62
47
|
attachments = klass.download_your_data_images(user)
|
63
48
|
export_attachments << [klass.model_name.name.parameterize.pluralize, attachments.flatten] unless attachments.nil?
|
64
49
|
end
|
@@ -69,5 +54,31 @@ module Decidim
|
|
69
54
|
def download_your_data_entities
|
70
55
|
@download_your_data_entities ||= DownloadYourDataSerializers.data_entities
|
71
56
|
end
|
57
|
+
|
58
|
+
def save_user_data(tmpdir, user_data)
|
59
|
+
user_data.each do |entity, exporter_data|
|
60
|
+
next if exporter_data.read == "\n"
|
61
|
+
|
62
|
+
file_name = File.join(tmpdir, "#{entity}-#{exporter_data.filename}")
|
63
|
+
File.write(file_name, exporter_data.read)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def save_user_attachments(tmpdir, user_attachments)
|
68
|
+
user_attachments.each do |entity, attachment_block|
|
69
|
+
attachment_block.each do |attachment|
|
70
|
+
next unless attachment.attached?
|
71
|
+
|
72
|
+
blobs = attachment.is_a?(ActiveStorage::Attached::One) ? [attachment.blob] : attachment.blobs
|
73
|
+
blobs.each do |blob|
|
74
|
+
Dir.mkdir(File.join(tmpdir, entity.parameterize))
|
75
|
+
file_name = File.join(tmpdir, entity.parameterize, blob.filename.to_s)
|
76
|
+
blob.open do |blob_file|
|
77
|
+
File.write(file_name, blob_file.read.force_encoding("UTF-8"))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
72
83
|
end
|
73
84
|
end
|
@@ -86,7 +86,7 @@ module Decidim
|
|
86
86
|
locales.flat_map do |locale|
|
87
87
|
previous_value = values.first.try(:[], locale)
|
88
88
|
new_value = values.last.try(:[], locale)
|
89
|
-
if previous_value == new_value
|
89
|
+
if previous_value == new_value || (previous_value.nil? && new_value.blank?)
|
90
90
|
nil
|
91
91
|
else
|
92
92
|
label = generate_label(attribute, locale)
|
@@ -51,13 +51,14 @@ module Decidim
|
|
51
51
|
headers.push(*exporter.headers)
|
52
52
|
exported = exporter.export
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
54
|
+
tmpdir = Dir::Tmpname.create(export_manifest.name.to_s) do
|
55
|
+
# just get an empty file name
|
56
|
+
end
|
57
|
+
filename = File.join(tmpdir, "#{component.id}.csv")
|
58
|
+
Dir.mkdir(tmpdir)
|
59
|
+
File.write(filename, exported.read)
|
60
|
+
|
61
|
+
collection.push(filename)
|
61
62
|
end
|
62
63
|
end
|
63
64
|
end
|
@@ -5,7 +5,7 @@
|
|
5
5
|
<% if current_user.unconfirmed_email.present? %>
|
6
6
|
<%# NOTE: announcement cell clean_body method will purge the button %>
|
7
7
|
<div id="email-change-pending" class="flash secondary" data-announcement>
|
8
|
-
<
|
8
|
+
<div class="flash__message flex-none block leading-relaxed">
|
9
9
|
<p>
|
10
10
|
<strong><%= t("decidim.account.email_change.title") %></strong>
|
11
11
|
</p>
|
@@ -18,7 +18,7 @@
|
|
18
18
|
resend_link: link_to(t("decidim.account.email_change.send_again"), resend_confirmation_instructions_account_path, role: :button, method: :post, remote: true),
|
19
19
|
cancel_link: link_to(t("decidim.account.email_change.cancel"), cancel_email_change_account_path, role: :button, method: :post, remote: true)) %>
|
20
20
|
</p>
|
21
|
-
</
|
21
|
+
</div>
|
22
22
|
</div>
|
23
23
|
<% end %>
|
24
24
|
|
@@ -7,8 +7,8 @@
|
|
7
7
|
<div class="card__list-text"><%= decidim_escape_translated(document.description) %></div>
|
8
8
|
<% end %>
|
9
9
|
<div class="card__list-metadata">
|
10
|
-
<
|
11
|
-
<
|
10
|
+
<div><%= icon "file-text-line" %><%= document.file_type %></div>
|
11
|
+
<div><%= icon "scales-2-line" %><%= number_to_human_size(document.file_size) %></div>
|
12
12
|
</div>
|
13
13
|
</div>
|
14
14
|
<%= link_to document.url,
|
@@ -1,5 +1,4 @@
|
|
1
1
|
updateEndorsementBlock();
|
2
|
-
|
3
2
|
function updateEndorsementBlock() {
|
4
3
|
var $endorsementBlock = $('#resource-<%= resource.id %>-endorsement-block');
|
5
4
|
var $endorsementListTrigger = $('#resource-<%= resource.id %>-endorsement-block #dropdown-trigger');
|
@@ -24,4 +23,6 @@ function updateEndorsementBlock() {
|
|
24
23
|
} else {
|
25
24
|
$endorsementIdentitiesButton[0].innerHTML = '<%= j(cell("decidim/endorsement_buttons", resource).button_content).strip.html_safe %>';
|
26
25
|
}
|
26
|
+
document.dispatchEvent(new CustomEvent("ajax:loaded", { detail: $endorsementBlock[0] }));
|
27
|
+
document.dispatchEvent(new CustomEvent("ajax:loaded", { detail: $endorsementListGrid[0] }));
|
27
28
|
}
|
@@ -1,40 +1,41 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
<% add_decidim_meta_tags(
|
2
|
+
title: t(".title"),
|
3
|
+
description: t(".page_description")
|
4
|
+
) %>
|
5
|
+
|
6
|
+
<main class="layout-1col cols-10">
|
7
|
+
|
8
|
+
<header class="text-center py-10">
|
9
|
+
<h1 class="title-decorator inline-block text-left mb-12">
|
10
|
+
<%= t ".title" %>
|
11
|
+
</h1>
|
12
|
+
<p class="text-lg text-gray-2">
|
13
|
+
<%= t ".page_description" %>
|
6
14
|
</p>
|
7
|
-
</
|
15
|
+
</header>
|
16
|
+
|
8
17
|
<% @badges.each do |badge| %>
|
9
|
-
<div class="
|
10
|
-
<
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
<div class="card__text text-center">
|
19
|
-
<strong><%= badge.translated_name %></strong>
|
20
|
-
</div>
|
18
|
+
<div class="mb-12">
|
19
|
+
<h2 class="h4 mb-4"><%= t ".badge_title", name: badge.translated_name %></h2>
|
20
|
+
<div class="grid grid-cols-10 text-gray-2 leading-relaxed">
|
21
|
+
<div class="col-span-2">
|
22
|
+
<div class="flex justify-center items-center">
|
23
|
+
<%= image_tag badge.image, class: "w-32", alt: badge.translated_name %>
|
24
|
+
</div>
|
25
|
+
<div class="text-center mt-4">
|
26
|
+
<strong><%= badge.translated_name %></strong>
|
21
27
|
</div>
|
22
28
|
</div>
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
<
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
</
|
32
|
-
<ol>
|
33
|
-
<% badge.conditions.each do |condition| %>
|
34
|
-
<li><%= condition %></li>
|
35
|
-
<% end %>
|
36
|
-
</ol>
|
29
|
+
<div class="col-span-7 ml-2">
|
30
|
+
<p><%= badge.description(current_organization.name) %></p>
|
31
|
+
<p class="mt-4"><strong><%= t ".how" %></strong></p>
|
32
|
+
<ol class="list-decimal">
|
33
|
+
<% badge.conditions.each do |condition| %>
|
34
|
+
<li><%= condition %></li>
|
35
|
+
<% end %>
|
36
|
+
</ol>
|
37
|
+
</div>
|
37
38
|
</div>
|
38
39
|
</div>
|
39
40
|
<% end %>
|
40
|
-
</
|
41
|
+
</main>
|
@@ -16,6 +16,6 @@
|
|
16
16
|
<button class="button button__lg button__transparent-secondary" data-dialog-close="external-domain-warning">
|
17
17
|
<%= t("decidim.links.warning.cancel") %>
|
18
18
|
</button>
|
19
|
-
<%= link_to t("decidim.links.warning.proceed"), external_url.to_s , target: "_blank", class: "button button__lg button__secondary" %>
|
19
|
+
<%= link_to t("decidim.links.warning.proceed"), external_url.to_s , target: "_blank", class: "button button__lg button__secondary", rel: "nofollow noopener noreferrer" %>
|
20
20
|
</div>
|
21
21
|
<% end %>
|