decidim-forms 0.30.5 → 0.30.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e06e7d226bccdc4f66eb8caf167f5b1df063e7d5d4177e9fa1ecb5c128f0a5b6
4
- data.tar.gz: e3e81b54b7935115821b67dd2a7bd79a5688ab1609d097318d032667d3318023
3
+ metadata.gz: c7f2281f858b81bfc82836d8d4b6ae6941f5a3fe7c3f10082ec8dc4081617a6d
4
+ data.tar.gz: 00fefb51de81521205f3082be6b7f6bd10e5657e630c7f08e7f1188f4d6685c2
5
5
  SHA512:
6
- metadata.gz: 0f22985f3338a928b32c0248789e0dea4f4052d82696ecbb42951f4a55b370eae67df3eb44bb46d9efaba5e19ad73148e4aaaf348d2b716437eb11af983d6cfe
7
- data.tar.gz: 5244b69958892b107747377b6125468c49eaeb1a86000cc241158f721acdcb8d86c1fb1728b3ff387d8ec85f73f66ae68a9e0f4ec0d6e7f81ca1a8a145588060
6
+ metadata.gz: a5aba7ebe49e5ce098ea8eed16af98409617eac6c5b23fa792b3d984faa67060f37c664d25f7c22e2ac871efa1aa12e3d60b51a411fe806a2b6427ea0f9ed234
7
+ data.tar.gz: 22c4677cc60bd3538156b57752226857a15ad831f4adcc5b2bda67aa2432af8f0949bd9ae61d18df9d55ff9ae38f3ce18fe82c1a012c15f8ca3932e0bcf1aa55
@@ -43,6 +43,11 @@ module Decidim
43
43
  Decidim::Forms::QuestionnaireParticipants.new(self).count_participants
44
44
  end
45
45
 
46
+ # Public: Returns only the actual question types (excludes separators and title_and_description)
47
+ def question_types
48
+ questions.not_separator.not_title_and_description
49
+ end
50
+
46
51
  private
47
52
 
48
53
  # salt is used to generate secure hash in anonymous answers
@@ -10,6 +10,7 @@ import AutoLabelByPositionComponent from "src/decidim/admin/auto_label_by_positi
10
10
  import createDynamicFields from "src/decidim/admin/dynamic_fields.component"
11
11
  import createFieldDependentInputs from "src/decidim/admin/field_dependent_inputs.component"
12
12
  import initLanguageChangeSelect from "src/decidim/admin/choose_language"
13
+ import sortable from "html5sortable/dist/html5sortable.es"
13
14
 
14
15
  export default function createEditableForm() {
15
16
  const wrapperSelector = ".questionnaire-questions";
@@ -23,6 +24,7 @@ export default function createEditableForm() {
23
24
  const matrixRowRemoveFieldButtonSelector = ".remove-matrix-row";
24
25
  const addMatrixRowButtonSelector = ".add-matrix-row";
25
26
  const maxChoicesWrapperSelector = ".questionnaire-question-max-choices";
27
+ const responseOptionFreeTextSelector = ".questionnaire-question-answer-option-free-text";
26
28
 
27
29
  const displayConditionFieldSelector = ".questionnaire-question-display-condition";
28
30
  const displayConditionsWrapperSelector = ".questionnaire-question-display-conditions";
@@ -336,7 +338,10 @@ export default function createEditableForm() {
336
338
  const dynamicFieldsMatrixRows = dynamicFieldsForMatrixRows[fieldId];
337
339
 
338
340
  const onQuestionTypeChange = () => {
339
- if (isMultipleChoiceOption($fieldQuestionTypeSelect.val())) {
341
+ const $currentField = $fieldQuestionTypeSelect.parents(fieldSelector);
342
+ const questionType = $fieldQuestionTypeSelect.val();
343
+
344
+ if (isMultipleChoiceOption(questionType)) {
340
345
  const nOptions = $fieldQuestionTypeSelect.parents(fieldSelector).find(answerOptionFieldSelector).length;
341
346
 
342
347
  if (nOptions === 0) {
@@ -353,6 +358,12 @@ export default function createEditableForm() {
353
358
  dynamicFieldsMatrixRows._addField();
354
359
  }
355
360
  }
361
+
362
+ if (questionType === "sorting") {
363
+ $currentField.find(responseOptionFreeTextSelector).addClass("hidden");
364
+ } else {
365
+ $currentField.find(responseOptionFreeTextSelector).removeClass("hidden");
366
+ }
356
367
  };
357
368
 
358
369
  $fieldQuestionTypeSelect.on("change", onQuestionTypeChange);
@@ -392,6 +403,15 @@ export default function createEditableForm() {
392
403
 
393
404
  initLanguageChangeSelect($field.find("select.language-change").toArray());
394
405
 
406
+ const sortableContainer = document.querySelector(".questionnaire-questions-list[data-draggable-table]");
407
+ if (sortableContainer) {
408
+ sortable(sortableContainer, {
409
+ forcePlaceholderSize: true,
410
+ items: ".questionnaire-question",
411
+ handle: sortableContainer.dataset.draggableHandle || ".card-divider"
412
+ });
413
+ }
414
+
395
415
  // instead of initialize specific stuff, we send an event, with the DOM fragment we wanna update/refresh/bind
396
416
  document.dispatchEvent(new CustomEvent("ajax:loaded", { detail: $field[0] }));
397
417
  },
@@ -22,7 +22,7 @@
22
22
  }
23
23
 
24
24
  &__question-label {
25
- @apply text-black text-xl font-semibold relative before:content-[attr(data-answer-idx)] before:w-6 before:h-6 md:before:absolute md:before:-left-4 md:before:-translate-x-full before:inline-flex before:justify-center before:rounded-full before:bg-background before:text-lg before:text-gray-2 before:font-semibold;
25
+ @apply text-black text-xl font-semibold;
26
26
  }
27
27
 
28
28
  &__question-description {
@@ -28,13 +28,32 @@ module Decidim
28
28
  return attachments if answer.attachments.any?
29
29
  return "-" if answer.choices.empty?
30
30
 
31
- choices = answer.choices.map do |choice|
31
+ choices = build_choices
32
+
33
+ render_choices_list(choices)
34
+ end
35
+
36
+ private
37
+
38
+ def build_choices
39
+ answer.choices.map do |choice|
40
+ matrix_row_body = matrix_row_body_for(choice)
32
41
  {
33
42
  answer_option_body: choice.try(:answer_option).try(:translated_body),
34
- choice_body: body_or_custom_body(choice)
43
+ choice_body: body_or_custom_body(choice),
44
+ matrix_row_body:
35
45
  }
36
46
  end
47
+ end
48
+
49
+ def matrix_row_body_for(choice)
50
+ return unless answer.question.matrix?
51
+ return unless choice.matrix_row&.body
37
52
 
53
+ translated_attribute(choice.matrix_row.body)
54
+ end
55
+
56
+ def render_choices_list(choices)
38
57
  content_tag(:ul) do
39
58
  if answer.question.question_type == "single_option"
40
59
  choice(choices.first)
@@ -50,8 +69,6 @@ module Decidim
50
69
  end
51
70
  end
52
71
 
53
- private
54
-
55
72
  def pretty_attachment(attachment)
56
73
  # rubocop:disable Style/StringConcatenation
57
74
  # Interpolating strings that are `html_safe` is problematic with Rails.
@@ -70,7 +87,11 @@ module Decidim
70
87
 
71
88
  def choice(choice_hash)
72
89
  content_tag :li do
73
- render_body_for choice_hash
90
+ if choice_hash[:matrix_row_body].present?
91
+ content_tag(:strong, choice_hash[:matrix_row_body]) + ": " + render_body_for(choice_hash) # rubocop:disable Style/StringConcatenation
92
+ else
93
+ render_body_for choice_hash
94
+ end
74
95
  end
75
96
  end
76
97
 
@@ -26,15 +26,15 @@
26
26
  %>
27
27
  </div>
28
28
 
29
- <div class="row column">
30
- <%=
31
- form.check_box(
32
- :free_text,
33
- label: t(".free_text"),
34
- disabled: !questionnaire.questions_editable?
35
- )
36
- %>
37
- </div>
29
+ <div class="row column questionnaire-question-answer-option-free-text">
30
+ <%=
31
+ form.check_box(
32
+ :free_text,
33
+ label: t(".free_text"),
34
+ disabled: !questionnaire.questions_editable?
35
+ )
36
+ %>
37
+ </div>
38
38
  </div>
39
39
 
40
40
  <% if answer_option.persisted? %>
@@ -2,11 +2,11 @@
2
2
  <% is_expanded = question.errors.any? %>
3
3
  <div class="card questionnaire-question" id="accordion-<%= id %>-field">
4
4
  <div class="form__wrapper" data-component="accordion">
5
- <div class="card-divider">
5
+ <%= content_tag :div, class: ["card-divider", ("hover:cursor-grab" if editable)] do %>
6
6
  <h2 class="card-title flex items-center">
7
7
  <span>
8
8
  <% if editable %>
9
- <%== icon("drag-move-2-fill") %>
9
+ <%= icon("draggable", class: "dragger") %>
10
10
  <% end %>
11
11
  <%= dynamic_title(translated_attribute(question.body), class: "question-title-statement", max_length: 50, omission: "...", placeholder: t(".question")) %>
12
12
  </span>
@@ -23,14 +23,14 @@
23
23
  </button>
24
24
 
25
25
  <% if editable %>
26
- <button class="button button__xs button__transparent-secondary small alert remove-question button--title">
26
+ <button type="button" class="button button__xs button__transparent-secondary small alert remove-question button--title">
27
27
  <%= icon("delete-bin-line") %>
28
28
  <%= t(".remove") %>
29
29
  </button>
30
30
  <% end %>
31
31
  </span>
32
32
  </h2>
33
- </div>
33
+ <% end %>
34
34
 
35
35
  <div id="panel-<%= id %>-question-card" class="panel-question-card card-section collapsible <%= "panel-error" if is_expanded %>">
36
36
  <div class="row column">
@@ -39,7 +39,15 @@
39
39
  <%= cell("decidim/announcement", t(".already_answered_warning"), callout_class: "warning" ) %>
40
40
  <% end %>
41
41
 
42
- <div class="questionnaire-questions-list flex flex-col py-6 gap-6 last:pb-0" data-draggable-table data-sort-url="#" data-draggable-handle=".card-divider" id="questionnaire-questions-list">
42
+ <% list_attributes = {
43
+ class: "questionnaire-questions-list flex flex-col py-6 gap-6 last:pb-0",
44
+ id: "questionnaire-questions-list"
45
+ }
46
+ list_attributes[:"data-draggable-table"] = true if questionnaire.questions_editable?
47
+ list_attributes[:"data-sort-url"] = "#" if questionnaire.questions_editable?
48
+ list_attributes[:"data-draggable-handle"] = ".card-divider" if questionnaire.questions_editable? %>
49
+
50
+ <%= content_tag :div, list_attributes do %>
43
51
  <% @form.questions.each_with_index do |question, index| %>
44
52
  <%= fields_for "questions[questions][]", question do |question_form| %>
45
53
  <% if question.separator? %>
@@ -66,7 +74,7 @@
66
74
  <% end %>
67
75
  <% end %>
68
76
  <% end %>
69
- </div>
77
+ <% end %>
70
78
  </div>
71
79
 
72
80
  <%= append_javascript_pack_tag "decidim_forms_admin" %>
@@ -1,18 +1,18 @@
1
1
  <% question = form.object %>
2
2
 
3
3
  <div class="card questionnaire-question" id="<%= id %>-field">
4
- <div class="card-divider">
4
+ <%= content_tag :div, class: ["card-divider", ("hover:cursor-grab" if editable)] do %>
5
5
  <h2 class="card-title flex items-center">
6
6
  <span>
7
7
  <% if editable %>
8
- <%== icon("drag-move-2-fill") %>
8
+ <%= icon("draggable", class: "dragger") %>
9
9
  <% end %>
10
10
  <%= dynamic_title(t(".separator"), class: "question-title-statement", max_length: 50, omission: "...", placeholder: t(".separator")) %>
11
11
  </span>
12
12
 
13
13
  <div class="flex items-center gap-x-4 ml-auto">
14
14
  <% if editable %>
15
- <button class="button button__xs button__transparent button__transparent-secondary small alert remove-question button--title">
15
+ <button type="button" class="button button__xs button__transparent button__transparent-secondary small alert remove-question button--title">
16
16
  <%= icon("delete-bin-line") %>
17
17
  <span class="hidden md:block"><%= t(".remove") %></span>
18
18
  </button>
@@ -32,5 +32,5 @@
32
32
 
33
33
  <%= form.hidden_field :position, value: question.position || 0, disabled: !editable %>
34
34
  <%= form.hidden_field :deleted, disabled: !editable %>
35
- </div>
35
+ <% end %>
36
36
  </div>
@@ -2,12 +2,12 @@
2
2
  <% is_expanded = question.errors.any? %>
3
3
 
4
4
  <div class="card questionnaire-question" id="accordion-<%= id %>-field">
5
- <div data-component="accordion">
6
- <div class="card-divider">
5
+ <div data-controller="accordion">
6
+ <%= content_tag :div, class: ["card-divider", ("hover:cursor-grab" if editable)] do %>
7
7
  <h2 class="card-title flex items-center">
8
8
  <span>
9
9
  <% if editable %>
10
- <%== icon("drag-move-2-fill") %>
10
+ <%= icon("draggable", class: "dragger") %>
11
11
  <% end %>
12
12
  <%= dynamic_title(translated_attribute(question.body), class: "question-title-statement", max_length: 50, omission: "...", placeholder: t(".title_and_description")) %>
13
13
  </span>
@@ -23,7 +23,7 @@
23
23
  </button>
24
24
 
25
25
  <% if editable %>
26
- <button class="button button__xs button__transparent button__transparent-secondary small alert remove-question button--title">
26
+ <button type="button" class="button button__xs button__transparent button__transparent-secondary small alert remove-question button--title">
27
27
  <%= icon("delete-bin-line") %>
28
28
  <%= t(".remove") %>
29
29
  </button>
@@ -71,6 +71,6 @@
71
71
 
72
72
  <%= form.hidden_field :position, value: question.position || 0, disabled: !editable %>
73
73
  <%= form.hidden_field :deleted, disabled: !editable %>
74
- </div>
74
+ <% end %>
75
75
  </div>
76
76
  </div>
@@ -24,8 +24,7 @@
24
24
  <div class="answer-questionnaire__question">
25
25
  <%
26
26
  label_options = {
27
- class: "answer-questionnaire__question-label questionnaire-question",
28
- data: { "answer-idx": cleaned_answer_idx }
27
+ class: "answer-questionnaire__question-label questionnaire-question"
29
28
  }
30
29
  label_options[:for] = nil if %w(matrix_single matrix_multiple single_option multiple_option).include?(answer.question.question_type)
31
30
  %>
@@ -17,7 +17,6 @@
17
17
 
18
18
  <%= invisible_captcha %>
19
19
  <% answer_idx = 0 %>
20
- <% cleaned_answer_idx = 1 %>
21
20
  <% @form.responses_by_step.each_with_index do |step_answers, step_index| %>
22
21
  <div id="step-<%= step_index %>" class="answer-questionnaire__step" <%= "hidden" if !step_index.zero? %>>
23
22
 
@@ -39,16 +38,11 @@
39
38
  answer_form:,
40
39
  answer:,
41
40
  answer_idx:,
42
- cleaned_answer_idx:,
43
41
  disabled: !current_participatory_space.can_participate?(current_user)
44
42
  ) %>
45
43
  <% end %>
46
44
  </div>
47
45
 
48
- <% if !(answer.question.separator? || answer.question.title_and_description?) %>
49
- <% cleaned_answer_idx += 1 %>
50
- <% end %>
51
-
52
46
  <% answer_idx += 1 %>
53
47
 
54
48
  <% end %>
@@ -24,7 +24,7 @@ eu:
24
24
  missing: ez dira osatu
25
25
  too_many: Gehienez, %{count} aukeratu ahal duzu.
26
26
  questionnaire:
27
- request_invalid: Arazo bat izan da eskaera kudeatzean. Mesedez, saiatu berriro.
27
+ request_invalid: Arazo bat izan da eskaera kudeatzean. Mesedez, berriro saiatu.
28
28
  decidim:
29
29
  download_your_data:
30
30
  help:
@@ -51,7 +51,7 @@ eu:
51
51
  ends_at: Erantzunak noiz arte onartuta
52
52
  ends_at_help: Utzi zuriz data zehatzik ez badago
53
53
  starts_at: Erantzunak noiztik onartuak
54
- starts_at_help: Utzi zuriz data zehatzik ez badago
54
+ starts_at_help: Zuriz utzi data zehatzik ez badago
55
55
  tos: Zerbitzu-baldintzak
56
56
  questionnaires:
57
57
  actions:
@@ -27,6 +27,13 @@ fr-CA:
27
27
  request_invalid: Une erreur s'est produite lors du traitement de la requête. Veuillez essayer à nouveau.
28
28
  decidim:
29
29
  download_your_data:
30
+ help:
31
+ answers:
32
+ answer: La réponse à la question
33
+ id: L'identifiant unique de la réponse
34
+ question: La question à laquelle on a répondu
35
+ questionnaire: Le questionnaire auquel on a répondu
36
+ user: L'utilisateur qui a répondu au questionnaire
30
37
  show:
31
38
  answers: Export des réponses
32
39
  survey_user_answers: Réponses à l'enquête
@@ -27,6 +27,13 @@ fr:
27
27
  request_invalid: Une erreur s'est produite lors du traitement de la requête. Veuillez essayer à nouveau.
28
28
  decidim:
29
29
  download_your_data:
30
+ help:
31
+ answers:
32
+ answer: La réponse à la question
33
+ id: L'identifiant unique de la réponse
34
+ question: La question à laquelle on a répondu
35
+ questionnaire: Le questionnaire auquel on a répondu
36
+ user: L'utilisateur qui a répondu au questionnaire
30
37
  show:
31
38
  answers: Export des réponses
32
39
  survey_user_answers: Réponses à l'enquête
@@ -26,18 +26,37 @@ sv:
26
26
  questionnaire:
27
27
  request_invalid: Det gick inte att hantera begäran. Försök igen.
28
28
  decidim:
29
+ download_your_data:
30
+ help:
31
+ answers:
32
+ answer: Svaret på frågan
33
+ id: Unikt id för svaret
34
+ question: Frågan som besvarades
35
+ questionnaire: Enkäten som besvarades
36
+ user: Användaren som svarade på frågeformuläret
37
+ show:
38
+ answers: Exportera svar
39
+ survey_user_answers: Enkätsvar
29
40
  forms:
30
41
  admin:
31
42
  models:
32
43
  components:
44
+ allow_answers: Tillåt svar
45
+ allow_editing_answers: Tillåt registrerade användare att redigera egna enkätsvar
46
+ allow_unregistered: Tillåt ej registrerade användare att besvara enkäten
47
+ allow_unregistered_help: Om aktiv kommer ingen inloggning att krävas för att besvara enkäten. Detta kan leda till dålig eller opålitlig data och det kommer att vara mer sårbart för automatiserade attacker. Använd med försiktighet! Tänk på att en deltagare kan svara på samma enkät flera gånger, genom att använda olika webbläsare eller "privat surfning" i sin webbläsare.
33
48
  announcement: Meddelande
49
+ clean_after_publish: Ta bort svar vid publicering av enkäten
34
50
  description: Beskrivning
51
+ ends_at: Öppet för svar till
35
52
  ends_at_help: Lämna tomt för att inte sätta något datum
53
+ starts_at: Öppet för svar från
36
54
  starts_at_help: Lämna tomt för att inte sätta något datum
37
55
  tos: Användarvillkor
38
56
  questionnaires:
39
57
  actions:
40
58
  back: Tillbaka till svar
59
+ publish_answers: Publicera svar
41
60
  show: Visa svar
42
61
  answer_option:
43
62
  answer_option: Svarsalternativ
@@ -130,6 +149,9 @@ sv:
130
149
  invalid: Det gick inte att spara formuläret.
131
150
  success: Formuläret har sparats.
132
151
  admin_log:
152
+ question:
153
+ publish_answers: "%{user_name} publicerade svaren på %{resource_name} i utrymmet %{space_name}"
154
+ unpublish_answers: "%{user_name} avpublicerade svaren på %{resource_name} i utrymmet %{space_name}"
133
155
  questionnaire:
134
156
  update: "%{user_name} uppdaterade enkäten %{resource_name}"
135
157
  errors:
@@ -172,6 +194,9 @@ sv:
172
194
  questionnaire_answered:
173
195
  body: Du har redan besvarat det här formuläret.
174
196
  title: Redan svarat
197
+ questionnaire_answered_edit:
198
+ body: Du har redan svarat på formuläret. %{link}
199
+ edit: Redigera svar
175
200
  questionnaire_closed:
176
201
  body: Formuläret är stängt och kan inte besvaras.
177
202
  title: Formuläret är stängt
@@ -186,9 +211,11 @@ sv:
186
211
  tos_agreement: Genom att fortsätta godkänner du villkoren för anmälan
187
212
  step_navigation:
188
213
  show:
214
+ are_you_sure_edit_guest: Om du vill kunna redigera dina svar efteråt måste du logga in eller skapa ett konto.
189
215
  are_you_sure_no_edit: Efter att du har skickat in anmälan kan du inte ändra i den. Vill du fortsätta?
190
216
  back: Tillbaka
191
217
  continue: Fortsätt
218
+ disallowed: Du har inte behörighet att redigera dina svar.
192
219
  submit: Skicka
193
220
  user_answers_serializer:
194
221
  body: Svar
@@ -12,7 +12,14 @@ module Decidim
12
12
 
13
13
  class QuestionnaireAnswerPresenter < Decidim::Forms::Admin::QuestionnaireAnswerPresenter
14
14
  def choice(choice_hash)
15
- render_body_for choice_hash
15
+ if choice_hash[:matrix_row_body].present?
16
+ row_text = choice_hash[:matrix_row_body]
17
+ option_text = choice_hash[:answer_option_body]
18
+ custom_text = choice_hash[:choice_body].present? ? " (#{choice_hash[:choice_body]})" : ""
19
+ "#{row_text}: #{option_text}#{custom_text}"
20
+ else
21
+ render_body_for choice_hash
22
+ end
16
23
  end
17
24
 
18
25
  delegate :attachments, to: :answer
@@ -25,7 +32,8 @@ module Decidim
25
32
  choices = answer.choices.map do |choice|
26
33
  {
27
34
  answer_option_body: choice.try(:answer_option).try(:translated_body),
28
- choice_body: body_or_custom_body(choice)
35
+ choice_body: body_or_custom_body(choice),
36
+ matrix_row_body: choice.try(:matrix_row).try(:body) ? translated_attribute(choice.matrix_row.body) : nil
29
37
  }
30
38
  end
31
39
 
@@ -192,9 +192,7 @@ shared_examples_for "has questionnaire" do
192
192
 
193
193
  expect(form_fields[0]).to have_i18n_content(question.body)
194
194
  expect(form_fields[1]).to have_i18n_content(other_question.body)
195
- 2.times do |index|
196
- expect(form_fields[index]).to have_css("[data-answer-idx='#{index + 1}']")
197
- end
195
+ expect(page.text.index(translated_attribute(other_question.body))).to be > page.text.index(translated_attribute(question.body))
198
196
  end
199
197
  end
200
198
 
@@ -412,11 +412,57 @@ shared_examples_for "add questions" do
412
412
 
413
413
  select "Single option", from: "Type"
414
414
  expect(page).to have_css("input[type=checkbox][id$=_free_text]")
415
+
416
+ select "Sorting", from: "Type"
417
+ expect(page).to have_no_css("input[type=checkbox][id$=_free_text]", visible: :visible)
415
418
  end
416
419
 
417
420
  it_behaves_like "updating the max choices selector according to the configured options"
418
421
  end
419
422
 
423
+ context "when adding a sorting question" do
424
+ before do
425
+ click_on "Add question"
426
+
427
+ expand_all_questions
428
+
429
+ within ".questionnaire-question" do
430
+ fill_in find_nested_form_field_locator("body_en"), with: "This is a sorting question"
431
+ select "Single option", from: "Type"
432
+ end
433
+ end
434
+
435
+ it "does not display the free text option when switching to sorting type" do
436
+ within ".questionnaire-question" do
437
+ expect(page).to have_css("input[type=checkbox][id$=_free_text]")
438
+
439
+ select "Sorting", from: "Type"
440
+
441
+ expect(page).to have_no_css("input[type=checkbox][id$=_free_text]", visible: :visible)
442
+ end
443
+ end
444
+
445
+ it "shows the free text option when switching back from sorting to single option" do
446
+ within ".questionnaire-question" do
447
+ select "Sorting", from: "Type"
448
+ expect(page).to have_no_css("input[type=checkbox][id$=_free_text]", visible: :visible)
449
+
450
+ select "Single option", from: "Type"
451
+ expect(page).to have_css("input[type=checkbox][id$=_free_text]")
452
+ end
453
+ end
454
+
455
+ it "hides free text option when switching from multiple option to sorting" do
456
+ within ".questionnaire-question" do
457
+ select "Multiple option", from: "Type"
458
+ expect(page).to have_css("input[type=checkbox][id$=_free_text]")
459
+
460
+ select "Sorting", from: "Type"
461
+ expect(page).to have_no_css("input[type=checkbox][id$=_free_text]", visible: :visible)
462
+ end
463
+ end
464
+ end
465
+
420
466
  context "when adding a matrix question" do
421
467
  let(:multiple_option_string) { "Matrix (Multiple option)" }
422
468
  let(:single_option_string) { "Matrix (Single option)" }
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ shared_examples_for "manage questionnaire draggable behavior" do
6
+ let!(:question) { create(:questionnaire_question, body:, questionnaire:) }
7
+
8
+ context "when questionnaire has no responses (editable)" do
9
+ before do
10
+ visit current_path
11
+ end
12
+
13
+ it "shows draggable data attributes for questions list" do
14
+ expect(page).to have_css("[data-draggable-table]")
15
+ expect(page).to have_css("[data-draggable-handle]")
16
+ end
17
+
18
+ describe "when hovering over card divider" do
19
+ it "shows resize cursor for editable questions" do
20
+ within first(".questionnaire-question") do
21
+ expect(page).to have_css(".card-divider.hover\\:cursor-grab")
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ context "when questionnaire has responses (not editable)" do
28
+ let!(:answer) { create(:answer, question:, questionnaire:) }
29
+
30
+ before do
31
+ visit current_path
32
+ end
33
+
34
+ it "does not show draggable data attributes for questions list" do
35
+ expect(page).to have_no_css("[data-draggable-table]")
36
+ expect(page).to have_no_css("[data-draggable-handle]")
37
+ end
38
+
39
+ describe "when hovering over card divider" do
40
+ it "does not show resize cursor for non-editable questions" do
41
+ within first(".questionnaire-question") do
42
+ expect(page).to have_no_css(".card-divider.hover\\:cursor-grab")
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -6,6 +6,7 @@ require "decidim/forms/test/shared_examples/manage_questionnaires/add_questions"
6
6
  require "decidim/forms/test/shared_examples/manage_questionnaires/update_questions"
7
7
  require "decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions"
8
8
  require "decidim/forms/test/shared_examples/manage_questionnaires/update_display_conditions"
9
+ require "decidim/forms/test/shared_examples/manage_questionnaires/draggable_behavior"
9
10
 
10
11
  shared_examples_for "manage questionnaires" do
11
12
  let(:body) do
@@ -33,6 +34,7 @@ shared_examples_for "manage questionnaires" do
33
34
  it_behaves_like "update questions"
34
35
  it_behaves_like "add display conditions"
35
36
  it_behaves_like "update display conditions"
37
+ it_behaves_like "manage questionnaire draggable behavior"
36
38
  end
37
39
 
38
40
  context "when the questionnaire is already answered" do
@@ -4,7 +4,7 @@ module Decidim
4
4
  # This holds the decidim-forms version.
5
5
  module Forms
6
6
  def self.version
7
- "0.30.5"
7
+ "0.30.7"
8
8
  end
9
9
  end
10
10
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: decidim-forms
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.30.5
4
+ version: 0.30.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josep Jaume Rey Peroy
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2026-01-28 00:00:00.000000000 Z
14
+ date: 2026-03-26 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: decidim-core
@@ -19,42 +19,42 @@ dependencies:
19
19
  requirements:
20
20
  - - '='
21
21
  - !ruby/object:Gem::Version
22
- version: 0.30.5
22
+ version: 0.30.7
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - '='
28
28
  - !ruby/object:Gem::Version
29
- version: 0.30.5
29
+ version: 0.30.7
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: decidim-admin
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  requirements:
34
34
  - - '='
35
35
  - !ruby/object:Gem::Version
36
- version: 0.30.5
36
+ version: 0.30.7
37
37
  type: :development
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
41
  - - '='
42
42
  - !ruby/object:Gem::Version
43
- version: 0.30.5
43
+ version: 0.30.7
44
44
  - !ruby/object:Gem::Dependency
45
45
  name: decidim-dev
46
46
  requirement: !ruby/object:Gem::Requirement
47
47
  requirements:
48
48
  - - '='
49
49
  - !ruby/object:Gem::Version
50
- version: 0.30.5
50
+ version: 0.30.7
51
51
  type: :development
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
54
54
  requirements:
55
55
  - - '='
56
56
  - !ruby/object:Gem::Version
57
- version: 0.30.5
57
+ version: 0.30.7
58
58
  description: A forms gem for decidim.
59
59
  email:
60
60
  - josepjaume@gmail.com
@@ -281,6 +281,7 @@ files:
281
281
  - lib/decidim/forms/test/shared_examples/manage_questionnaires.rb
282
282
  - lib/decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions.rb
283
283
  - lib/decidim/forms/test/shared_examples/manage_questionnaires/add_questions.rb
284
+ - lib/decidim/forms/test/shared_examples/manage_questionnaires/draggable_behavior.rb
284
285
  - lib/decidim/forms/test/shared_examples/manage_questionnaires/update_display_conditions.rb
285
286
  - lib/decidim/forms/test/shared_examples/manage_questionnaires/update_questions.rb
286
287
  - lib/decidim/forms/user_answers_serializer.rb