decidim-core 0.26.5 → 0.26.7

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.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/announcement_cell.rb +1 -1
  3. data/app/cells/decidim/content_blocks/cta_cell.rb +1 -1
  4. data/app/cells/decidim/content_blocks/hero/show.erb +1 -1
  5. data/app/cells/decidim/content_blocks/highlighted_content_banner/show.erb +1 -1
  6. data/app/cells/decidim/content_blocks/sub_hero_cell.rb +1 -1
  7. data/app/controllers/decidim/links_controller.rb +8 -11
  8. data/app/helpers/decidim/cells_helper.rb +1 -0
  9. data/app/helpers/decidim/external_domain_helper.rb +14 -3
  10. data/app/helpers/decidim/sanitize_helper.rb +15 -5
  11. data/app/models/decidim/scope_type.rb +28 -0
  12. data/app/packs/src/decidim/editor/clipboard_override.js +6 -2
  13. data/app/packs/src/decidim/editor.js +63 -33
  14. data/app/packs/stylesheets/decidim/_editor.scss +129 -0
  15. data/app/packs/stylesheets/decidim/extras/_quill.scss +0 -6
  16. data/app/packs/stylesheets/decidim/modules/_buttons.scss +10 -6
  17. data/app/packs/stylesheets/decidim/modules/_cards.scss +1 -1
  18. data/app/packs/stylesheets/decidim/modules/_comments.scss +24 -0
  19. data/app/packs/stylesheets/decidim/vizzs/_linechart.scss +2 -2
  20. data/app/packs/stylesheets/decidim/vizzs/_rowchart.scss +2 -2
  21. data/app/presenters/decidim/notification_presenter.rb +1 -1
  22. data/app/presenters/decidim/user_group_presenter.rb +1 -1
  23. data/app/presenters/decidim/user_presenter.rb +1 -1
  24. data/app/scrubbers/decidim/admin_input_scrubber.rb +27 -0
  25. data/app/scrubbers/decidim/user_input_scrubber.rb +32 -5
  26. data/app/services/decidim/traceability.rb +1 -0
  27. data/app/views/decidim/links/_invalid_url_modal.html.erb +17 -0
  28. data/app/views/decidim/links/_modal.html.erb +1 -1
  29. data/app/views/decidim/links/invalid_url.js.erb +24 -0
  30. data/app/views/decidim/links/new.html.erb +1 -1
  31. data/app/views/decidim/messaging/conversations/_conversation.html.erb +1 -5
  32. data/app/views/decidim/pages/_standalone.html.erb +1 -1
  33. data/app/views/decidim/pages/_tabbed.html.erb +1 -1
  34. data/config/locales/ar.yml +422 -7
  35. data/config/locales/bg.yml +1 -4
  36. data/config/locales/ca.yml +20 -18
  37. data/config/locales/cs.yml +21 -29
  38. data/config/locales/da.yml +3 -0
  39. data/config/locales/de.yml +4 -23
  40. data/config/locales/el.yml +2 -4
  41. data/config/locales/en.yml +15 -13
  42. data/config/locales/eo.yml +2 -1
  43. data/config/locales/es-MX.yml +19 -17
  44. data/config/locales/es-PY.yml +19 -17
  45. data/config/locales/es.yml +20 -18
  46. data/config/locales/et.yml +3 -0
  47. data/config/locales/eu.yml +87 -63
  48. data/config/locales/fa-IR.yml +1 -0
  49. data/config/locales/fi-plain.yml +0 -19
  50. data/config/locales/fi.yml +17 -15
  51. data/config/locales/fr-CA.yml +22 -17
  52. data/config/locales/fr.yml +20 -15
  53. data/config/locales/ga-IE.yml +1 -0
  54. data/config/locales/gl.yml +0 -22
  55. data/config/locales/gn-PY.yml +3 -0
  56. data/config/locales/hr.yml +3 -0
  57. data/config/locales/hu.yml +48 -24
  58. data/config/locales/id-ID.yml +2 -4
  59. data/config/locales/is-IS.yml +2 -1
  60. data/config/locales/it.yml +1 -11
  61. data/config/locales/ja.yml +9 -23
  62. data/config/locales/ka-GE.yml +3 -0
  63. data/config/locales/kaa.yml +1 -0
  64. data/config/locales/lb.yml +0 -4
  65. data/config/locales/lt.yml +0 -33
  66. data/config/locales/lv.yml +0 -3
  67. data/config/locales/nl.yml +1 -20
  68. data/config/locales/no.yml +1 -24
  69. data/config/locales/oc-FR.yml +2 -0
  70. data/config/locales/pl.yml +0 -33
  71. data/config/locales/pt-BR.yml +2 -6
  72. data/config/locales/pt.yml +0 -4
  73. data/config/locales/ro-RO.yml +5 -8
  74. data/config/locales/ru.yml +1 -3
  75. data/config/locales/sk.yml +3 -5
  76. data/config/locales/sl.yml +1 -0
  77. data/config/locales/sr-CS.yml +2 -0
  78. data/config/locales/sv.yml +1 -24
  79. data/config/locales/tr-TR.yml +3 -7
  80. data/config/locales/uk.yml +1 -3
  81. data/config/locales/zh-CN.yml +0 -4
  82. data/config/locales/zh-TW.yml +1712 -0
  83. data/lib/decidim/core/test/shared_examples/comments_examples.rb +36 -0
  84. data/lib/decidim/core/test/shared_examples/editor_shared_examples.rb +10 -0
  85. data/lib/decidim/core/test/shared_examples/rich_text_editor_examples.rb +7 -3
  86. data/lib/decidim/core/test.rb +1 -0
  87. data/lib/decidim/core/version.rb +1 -1
  88. data/lib/decidim/form_builder.rb +0 -1
  89. data/lib/decidim/publicable.rb +4 -0
  90. metadata +12 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8937550934aed6ed69fa84837edbbc2902c5fd6779654a5180a63abbfe25d700
4
- data.tar.gz: ba86b8da585b54db8845cf1d5e476086db70d03920f99ddf3a32cbe023521992
3
+ metadata.gz: 2d573b856227ec581d40d90cff9a85c1f21502a1ed6278b82aa9768a434f0e9c
4
+ data.tar.gz: 2ca2fff70b6e6b9314450c35ab22965b3ba60af303a2839c7716e502cb566b3a
5
5
  SHA512:
6
- metadata.gz: de40caba191fb9ff0b88bbf9055fbb4592fcc12352c6e35d21d812e87399b1772254d669438ade3ada960ca994247ab87b3eb4743e80df9121cb3bb07c6a9f18
7
- data.tar.gz: c115b3d2e531d0b0d8e43f7b41a863dc51eb2c076bc8c4f2c8731e642fb191115b2fdf6aebe6a3cf28c48fb746c3e9cec85ea9a5be630d382ee695cff238278f
6
+ metadata.gz: 1000d09afe7e9af0586fa14c917c77a150bf9f55adee9d0a243744799a9cf9c84aa364b0f014cdec6eda3855c10b4b15772732c979d9f15e381c8a62e78aad8f
7
+ data.tar.gz: 1a4feafaa713a4fa540aab815e0306f125cc74d45599d5defbec2e9dd2cce8bc6223acd0148424b3973a0f1d6853b96cd3ee9a6fda7ff45cc91073fd2b84ac8a
@@ -62,7 +62,7 @@ module Decidim
62
62
  end
63
63
 
64
64
  def clean(value)
65
- decidim_sanitize(translated_attribute(value))
65
+ decidim_sanitize_admin(translated_attribute(value))
66
66
  end
67
67
  end
68
68
  end
@@ -16,7 +16,7 @@ module Decidim
16
16
  end
17
17
 
18
18
  def translated_description
19
- @translated_description ||= decidim_sanitize_editor(translated_attribute(model.settings.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
- <%= decidim_sanitize translated_welcome_text %>
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
- <%= decidim_sanitize_editor translated_attribute current_organization.highlighted_content_banner_short_description %>
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 = decidim_sanitize(translated_attribute(current_organization.description))
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.
@@ -21,24 +21,21 @@ module Decidim
21
21
 
22
22
  def invalid_url
23
23
  flash[:alert] = I18n.t("decidim.links.invalid_url")
24
- redirect_to decidim.root_path
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]).to_s
38
+ @external_url ||= URI.parse(params[:external_url])
42
39
  end
43
40
  end
44
41
  end
@@ -35,6 +35,7 @@ module Decidim
35
35
  end
36
36
 
37
37
  def user_flaggable?
38
+ return if (try(:profile_holder) || try(:profile_user) || try(:model)).try(:blocked)
38
39
  return unless context[:controller].try(:flaggable_controller?)
39
40
 
40
41
  true
@@ -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, "#{@url_parts[:protocol]}//") +
8
- content_tag(:span, @url_parts[:domain], class: "alert") +
9
- content_tag(:span, @url_parts[:path])
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
@@ -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: Decidim::UserInputScrubber.new)
21
+ strip_tags sanitize(html, scrubber: scrubber)
21
22
  else
22
- sanitize(html, scrubber: Decidim::UserInputScrubber.new)
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 ql-reset-decidim))
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
@@ -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.upload(range, files);
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.upload(range, files);
84
+ if (typeof this.quill.uploader !== "undefined") {
85
+ this.quill.uploader.upload(range, files);
86
+ }
83
87
  return;
84
88
  }
85
89
  }
@@ -1,11 +1,25 @@
1
1
  /* eslint-disable require-jsdoc */
2
2
 
3
- import lineBreakButtonHandler from "src/decidim/editor/linebreak_module"
4
- import "src/decidim/editor/clipboard_override"
5
- import "src/decidim/vendor/image-resize.min"
6
- import "src/decidim/vendor/image-upload.min"
3
+ import lineBreakButtonHandler from "src/decidim/editor/linebreak_module";
4
+ import "src/decidim/editor/clipboard_override";
5
+ import "src/decidim/vendor/image-resize.min";
6
+ import "src/decidim/vendor/image-upload.min";
7
7
 
8
- const quillFormats = ["bold", "italic", "link", "underline", "header", "list", "video", "image", "alt", "break", "width", "style", "code", "blockquote", "indent"];
8
+ const quillFormats = [
9
+ "bold",
10
+ "italic",
11
+ "link",
12
+ "underline",
13
+ "header",
14
+ "list",
15
+ "alt",
16
+ "break",
17
+ "width",
18
+ "style",
19
+ "code",
20
+ "blockquote",
21
+ "indent"
22
+ ];
9
23
 
10
24
  export default function createQuillEditor(container) {
11
25
  const toolbar = $(container).data("toolbar");
@@ -17,26 +31,28 @@ export default function createQuillEditor(container) {
17
31
  [{ list: "ordered" }, { list: "bullet" }],
18
32
  ["link", "clean"],
19
33
  ["code", "blockquote"],
20
- [{ "indent": "-1"}, { "indent": "+1" }]
34
+ [{ indent: "-1" }, { indent: "+1" }]
21
35
  ];
22
36
 
23
- let addImage = $(container).data("editorImages");
37
+ let addImage = false;
38
+ let addVideo = false;
24
39
 
25
- if (toolbar === "full") {
40
+ /**
41
+ * - basic = only basic controls without titles
42
+ * - content = basic + headings
43
+ * - full = basic + headings + image + video
44
+ */
45
+ if (toolbar === "content") {
46
+ quillToolbar = [[{ header: [2, 3, 4, 5, 6, false] }], ...quillToolbar];
47
+ } else if (toolbar === "full") {
48
+ addImage = true;
49
+ addVideo = true;
26
50
  quillToolbar = [
27
51
  [{ header: [2, 3, 4, 5, 6, false] }],
28
52
  ...quillToolbar,
29
- ["video"]
53
+ ["video"],
54
+ ["image"]
30
55
  ];
31
- } else if (toolbar === "basic") {
32
- quillToolbar = [
33
- ...quillToolbar,
34
- ["video"]
35
- ];
36
- }
37
-
38
- if (addImage) {
39
- quillToolbar.push(["image"]);
40
56
  }
41
57
 
42
58
  let modules = {
@@ -44,17 +60,26 @@ export default function createQuillEditor(container) {
44
60
  toolbar: {
45
61
  container: quillToolbar,
46
62
  handlers: {
47
- "linebreak": lineBreakButtonHandler
63
+ linebreak: lineBreakButtonHandler
48
64
  }
49
65
  }
50
66
  };
51
67
  const $input = $(container).siblings('input[type="hidden"]');
52
68
  container.innerHTML = $input.val() || "";
53
69
  const token = $('meta[name="csrf-token"]').attr("content");
70
+
71
+ if (addVideo) {
72
+ quillFormats.push("video");
73
+ }
74
+
54
75
  if (addImage) {
76
+ // Attempt to allow images only if the image support is enabled at editor support.
77
+ // see: https://github.com/quilljs/quill/issues/1108
78
+ quillFormats.push("image");
79
+
55
80
  modules.imageResize = {
56
81
  modules: ["Resize", "DisplaySize"]
57
- }
82
+ };
58
83
  modules.imageUpload = {
59
84
  url: $(container).data("uploadImagesPath"),
60
85
  method: "POST",
@@ -62,18 +87,23 @@ export default function createQuillEditor(container) {
62
87
  withCredentials: false,
63
88
  headers: { "X-CSRF-Token": token },
64
89
  callbackOK: (serverResponse, next) => {
65
- $("div.ql-toolbar").last().removeClass("editor-loading")
90
+ $("div.ql-toolbar").last().removeClass("editor-loading");
66
91
  next(serverResponse.url);
67
92
  },
68
93
  callbackKO: (serverError) => {
69
- $("div.ql-toolbar").last().removeClass("editor-loading")
94
+ $("div.ql-toolbar").last().removeClass("editor-loading");
70
95
  console.log(`Image upload error: ${serverError.message}`);
71
96
  },
72
97
  checkBeforeSend: (file, next) => {
73
- $("div.ql-toolbar").last().addClass("editor-loading")
98
+ $("div.ql-toolbar").last().addClass("editor-loading");
74
99
  next(file);
75
100
  }
76
- }
101
+ };
102
+
103
+ const text = $(container).data("dragAndDropHelpText");
104
+ $(container).after(
105
+ `<p class="help-text" style="margin-top:-1.5rem;">${text}</p>`
106
+ );
77
107
  }
78
108
  const quill = new Quill(container, {
79
109
  modules: modules,
@@ -81,6 +111,11 @@ export default function createQuillEditor(container) {
81
111
  theme: "snow"
82
112
  });
83
113
 
114
+ if (addImage === false) {
115
+ // Firefox natively implements image drop in contenteditable which is why we need to disable that
116
+ quill.root.addEventListener("drop", (ev) => ev.preventDefault());
117
+ }
118
+
84
119
  if (disabled) {
85
120
  quill.disable();
86
121
  }
@@ -95,7 +130,10 @@ export default function createQuillEditor(container) {
95
130
  });
96
131
  container.dispatchEvent(event);
97
132
 
98
- if ((text === "\n" || text === "\n\n") && quill.root.querySelectorAll(allowedEmptyContentSelector).length === 0) {
133
+ if (
134
+ (text === "\n" || text === "\n\n") &&
135
+ quill.root.querySelectorAll(allowedEmptyContentSelector).length === 0
136
+ ) {
99
137
  $input.val("");
100
138
  } else {
101
139
  const emptyParagraph = "<p><br></p>";
@@ -109,13 +147,5 @@ export default function createQuillEditor(container) {
109
147
  // After editor is ready, linebreak_module deletes two extraneous new lines
110
148
  quill.emitter.emit("editor-ready");
111
149
 
112
- if (addImage) {
113
- const text = $(container).data("dragAndDropHelpText");
114
- $(container).after(`<p class="help-text" style="margin-top:-1.5rem;">${text}</p>`);
115
- }
116
-
117
- // After editor is ready, linebreak_module deletes two extraneous new lines
118
- quill.emitter.emit("editor-ready");
119
-
120
150
  return quill;
121
151
  }
@@ -10,4 +10,133 @@
10
10
  margin-bottom: $paragraph-margin-bottom;
11
11
  text-rendering: $paragraph-text-rendering;
12
12
  }
13
+
14
+ ul,
15
+ ol{
16
+ margin-bottom: $paragraph-margin-bottom;
17
+ }
18
+ }
19
+
20
+ .ql-editor-display{
21
+ ul,
22
+ ol{
23
+ li{
24
+ list-style-type: none;
25
+ margin-bottom: .5rem;
26
+
27
+ &::before{
28
+ content: "\2022";
29
+ display: inline-block;
30
+ white-space: nowrap;
31
+ width: 1.2em;
32
+ }
33
+
34
+ &.ql-indent-1{
35
+ padding-left: 3em;
36
+ }
37
+
38
+ &.ql-indent-2{
39
+ padding-left: 6em;
40
+ }
41
+
42
+ &.ql-indent-3{
43
+ padding-left: 9em;
44
+ }
45
+
46
+ &.ql-indent-4{
47
+ padding-left: 12em;
48
+ }
49
+
50
+ &.ql-indent-5{
51
+ padding-left: 15em;
52
+ }
53
+
54
+ &.ql-indent-6{
55
+ padding-left: 18em;
56
+ }
57
+
58
+ &.ql-indent-7{
59
+ padding-left: 21em;
60
+ }
61
+
62
+ &.ql-indent-8{
63
+ padding-left: 24em;
64
+ }
65
+
66
+ &.ql-indent-9{
67
+ padding-left: 27em;
68
+ }
69
+ }
70
+ }
71
+
72
+ ol{
73
+ li{
74
+ counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
75
+ counter-increment: list-0;
76
+
77
+ &::before{ content: counter(list-0, decimal) ". "; }
78
+
79
+ &.ql-indent-1{
80
+ counter-increment: list-1;
81
+ counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
82
+
83
+ &::before{ content: counter(list-1, lower-alpha) ". "; }
84
+ }
85
+
86
+ &.ql-indent-2{
87
+ counter-increment: list-2;
88
+ counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9;
89
+
90
+ &::before{ content: counter(list-2, lower-roman) ". "; }
91
+ }
92
+
93
+ &.ql-indent-3{
94
+ counter-increment: list-3;
95
+ counter-reset: list-4 list-5 list-6 list-7 list-8 list-9;
96
+
97
+ &::before{ content: counter(list-3, decimal) ". "; }
98
+ }
99
+
100
+ &.ql-indent-4{
101
+ counter-increment: list-4;
102
+ counter-reset: list-5 list-6 list-7 list-8 list-9;
103
+
104
+ &::before{ content: counter(list-4, lower-alpha) ". "; }
105
+ }
106
+
107
+ &.ql-indent-5{
108
+ counter-increment: list-5;
109
+ counter-reset: list-6 list-7 list-8 list-9;
110
+
111
+ &::before{ content: counter(list-5, lower-roman) ". "; }
112
+ }
113
+
114
+ &.ql-indent-6{
115
+ counter-increment: list-6;
116
+ counter-reset: list-7 list-8 list-9;
117
+
118
+ &::before{ content: counter(list-6, decimal) ". "; }
119
+ }
120
+
121
+ &.ql-indent-7{
122
+ counter-increment: list-7;
123
+ counter-reset: list-8 list-9;
124
+
125
+ &::before{ content: counter(list-7, lower-alpha) ". "; }
126
+ }
127
+
128
+ &.ql-indent-8{
129
+ counter-increment: list-8;
130
+ counter-reset: list-9;
131
+
132
+ &::before{ content: counter(list-8, lower-roman) ". "; }
133
+ }
134
+
135
+ &.ql-indent-9{
136
+ counter-increment: list-9;
137
+
138
+ &::before{ content: counter(list-9, decimal) ". "; }
139
+ }
140
+ }
141
+ }
13
142
  }
@@ -11,9 +11,3 @@
11
11
  margin-top: 0;
12
12
  margin-bottom: 0;
13
13
  }
14
-
15
- .ql-reset-decidim{
16
- display: inline;
17
- padding: 0;
18
- white-space: inherit;
19
- }
@@ -123,6 +123,10 @@
123
123
  }
124
124
  }
125
125
 
126
+ &.primary{
127
+ @include button-hollow-variant(var(--primary));
128
+ }
129
+
126
130
  &.secondary{
127
131
  @include button-hollow-variant(var(--secondary));
128
132
  }
@@ -257,12 +261,12 @@
257
261
 
258
262
  .button--shadow{
259
263
  $shadows: (
260
- primary: shade($primary, 50),
261
- secondary: shade($secondary, 50),
262
- success: shade($success, 50),
263
- warning: shade($warning, 50),
264
- alert: shade($alert, 50),
265
- muted: shade($muted, 50),
264
+ primary: shade($primary, 50%),
265
+ secondary: shade($secondary, 50%),
266
+ success: shade($success, 50%),
267
+ warning: shade($warning, 50%),
268
+ alert: shade($alert, 50%),
269
+ muted: shade($muted, 50%),
266
270
  );
267
271
 
268
272
  @include modifiers(background-color, $shadows){
@@ -934,7 +934,7 @@ a .card__title{
934
934
  @include modifiers(
935
935
  color,
936
936
  (
937
- muted: tint($muted, 50),
937
+ muted: tint($muted, 50%),
938
938
  )
939
939
  ){
940
940
  margin-top: -$global-margin * .95;
@@ -17,6 +17,30 @@ $comment-form-bg: $light-gray;
17
17
 
18
18
  .comment-thread{
19
19
  @extend .card;
20
+
21
+ .show-comment-replies{
22
+ display: none;
23
+ }
24
+
25
+ .hide-comment-replies{
26
+ display: inline;
27
+ }
28
+
29
+ .comment__hide{
30
+ float: left;
31
+ margin-bottom: 0;
32
+ }
33
+
34
+ .no-comments{
35
+ .show-comment-replies{
36
+ display: inline;
37
+ }
38
+
39
+ .hide-comment-replies,
40
+ .replies{
41
+ display: none;
42
+ }
43
+ }
20
44
  }
21
45
 
22
46
  .comment-thread__title{
@@ -36,8 +36,8 @@
36
36
  @mixin loop-colors-types($color, $max: 12){
37
37
  @for $i from 0 through ($max - 1){
38
38
  $interval: ($i % 4) * 24 + 1;
39
- $tints: tint($color, $interval);
40
- $shades: shade($color, $interval);
39
+ $tints: tint($color, $interval * 1%);
40
+ $shades: shade($color, $interval * 1%);
41
41
  $adjusts: adjust-color($color, $lightness: $interval * 1%, $hue: -$interval);
42
42
 
43
43
  .type-#{$i}:not(.legend){
@@ -27,8 +27,8 @@
27
27
  @mixin loop-colors-types($color, $max: 12){
28
28
  @for $i from 0 through ($max - 1){
29
29
  $interval: ($i % 4) * 24 + 1;
30
- $tints: tint($color, $interval);
31
- $shades: shade($color, $interval);
30
+ $tints: tint($color, $interval * 1%);
31
+ $shades: shade($color, $interval * 1%);
32
32
  $adjusts: adjust-color($color, $lightness: $interval * 1%, $hue: -$interval);
33
33
 
34
34
  .type-#{$i}{
@@ -11,7 +11,7 @@ module Decidim
11
11
 
12
12
  def created_at_in_words
13
13
  if created_at.between?(1.month.ago, Time.current)
14
- time_ago_in_words(created_at)
14
+ I18n.t("decidim.user_conversations.index.time_ago", time: time_ago_in_words(created_at))
15
15
  else
16
16
  format = created_at.year == Time.current.year ? :ddmm : :ddmmyyyy
17
17
  I18n.l(created_at, format: format)
@@ -16,7 +16,7 @@ module Decidim
16
16
  end
17
17
 
18
18
  def can_be_contacted?
19
- true
19
+ true unless blocked?
20
20
  end
21
21
 
22
22
  def officialization_text
@@ -61,7 +61,7 @@ module Decidim
61
61
  end
62
62
 
63
63
  def can_be_contacted?
64
- true
64
+ true unless blocked?
65
65
  end
66
66
 
67
67
  def officialization_text