decidim-core 0.26.5 → 0.26.8
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 +1 -1
- data/app/cells/decidim/collapsible_list/show.erb +1 -1
- data/app/cells/decidim/content_blocks/cta_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/hero/show.erb +1 -1
- data/app/cells/decidim/content_blocks/highlighted_content_banner/show.erb +1 -1
- data/app/cells/decidim/content_blocks/sub_hero_cell.rb +1 -1
- data/app/controllers/decidim/authorization_modals_controller.rb +1 -1
- data/app/controllers/decidim/links_controller.rb +8 -11
- data/app/forms/url_validator.rb +1 -1
- data/app/helpers/decidim/cells_helper.rb +1 -0
- data/app/helpers/decidim/external_domain_helper.rb +14 -3
- data/app/helpers/decidim/layout_helper.rb +15 -4
- data/app/helpers/decidim/layout_helper.rb.orig +225 -0
- data/app/helpers/decidim/sanitize_helper.rb +15 -5
- data/app/models/decidim/organization.rb +6 -0
- data/app/models/decidim/scope_type.rb +28 -0
- data/app/packs/src/decidim/editor/clipboard_override.js +6 -2
- data/app/packs/src/decidim/editor.js +63 -33
- data/app/packs/src/decidim/map/controller/drag_marker.js +0 -2
- data/app/packs/src/decidim/map/controller/markers.js +0 -1
- data/app/packs/src/decidim/map/controller/static.js +0 -1
- data/app/packs/src/decidim/map/controller.js +0 -2
- data/app/packs/src/decidim/map/factory.js +4 -1
- data/app/packs/src/decidim/map/icon.js +0 -1
- data/app/packs/src/decidim/map/legacy.js +0 -1
- data/app/packs/src/decidim/map/provider/default.js +2 -0
- data/app/packs/src/decidim/map/provider/here.js +2 -1
- data/app/packs/stylesheets/decidim/_editor.scss +129 -0
- data/app/packs/stylesheets/decidim/extras/_quill.scss +0 -6
- data/app/packs/stylesheets/decidim/modules/_buttons.scss +10 -6
- data/app/packs/stylesheets/decidim/modules/_cards.scss +1 -1
- data/app/packs/stylesheets/decidim/modules/_comments.scss +24 -0
- data/app/packs/stylesheets/decidim/modules/_dropdown_menu.scss +9 -0
- data/app/packs/stylesheets/decidim/vizzs/_linechart.scss +2 -2
- data/app/packs/stylesheets/decidim/vizzs/_rowchart.scss +2 -2
- data/app/presenters/decidim/notification_presenter.rb +1 -1
- data/app/presenters/decidim/user_group_presenter.rb +1 -1
- data/app/presenters/decidim/user_presenter.rb +1 -1
- data/app/queries/decidim/metrics/users_metric_manage.rb +6 -6
- data/app/scrubbers/decidim/admin_input_scrubber.rb +27 -0
- data/app/scrubbers/decidim/user_input_scrubber.rb +32 -5
- data/app/services/decidim/traceability.rb +1 -0
- data/app/views/decidim/devise/registrations/new.html.erb.orig +231 -0
- data/app/views/decidim/links/_invalid_url_modal.html.erb +17 -0
- data/app/views/decidim/links/_modal.html.erb +1 -1
- data/app/views/decidim/links/invalid_url.js.erb +24 -0
- data/app/views/decidim/links/new.html.erb +1 -1
- data/app/views/decidim/messaging/conversations/_conversation.html.erb +1 -5
- data/app/views/decidim/pages/_standalone.html.erb +1 -1
- data/app/views/decidim/pages/_tabbed.html.erb +1 -1
- data/config/environment.rb +0 -0
- data/config/locales/ar.yml +423 -8
- data/config/locales/bg.yml +1 -4
- data/config/locales/ca.yml +26 -23
- data/config/locales/cs.yml +40 -32
- data/config/locales/da.yml +3 -0
- data/config/locales/de.yml +39 -23
- data/config/locales/el.yml +100 -2
- data/config/locales/en.yml +16 -13
- data/config/locales/eo.yml +5 -1
- data/config/locales/es-MX.yml +21 -18
- data/config/locales/es-PY.yml +23 -20
- data/config/locales/es.yml +25 -22
- data/config/locales/et.yml +3 -0
- data/config/locales/eu.yml +91 -67
- data/config/locales/fa-IR.yml +1 -0
- data/config/locales/fi-plain.yml +16 -13
- data/config/locales/fi.yml +18 -15
- data/config/locales/fr-CA.yml +28 -22
- data/config/locales/fr.yml +27 -21
- data/config/locales/ga-IE.yml +1 -0
- data/config/locales/gl.yml +4 -23
- data/config/locales/gn-PY.yml +3 -0
- data/config/locales/hr.yml +3 -0
- data/config/locales/hu.yml +66 -21
- data/config/locales/id-ID.yml +6 -4
- data/config/locales/is-IS.yml +5 -2
- data/config/locales/it.yml +5 -15
- data/config/locales/ja.yml +16 -15
- data/config/locales/ka-GE.yml +3 -0
- data/config/locales/kaa.yml +5 -0
- data/config/locales/lb.yml +8 -12
- data/config/locales/lt.yml +1 -34
- data/config/locales/lv.yml +0 -3
- data/config/locales/nl.yml +5 -24
- data/config/locales/no.yml +5 -28
- data/config/locales/oc-FR.yml +2 -0
- data/config/locales/pl.yml +0 -33
- data/config/locales/pt-BR.yml +3 -7
- data/config/locales/pt.yml +1 -5
- data/config/locales/ro-RO.yml +5 -8
- data/config/locales/ru.yml +3 -3
- data/config/locales/sk.yml +18 -10
- data/config/locales/sl.yml +1 -0
- data/config/locales/sr-CS.yml +10 -0
- data/config/locales/sv.yml +11 -34
- data/config/locales/tr-TR.yml +3 -7
- data/config/locales/uk.yml +3 -3
- data/config/locales/zh-CN.yml +0 -4
- data/config/locales/zh-TW.yml +1726 -0
- data/db/migrate/20181030090144_destroy_deleted_users_follows.rb +1 -1
- data/db/migrate/20181204110723_remove_following_users_count_from_users.rb +11 -2
- data/db/migrate/20181214101250_add_notification_types_to_users.rb +6 -1
- data/db/migrate/20190412131728_fix_user_names.rb +13 -6
- data/db/migrate/20200211173227_add_direct_message_types_to_users.rb +6 -1
- data/db/migrate/20210302150803_invalidate_all_sessions_for_deleted_users.rb +10 -3
- data/db/migrate/20210310120640_add_followable_counter_cache_to_users.rb +13 -3
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +36 -0
- data/lib/decidim/core/test/shared_examples/editor_shared_examples.rb +10 -0
- data/lib/decidim/core/test/shared_examples/map_examples.rb +4 -1
- data/lib/decidim/core/test/shared_examples/rich_text_editor_examples.rb +7 -3
- data/lib/decidim/core/test.rb +1 -0
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/core.rb +43 -0
- data/lib/decidim/dependency_resolver.rb +272 -0
- data/lib/decidim/form_builder.rb +6 -14
- data/lib/decidim/publicable.rb +4 -0
- data/lib/tasks/upgrade/decidim_user_moderation.rake +14 -0
- metadata +18 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7ddc4e551d59fc9b95f5121333870c4e91a77eb2f53d03f659d63e16bea7ca7f
|
|
4
|
+
data.tar.gz: dd766575d88dfe729ce7f8ea151967642b40e875c0596443962d0a6d8d5cd101
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dcbcc2625fe80e646c9f5e05c0e187485004542bcb73c33978bd8f2b1f78f31c2e0a4f4dba6904ba0b660e5b4408977a21d13e0c02fe2d46cba8bdb13c399321
|
|
7
|
+
data.tar.gz: a1abc1c25bfe4c99875d00822beeefeadb20bd214672772b1491d07e515ce3990b6b24c96d5400e4bc71d1accb8c8484d7e57c6ed006f63fd19e23f8378234ce
|
|
@@ -16,7 +16,7 @@ module Decidim
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def translated_description
|
|
19
|
-
@translated_description ||=
|
|
19
|
+
@translated_description ||= decidim_sanitize_editor_admin(translated_attribute(model.settings.description))
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def button_url
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<% if translated_welcome_text.blank? %>
|
|
7
7
|
<%= t("decidim.pages.home.hero.welcome", organization: current_organization.name) %>
|
|
8
8
|
<% else %>
|
|
9
|
-
<%=
|
|
9
|
+
<%= decidim_sanitize_admin translated_welcome_text %>
|
|
10
10
|
<% end %>
|
|
11
11
|
</h1>
|
|
12
12
|
</div>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<%= translated_attribute current_organization.highlighted_content_banner_title %>
|
|
8
8
|
</h1>
|
|
9
9
|
<span class="text-highlight">
|
|
10
|
-
<%=
|
|
10
|
+
<%= decidim_sanitize_editor_admin translated_attribute current_organization.highlighted_content_banner_short_description %>
|
|
11
11
|
</span>
|
|
12
12
|
</div>
|
|
13
13
|
<div class="columns large-2">
|
|
@@ -15,7 +15,7 @@ module Decidim
|
|
|
15
15
|
private
|
|
16
16
|
|
|
17
17
|
def organization_description
|
|
18
|
-
desc =
|
|
18
|
+
desc = decidim_sanitize_admin(translated_attribute(current_organization.description))
|
|
19
19
|
|
|
20
20
|
# Strip the surrounding paragraph tag because it is not allowed within
|
|
21
21
|
# a <hN> element.
|
|
@@ -17,7 +17,7 @@ module Decidim
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def current_component
|
|
20
|
-
@current_component ||= Decidim::Component.find(params[:component_id])
|
|
20
|
+
@current_component ||= Decidim::Component.where(participatory_space: current_organization.participatory_spaces).find(params[:component_id])
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def authorization_action
|
|
@@ -21,24 +21,21 @@ module Decidim
|
|
|
21
21
|
|
|
22
22
|
def invalid_url
|
|
23
23
|
flash[:alert] = I18n.t("decidim.links.invalid_url")
|
|
24
|
-
|
|
24
|
+
if request.xhr?
|
|
25
|
+
render "invalid_url"
|
|
26
|
+
else
|
|
27
|
+
redirect_to decidim.root_path
|
|
28
|
+
end
|
|
25
29
|
end
|
|
26
30
|
|
|
27
31
|
def parse_url
|
|
32
|
+
raise Decidim::InvalidUrlError if params[:external_url].blank?
|
|
28
33
|
raise Decidim::InvalidUrlError unless external_url
|
|
29
|
-
|
|
30
|
-
parts = external_url.match %r{\A(([a-z]+):)?//([^/]+)(/.*)?\z}
|
|
31
|
-
raise Decidim::InvalidUrlError unless parts
|
|
32
|
-
|
|
33
|
-
@url_parts = {
|
|
34
|
-
protocol: parts[1],
|
|
35
|
-
domain: parts[3],
|
|
36
|
-
path: parts[4]
|
|
37
|
-
}
|
|
34
|
+
raise Decidim::InvalidUrlError unless %w(http https).include?(external_url.scheme)
|
|
38
35
|
end
|
|
39
36
|
|
|
40
37
|
def external_url
|
|
41
|
-
@external_url ||= URI.parse(params[:external_url])
|
|
38
|
+
@external_url ||= URI.parse(params[:external_url])
|
|
42
39
|
end
|
|
43
40
|
end
|
|
44
41
|
end
|
data/app/forms/url_validator.rb
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
#
|
|
7
7
|
class UrlValidator < ActiveModel::EachValidator
|
|
8
8
|
def validate_each(record, attribute, value)
|
|
9
|
-
record.errors
|
|
9
|
+
record.errors.add attribute, :url_format, **options unless url_valid?(value)
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
# a URL may be technically well-formed but may
|
|
@@ -3,10 +3,21 @@
|
|
|
3
3
|
module Decidim
|
|
4
4
|
module ExternalDomainHelper
|
|
5
5
|
def highlight_domain
|
|
6
|
+
highlighted_domain = [
|
|
7
|
+
external_url.host,
|
|
8
|
+
(external_url.port && [80, 443].include?(external_url.port) ? "" : ":#{external_url.port}")
|
|
9
|
+
].join
|
|
10
|
+
|
|
11
|
+
path = [
|
|
12
|
+
external_url.path,
|
|
13
|
+
(external_url.query ? "?#{external_url.query}" : ""),
|
|
14
|
+
(external_url.fragment ? "##{external_url.fragment}" : "")
|
|
15
|
+
].join
|
|
16
|
+
|
|
6
17
|
tag.div do
|
|
7
|
-
content_tag(:span, "#{
|
|
8
|
-
content_tag(:span,
|
|
9
|
-
content_tag(:span,
|
|
18
|
+
content_tag(:span, "#{external_url.scheme}://") +
|
|
19
|
+
content_tag(:span, highlighted_domain, class: "text-alert") +
|
|
20
|
+
content_tag(:span, path)
|
|
10
21
|
end
|
|
11
22
|
end
|
|
12
23
|
end
|
|
@@ -74,8 +74,11 @@ module Decidim
|
|
|
74
74
|
classes = _icon_classes(options) + ["external-icon"]
|
|
75
75
|
|
|
76
76
|
if path.split(".").last == "svg"
|
|
77
|
+
icon_path = application_path(path)
|
|
78
|
+
return unless icon_path
|
|
79
|
+
|
|
77
80
|
attributes = { class: classes.join(" ") }.merge(options)
|
|
78
|
-
asset = File.read(
|
|
81
|
+
asset = File.read(icon_path)
|
|
79
82
|
asset.gsub("<svg ", "<svg#{tag_builder.tag_options(attributes)} ").html_safe
|
|
80
83
|
else
|
|
81
84
|
image_pack_tag(path, class: classes.join(" "), style: "display: none")
|
|
@@ -83,9 +86,17 @@ module Decidim
|
|
|
83
86
|
end
|
|
84
87
|
|
|
85
88
|
def application_path(path)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
# Force the path to be returned without the protocol and host even when a
|
|
90
|
+
# custom asset host has been defined. The host parameter needs to be a
|
|
91
|
+
# non-nil because otherwise it will be set to the asset host at
|
|
92
|
+
# ActionView::Helpers::AssetUrlHelper#compute_asset_host.
|
|
93
|
+
img_path = asset_pack_path(path, host: "", protocol: :relative)
|
|
94
|
+
path = Rails.public_path.join(img_path.sub(%r{^/}, ""))
|
|
95
|
+
return unless File.exist?(path)
|
|
96
|
+
|
|
97
|
+
path
|
|
98
|
+
rescue ::Webpacker::Manifest::MissingEntryError
|
|
99
|
+
nil
|
|
89
100
|
end
|
|
90
101
|
|
|
91
102
|
# Allows to create role attribute according to accessibility rules
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
# View helpers related to the layout.
|
|
5
|
+
module LayoutHelper
|
|
6
|
+
include Decidim::ModalHelper
|
|
7
|
+
include Decidim::TooltipHelper
|
|
8
|
+
|
|
9
|
+
# Public: Generates a set of meta tags that generate the different favicon
|
|
10
|
+
# versions for an organization.
|
|
11
|
+
#
|
|
12
|
+
# Returns a safe String with the versions.
|
|
13
|
+
def favicon
|
|
14
|
+
return if current_organization.favicon.blank?
|
|
15
|
+
|
|
16
|
+
safe_join(Decidim::OrganizationFaviconUploader::SIZES.map do |version, size|
|
|
17
|
+
favicon_link_tag(current_organization.attached_uploader(:favicon).variant_url(version, host: current_organization.host), sizes: "#{size}x#{size}")
|
|
18
|
+
end)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def apple_favicon
|
|
22
|
+
icon_image = current_organization.attached_uploader(:favicon).variant_url(:medium, host: current_organization.host)
|
|
23
|
+
return unless icon_image
|
|
24
|
+
|
|
25
|
+
favicon_link_tag(icon_image, rel: "apple-touch-icon", type: "image/png")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def legacy_favicon
|
|
29
|
+
variant = :favicon if current_organization.favicon.content_type != "image/vnd.microsoft.icon"
|
|
30
|
+
icon_image = current_organization.attached_uploader(:favicon).variant_url(variant, host: current_organization.host)
|
|
31
|
+
return unless icon_image
|
|
32
|
+
|
|
33
|
+
favicon_link_tag(icon_image, rel: "icon", sizes: "any", type: nil)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Outputs an SVG-based icon.
|
|
37
|
+
#
|
|
38
|
+
# name - The String with the icon name.
|
|
39
|
+
# options - The Hash options used to customize the icon (default {}):
|
|
40
|
+
# :width - The Number of width in pixels (optional).
|
|
41
|
+
# :height - The Number of height in pixels (optional).
|
|
42
|
+
# :title - The title for the SVG element (optional, similar to alt for img)
|
|
43
|
+
# :aria_label - The String to set as aria label (optional).
|
|
44
|
+
# :aria_hidden - The Truthy value to enable aria_hidden (optional).
|
|
45
|
+
# :role - The String to set as the role (optional).
|
|
46
|
+
# :class - The String to add as a CSS class (optional).
|
|
47
|
+
#
|
|
48
|
+
# Returns a String.
|
|
49
|
+
def redesigned_icon(name, options = {})
|
|
50
|
+
default_html_properties = {
|
|
51
|
+
"width" => "1em",
|
|
52
|
+
"height" => "1em",
|
|
53
|
+
"role" => "img",
|
|
54
|
+
"aria-hidden" => "true"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
html_properties = options.with_indifferent_access.transform_keys(&:dasherize).slice("width", "height", "aria-label", "role", "aria-hidden", "class", "style")
|
|
58
|
+
html_properties = default_html_properties.merge(html_properties)
|
|
59
|
+
|
|
60
|
+
href = Decidim.cors_enabled ? "" : asset_pack_path("media/images/remixicon.symbol.svg")
|
|
61
|
+
|
|
62
|
+
content_tag :svg, html_properties do
|
|
63
|
+
content_tag :use, nil, "href" => "#{href}#ri-#{name}", tabindex: -1
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def legacy_icon(name, options = {})
|
|
68
|
+
options = options.with_indifferent_access
|
|
69
|
+
html_properties = {}
|
|
70
|
+
|
|
71
|
+
html_properties["width"] = options[:width]
|
|
72
|
+
html_properties["height"] = options[:height]
|
|
73
|
+
html_properties["aria-label"] = options[:aria_label] || options[:"aria-label"]
|
|
74
|
+
html_properties["role"] = options[:role] || "img"
|
|
75
|
+
html_properties["aria-hidden"] = options[:aria_hidden] || options[:"aria-hidden"]
|
|
76
|
+
|
|
77
|
+
html_properties["class"] = (["icon--#{name}"] + _icon_classes(options)).join(" ")
|
|
78
|
+
|
|
79
|
+
title = options["title"] || html_properties["aria-label"]
|
|
80
|
+
if title.blank? && html_properties["role"] == "img"
|
|
81
|
+
# This will make the accessibility audit tools happy as with the "img"
|
|
82
|
+
# role, the alternative text (aria-label) and title are required for the
|
|
83
|
+
# element. This will also force the SVG to be hidden because otherwise
|
|
84
|
+
# the screen reader would announce the icon name which can be in
|
|
85
|
+
# different language (English) than the page language which is not
|
|
86
|
+
# allowed.
|
|
87
|
+
title = name
|
|
88
|
+
html_properties["aria-label"] = title
|
|
89
|
+
html_properties["aria-hidden"] = true
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
href = Decidim.cors_enabled ? "" : asset_pack_path("media/images/icons.svg")
|
|
93
|
+
|
|
94
|
+
content_tag :svg, html_properties do
|
|
95
|
+
inner = content_tag :title, title
|
|
96
|
+
inner += content_tag :use, nil, "href" => "#{href}#icon-#{name}"
|
|
97
|
+
|
|
98
|
+
inner
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def icon(*args)
|
|
103
|
+
redesign_enabled? ? redesigned_icon(*args) : legacy_icon(*args)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Outputs a SVG icon from an external file. It apparently renders an image
|
|
107
|
+
# tag, but then a JS script kicks in and replaces it with an inlined SVG
|
|
108
|
+
# version.
|
|
109
|
+
#
|
|
110
|
+
# path - The asset's path
|
|
111
|
+
#
|
|
112
|
+
# Returns an <img /> tag with the SVG icon.
|
|
113
|
+
def external_icon(path, options = {})
|
|
114
|
+
classes = _icon_classes(options) + ["external-icon"]
|
|
115
|
+
|
|
116
|
+
if path.split(".").last == "svg"
|
|
117
|
+
icon_path = application_path(path)
|
|
118
|
+
return unless icon_path
|
|
119
|
+
|
|
120
|
+
attributes = { class: classes.join(" ") }.merge(options)
|
|
121
|
+
asset = File.read(icon_path)
|
|
122
|
+
asset.gsub("<svg ", "<svg#{tag_builder.tag_options(attributes)} ").html_safe
|
|
123
|
+
else
|
|
124
|
+
image_pack_tag(path, class: classes.join(" "), style: "display: none")
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def application_path(path)
|
|
129
|
+
# Force the path to be returned without the protocol and host even when a
|
|
130
|
+
# custom asset host has been defined. The host parameter needs to be a
|
|
131
|
+
# non-nil because otherwise it will be set to the asset host at
|
|
132
|
+
# ActionView::Helpers::AssetUrlHelper#compute_asset_host.
|
|
133
|
+
img_path = asset_pack_path(path, host: "", protocol: :relative)
|
|
134
|
+
path = Rails.public_path.join(img_path.sub(%r{^/}, ""))
|
|
135
|
+
return unless File.exist?(path)
|
|
136
|
+
|
|
137
|
+
path
|
|
138
|
+
rescue ::Webpacker::Manifest::MissingEntryError
|
|
139
|
+
nil
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Allows to create role attribute according to accessibility rules
|
|
143
|
+
#
|
|
144
|
+
# Returns role attribute string if role option is specified
|
|
145
|
+
def role(options = {})
|
|
146
|
+
"role=\"#{options[:role]}\" " if options[:role]
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def _icon_classes(options = {})
|
|
150
|
+
classes = options[:remove_icon_class] ? [] : ["icon"]
|
|
151
|
+
classes += [options[:class]]
|
|
152
|
+
classes.compact
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def extended_navigation_bar(items, max_items: 5)
|
|
156
|
+
return unless items.any?
|
|
157
|
+
|
|
158
|
+
extra_items = items.slice((max_items + 1)..-1) || []
|
|
159
|
+
active_item = items.find { |item| item[:active] }
|
|
160
|
+
|
|
161
|
+
controller.view_context.render partial: "decidim/shared/extended_navigation_bar", locals: {
|
|
162
|
+
items:,
|
|
163
|
+
extra_items:,
|
|
164
|
+
active_item:,
|
|
165
|
+
max_items:
|
|
166
|
+
}
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Renders a view with the customizable CSS variables in two flavours:
|
|
170
|
+
# 1. as a hexadecimal valid CSS color (ie: #ff0000)
|
|
171
|
+
# 2. as a disassembled RGB components (ie: 255 0 0)
|
|
172
|
+
#
|
|
173
|
+
# Example:
|
|
174
|
+
#
|
|
175
|
+
# --primary: #ff0000;
|
|
176
|
+
# --primary-rgb: 255,0,0
|
|
177
|
+
#
|
|
178
|
+
# Hexadecimal variables can be used as a normal CSS color:
|
|
179
|
+
#
|
|
180
|
+
# color: var(--primary)
|
|
181
|
+
#
|
|
182
|
+
# While the disassembled variant can be used where you need to manipulate
|
|
183
|
+
# the color somehow (ie: adding a background transparency):
|
|
184
|
+
#
|
|
185
|
+
# background-color: rgba(var(--primary-rgb), 0.5)
|
|
186
|
+
def organization_colors
|
|
187
|
+
css = current_organization.colors.each.map { |k, v| "--#{k}: #{v};--#{k}-rgb: #{v[1..2].hex} #{v[3..4].hex} #{v[5..6].hex};" }.join
|
|
188
|
+
render partial: "layouts/decidim/organization_colors", locals: { css: }
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
<<<<<<< HEAD
|
|
192
|
+
def current_user_unread_data
|
|
193
|
+
return {} if current_user.blank?
|
|
194
|
+
|
|
195
|
+
{}.tap do |d|
|
|
196
|
+
d.merge!(unread_notifications: true) if current_user.notifications.any?
|
|
197
|
+
d.merge!(unread_conversations: true) if current_user.unread_conversations.any?
|
|
198
|
+
d.merge!(unread_items: d.present?)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
||||||| parent of 53b6893e5c (Use local emojibase data instead of CDN)
|
|
203
|
+
=======
|
|
204
|
+
# Public: Gets the name of the webpacker entrypoint that will be used
|
|
205
|
+
# for the locale of the Emojibase NPM package, used with @picmo/popup-picker
|
|
206
|
+
#
|
|
207
|
+
# Returns a string with the entrypoint name
|
|
208
|
+
def emojibase_entrypoint_locale
|
|
209
|
+
entrypoint = Decidim::Webpacker.configuration.entrypoints.keys.select do |entry|
|
|
210
|
+
entry == "decidim_emojibase_#{I18n.locale}"
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
return "decidim_emojibase_en" if entrypoint.empty?
|
|
214
|
+
|
|
215
|
+
entrypoint.first
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
>>>>>>> 53b6893e5c (Use local emojibase data instead of CDN)
|
|
219
|
+
private
|
|
220
|
+
|
|
221
|
+
def tag_builder
|
|
222
|
+
@tag_builder ||= ActionView::Helpers::TagHelper::TagBuilder.new(self)
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
@@ -16,13 +16,18 @@ module Decidim
|
|
|
16
16
|
#
|
|
17
17
|
# Returns an HTML-safe String.
|
|
18
18
|
def decidim_sanitize(html, options = {})
|
|
19
|
+
scrubber = options[:scrubber] || Decidim::UserInputScrubber.new
|
|
19
20
|
if options[:strip_tags]
|
|
20
|
-
strip_tags sanitize(html, scrubber:
|
|
21
|
+
strip_tags sanitize(html, scrubber: scrubber)
|
|
21
22
|
else
|
|
22
|
-
sanitize(html, scrubber:
|
|
23
|
+
sanitize(html, scrubber: scrubber)
|
|
23
24
|
end
|
|
24
25
|
end
|
|
25
26
|
|
|
27
|
+
def decidim_sanitize_admin(html, options = {})
|
|
28
|
+
decidim_sanitize(html, { scrubber: Decidim::AdminInputScrubber.new }.merge(options))
|
|
29
|
+
end
|
|
30
|
+
|
|
26
31
|
def decidim_sanitize_newsletter(html, options = {})
|
|
27
32
|
if options[:strip_tags]
|
|
28
33
|
strip_tags sanitize(html, scrubber: Decidim::NewsletterScrubber.new)
|
|
@@ -32,7 +37,11 @@ module Decidim
|
|
|
32
37
|
end
|
|
33
38
|
|
|
34
39
|
def decidim_sanitize_editor(html, options = {})
|
|
35
|
-
content_tag(:div, decidim_sanitize(html, options), class: %w(ql-editor
|
|
40
|
+
content_tag(:div, decidim_sanitize(html, options), class: %w(ql-editor-display))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def decidim_sanitize_editor_admin(html, options = {})
|
|
44
|
+
decidim_sanitize_editor(html, { scrubber: Decidim::AdminInputScrubber.new }.merge(options))
|
|
36
45
|
end
|
|
37
46
|
|
|
38
47
|
def decidim_html_escape(text)
|
|
@@ -102,9 +111,10 @@ module Decidim
|
|
|
102
111
|
#
|
|
103
112
|
# @return ActiveSupport::SafeBuffer
|
|
104
113
|
def render_sanitized_content(resource, method)
|
|
105
|
-
content = present(resource).send(method, links: true, strip_tags: !safe_content?)
|
|
114
|
+
content = present(resource).send(method, links: true, strip_tags: !try(:safe_content?))
|
|
106
115
|
|
|
107
|
-
return decidim_sanitize(content, {}) unless safe_content?
|
|
116
|
+
return decidim_sanitize(content, {}) unless try(:safe_content?)
|
|
117
|
+
return decidim_sanitize_editor_admin(content, {}) if try(:safe_content_admin?)
|
|
108
118
|
|
|
109
119
|
decidim_sanitize_editor(content)
|
|
110
120
|
end
|
|
@@ -87,6 +87,12 @@ module Decidim
|
|
|
87
87
|
@top_scopes ||= scopes.top_level
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
+
def participatory_spaces
|
|
91
|
+
@participatory_spaces ||= Decidim.participatory_space_manifests.flat_map do |manifest|
|
|
92
|
+
manifest.participatory_spaces.call(self)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
90
96
|
def public_participatory_spaces
|
|
91
97
|
@public_participatory_spaces ||= Decidim.participatory_space_manifests.flat_map do |manifest|
|
|
92
98
|
manifest.participatory_spaces.call(self).public_spaces
|
|
@@ -15,5 +15,33 @@ module Decidim
|
|
|
15
15
|
has_many :scopes, class_name: "Decidim::Scope", inverse_of: :scope_type, dependent: :nullify
|
|
16
16
|
|
|
17
17
|
validates :name, presence: true
|
|
18
|
+
|
|
19
|
+
before_destroy :detach_dynamic_associations
|
|
20
|
+
|
|
21
|
+
def self.log_presenter_class_for(_log)
|
|
22
|
+
Decidim::AdminLog::ScopeTypePresenter
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
# This method detaches all records that may have association with the scope
|
|
28
|
+
# type. This cannot be done directly using the `dependent` option in the
|
|
29
|
+
# `has_many` relation in order to avoid tight coupling between the modules.
|
|
30
|
+
#
|
|
31
|
+
# This logic does not have to be applied to any classes that have been
|
|
32
|
+
# defined as `has_many` associations within this model already as they are
|
|
33
|
+
# already handled by the `dependent` option.
|
|
34
|
+
def detach_dynamic_associations
|
|
35
|
+
ActiveRecord::Base.descendants.each do |cls|
|
|
36
|
+
next if cls.abstract_class? || !cls.name&.match?(/^Decidim::/)
|
|
37
|
+
next if [self.class, Decidim::Scope].include?(cls)
|
|
38
|
+
|
|
39
|
+
cls.reflect_on_all_associations(:belongs_to).each do |ref|
|
|
40
|
+
next unless ref.options[:class_name] == self.class.name
|
|
41
|
+
|
|
42
|
+
cls.where(ref.options[:foreign_key] => id).update_all(ref.options[:foreign_key] => nil) # rubocop:disable Rails/SkipsModelValidations
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
18
46
|
end
|
|
19
47
|
end
|
|
@@ -70,7 +70,9 @@ export default class ClipboardOverride extends Clipboard {
|
|
|
70
70
|
const text = ev.clipboardData.getData("text/plain");
|
|
71
71
|
const files = Array.from(ev.clipboardData.files || []);
|
|
72
72
|
if (!html && files.length > 0) {
|
|
73
|
-
this.quill.uploader
|
|
73
|
+
if (typeof this.quill.uploader !== "undefined") {
|
|
74
|
+
this.quill.uploader.upload(range, files);
|
|
75
|
+
}
|
|
74
76
|
return;
|
|
75
77
|
}
|
|
76
78
|
if (html && files.length > 0) {
|
|
@@ -79,7 +81,9 @@ export default class ClipboardOverride extends Clipboard {
|
|
|
79
81
|
doc.body.childElementCount === 1 &&
|
|
80
82
|
doc.body.firstElementChild.tagName === "IMG"
|
|
81
83
|
) {
|
|
82
|
-
this.quill.uploader
|
|
84
|
+
if (typeof this.quill.uploader !== "undefined") {
|
|
85
|
+
this.quill.uploader.upload(range, files);
|
|
86
|
+
}
|
|
83
87
|
return;
|
|
84
88
|
}
|
|
85
89
|
}
|