decidim-forms 0.20.1 → 0.23.1

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 (158) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/admin/decidim_forms_manifest.css +3 -0
  3. data/app/assets/config/admin/decidim_forms_manifest.js +1 -0
  4. data/app/assets/config/decidim_forms_manifest.css +1 -0
  5. data/app/assets/images/decidim/surveys/icon.svg +1 -19
  6. data/app/assets/javascripts/decidim/forms/admin/auto_select_options_from_url.component.js.es6 +40 -0
  7. data/app/assets/javascripts/decidim/forms/admin/collapsible_questions.js.es6 +13 -0
  8. data/app/assets/javascripts/decidim/forms/admin/forms.js.es6 +260 -16
  9. data/app/assets/javascripts/decidim/forms/admin/live_text_update.component.js.es6 +52 -0
  10. data/app/assets/javascripts/decidim/forms/autosortable_checkboxes.component.js.es6 +54 -34
  11. data/app/assets/javascripts/decidim/forms/display_conditions.component.js.es6 +203 -0
  12. data/app/assets/javascripts/decidim/forms/forms.js.es6 +49 -1
  13. data/app/assets/javascripts/decidim/forms/max_choices_alert.component.js.es6 +44 -0
  14. data/app/assets/stylesheets/decidim/forms/forms.scss +39 -0
  15. data/app/assets/stylesheets/decidim/forms/questionnaire-answers-pdf.scss +69 -0
  16. data/app/cells/decidim/forms/matrix_readonly/show.erb +5 -0
  17. data/app/cells/decidim/forms/matrix_readonly_cell.rb +12 -0
  18. data/app/cells/decidim/forms/question_readonly/show.erb +5 -1
  19. data/app/cells/decidim/forms/question_readonly_cell.rb +5 -0
  20. data/app/cells/decidim/forms/step_navigation/show.erb +35 -0
  21. data/app/cells/decidim/forms/step_navigation_cell.rb +46 -0
  22. data/app/commands/decidim/forms/admin/update_questionnaire.rb +33 -1
  23. data/app/commands/decidim/forms/answer_questionnaire.rb +2 -1
  24. data/app/controllers/decidim/forms/admin/concerns/has_questionnaire.rb +52 -2
  25. data/app/controllers/decidim/forms/admin/concerns/has_questionnaire_answers.rb +97 -0
  26. data/app/controllers/decidim/forms/concerns/has_questionnaire.rb +11 -2
  27. data/app/forms/decidim/forms/admin/display_condition_form.rb +100 -0
  28. data/app/forms/decidim/forms/admin/question_form.rb +21 -1
  29. data/app/forms/decidim/forms/admin/question_matrix_row_form.rb +26 -0
  30. data/app/forms/decidim/forms/answer_choice_form.rb +1 -0
  31. data/app/forms/decidim/forms/answer_form.rb +31 -2
  32. data/app/forms/decidim/forms/questionnaire_form.rb +30 -3
  33. data/app/helpers/decidim/forms/admin/application_helper.rb +37 -0
  34. data/app/helpers/decidim/forms/admin/concerns/has_questionnaire_answers_pagination_helper.rb +49 -0
  35. data/app/helpers/decidim/forms/admin/concerns/has_questionnaire_answers_url_helper.rb +40 -0
  36. data/app/helpers/decidim/forms/admin/questionnaire_answers_helper.rb +27 -0
  37. data/app/jobs/decidim/forms/export_questionnaire_answers_job.rb +19 -0
  38. data/app/models/decidim/forms/answer.rb +0 -3
  39. data/app/models/decidim/forms/answer_choice.rb +7 -0
  40. data/app/models/decidim/forms/answer_option.rb +14 -0
  41. data/app/models/decidim/forms/display_condition.rb +65 -0
  42. data/app/models/decidim/forms/question.rb +52 -2
  43. data/app/models/decidim/forms/question_matrix_row.rb +15 -0
  44. data/app/models/decidim/forms/questionnaire.rb +11 -1
  45. data/app/presenters/decidim/forms/admin/questionnaire_answer_presenter.rb +43 -0
  46. data/app/presenters/decidim/forms/admin/questionnaire_participant_presenter.rb +60 -0
  47. data/app/presenters/decidim/forms/answer_option_presenter.rb +20 -0
  48. data/app/presenters/decidim/forms/question_presenter.rb +16 -0
  49. data/app/queries/decidim/forms/questionnaire_participant.rb +35 -0
  50. data/app/queries/decidim/forms/questionnaire_participants.rb +43 -0
  51. data/app/types/decidim/forms/answer_option_type.rb +14 -0
  52. data/app/types/decidim/forms/question_type.rb +23 -0
  53. data/app/types/decidim/forms/questionnaire_type.rb +22 -0
  54. data/app/views/decidim/forms/admin/questionnaires/_answer_option_template.html.erb +1 -1
  55. data/app/views/decidim/forms/admin/questionnaires/_display_condition.html.erb +88 -0
  56. data/app/views/decidim/forms/admin/questionnaires/_display_condition_template.html.erb +7 -0
  57. data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +67 -8
  58. data/app/views/decidim/forms/admin/questionnaires/_matrix_row.html.erb +34 -0
  59. data/app/views/decidim/forms/admin/questionnaires/_matrix_row_template.html.erb +7 -0
  60. data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +45 -6
  61. data/app/views/decidim/forms/admin/questionnaires/_separator.html.erb +41 -0
  62. data/app/views/decidim/forms/admin/questionnaires/answers/export/_answer.html.erb +31 -0
  63. data/app/views/decidim/forms/admin/questionnaires/answers/export/pdf.html.erb +13 -0
  64. data/app/views/decidim/forms/admin/questionnaires/answers/index.html.erb +53 -0
  65. data/app/views/decidim/forms/admin/questionnaires/answers/show.html.erb +48 -0
  66. data/app/views/decidim/forms/admin/questionnaires/edit.html.erb +9 -5
  67. data/app/views/decidim/forms/questionnaires/_answer.html.erb +28 -99
  68. data/app/views/decidim/forms/questionnaires/answers/_long_answer.html.erb +1 -0
  69. data/app/views/decidim/forms/questionnaires/answers/_matrix_multiple.html.erb +43 -0
  70. data/app/views/decidim/forms/questionnaires/answers/_matrix_single.html.erb +43 -0
  71. data/app/views/decidim/forms/questionnaires/answers/_multiple_option.html.erb +23 -0
  72. data/app/views/decidim/forms/questionnaires/answers/_separator.html.erb +1 -0
  73. data/app/views/decidim/forms/questionnaires/answers/_short_answer.html.erb +1 -0
  74. data/app/views/decidim/forms/questionnaires/answers/_single_option.html.erb +30 -0
  75. data/app/views/decidim/forms/questionnaires/answers/_sorting.html.erb +23 -0
  76. data/app/views/decidim/forms/questionnaires/show.html.erb +78 -26
  77. data/app/views/layouts/decidim/forms/admin/questionnaires/questionnaire_answers.html.erb +12 -0
  78. data/config/initializers/wicked_pdf.rb +25 -0
  79. data/config/locales/am-ET.yml +1 -0
  80. data/config/locales/ar.yml +7 -4
  81. data/config/locales/bg-BG.yml +14 -0
  82. data/config/locales/bg.yml +14 -0
  83. data/config/locales/ca.yml +89 -5
  84. data/config/locales/cs.yml +89 -5
  85. data/config/locales/da-DK.yml +1 -0
  86. data/config/locales/da.yml +1 -0
  87. data/config/locales/de.yml +92 -4
  88. data/config/locales/el.yml +118 -0
  89. data/config/locales/en.yml +89 -5
  90. data/config/locales/eo.yml +1 -0
  91. data/config/locales/es-MX.yml +88 -4
  92. data/config/locales/es-PY.yml +88 -4
  93. data/config/locales/es.yml +88 -4
  94. data/config/locales/et-EE.yml +1 -0
  95. data/config/locales/et.yml +1 -0
  96. data/config/locales/eu.yml +7 -4
  97. data/config/locales/fi-plain.yml +88 -4
  98. data/config/locales/fi.yml +88 -4
  99. data/config/locales/fr-CA.yml +172 -0
  100. data/config/locales/fr.yml +89 -5
  101. data/config/locales/ga-IE.yml +1 -0
  102. data/config/locales/gl.yml +7 -4
  103. data/config/locales/hr-HR.yml +1 -0
  104. data/config/locales/hr.yml +1 -0
  105. data/config/locales/hu.yml +11 -5
  106. data/config/locales/id-ID.yml +7 -4
  107. data/config/locales/is.yml +1 -0
  108. data/config/locales/it.yml +89 -5
  109. data/config/locales/ja-JP.yml +170 -0
  110. data/config/locales/ja.yml +170 -0
  111. data/config/locales/ko-KR.yml +1 -0
  112. data/config/locales/ko.yml +1 -0
  113. data/config/locales/lt-LT.yml +1 -0
  114. data/config/locales/lt.yml +1 -0
  115. data/config/locales/lv.yml +118 -0
  116. data/config/locales/mt-MT.yml +1 -0
  117. data/config/locales/mt.yml +1 -0
  118. data/config/locales/nl.yml +92 -8
  119. data/config/locales/no.yml +54 -5
  120. data/config/locales/om-ET.yml +1 -0
  121. data/config/locales/pl.yml +113 -26
  122. data/config/locales/pt-BR.yml +8 -5
  123. data/config/locales/pt.yml +111 -24
  124. data/config/locales/ro-RO.yml +167 -0
  125. data/config/locales/ru.yml +4 -2
  126. data/config/locales/sk-SK.yml +88 -0
  127. data/config/locales/sk.yml +90 -0
  128. data/config/locales/sl.yml +12 -0
  129. data/config/locales/so-SO.yml +1 -0
  130. data/config/locales/sr-CS.yml +1 -0
  131. data/config/locales/sv.yml +88 -7
  132. data/config/locales/ti-ER.yml +1 -0
  133. data/config/locales/tr-TR.yml +7 -4
  134. data/config/locales/vi-VN.yml +1 -0
  135. data/config/locales/vi.yml +1 -0
  136. data/config/locales/zh-CN.yml +172 -0
  137. data/config/locales/zh-TW.yml +1 -0
  138. data/db/migrate/20200130194123_create_decidim_forms_display_conditions.rb +20 -0
  139. data/db/migrate/20200225123810_create_decidim_forms_question_matrix_rows.rb +11 -0
  140. data/db/migrate/20200304152939_add_matrix_row_id_to_decidim_forms_answer_choices.rb +11 -0
  141. data/lib/decidim/api/questionnaire_entity_interface.rb +18 -0
  142. data/lib/decidim/exporters/form_pdf.rb +33 -0
  143. data/lib/decidim/exporters/form_pdf_controller_helper.rb +11 -0
  144. data/lib/decidim/forms.rb +6 -0
  145. data/lib/decidim/forms/admin_engine.rb +1 -1
  146. data/lib/decidim/forms/api.rb +7 -0
  147. data/lib/decidim/forms/test.rb +6 -0
  148. data/lib/decidim/forms/test/factories.rb +55 -0
  149. data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +918 -60
  150. data/lib/decidim/forms/test/shared_examples/manage_questionnaire_answers.rb +108 -0
  151. data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +33 -575
  152. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions.rb +179 -0
  153. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_questions.rb +463 -0
  154. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_display_conditions.rb +93 -0
  155. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_questions.rb +461 -0
  156. data/lib/decidim/forms/user_answers_serializer.rb +21 -4
  157. data/lib/decidim/forms/version.rb +1 -1
  158. metadata +133 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d2ede21376cb021e162f01466661931e8a122cdef2daeb098dfb9a3d7c334415
4
- data.tar.gz: c096f04a49d0c7d5f11f8f900ce3e649cb7caf8ed54ba18ff3fb8aaffd39d7fb
3
+ metadata.gz: 00b6fa084292af8d4b343f801ccc5725a7983e3390b41dcd00f2b84b34afc914
4
+ data.tar.gz: 9f037814dca4fd315e6425074dc2d8c42f8c144d1bb8c5042897dd8ab5410bdf
5
5
  SHA512:
6
- metadata.gz: 72e3d234e00b6f106b8dc6f336e3fc3652bfcfd322ef44c535e9349323f77f6195b6b95599cededa39eb43301791d946a695aeeb69962aa5a26f840059f04d1b
7
- data.tar.gz: d2f248216d11676dec71a5d795ff0a5292234ada433cb798082641949142ab8ab53a5839f72123c6839f54858260c4a2735949404c110036d78867602d3caf4d
6
+ metadata.gz: fc48b056500a941f30b72dd044e9614008b8a0e84111e10af937ce00bab58d13a2e8938a4fa7a8dea9660dbb6c00ffc5b897330f42a9f73a2203edd5c86dd6d9
7
+ data.tar.gz: a0dbe8818ba0efbe2d7d8b1f9503c5b07cde7023437d81ab5ee1c1695a16631d26e054cc8dd072460c97c652101ef34ef5489e6bfb596cc6376d58f3e53fd184
@@ -0,0 +1,3 @@
1
+ /*
2
+ *= link decidim/forms/questionnaire-answers-pdf.scss
3
+ */
@@ -1 +1,2 @@
1
1
  //= link decidim/forms/admin/forms.js
2
+ //= link decidim/forms/admin/collapsible_questions.js
@@ -1,3 +1,4 @@
1
1
  /*
2
2
  *= link decidim/forms/forms.scss
3
+ *= link decidim/forms/questionnaire-answers-pdf.scss
3
4
  */
@@ -1,19 +1 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
- <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
4
- viewBox="0 0 36 36" style="enable-background:new 0 0 36 36;" xml:space="preserve">
5
- <path d="M27,28H9c-0.6,0-1-0.4-1-1V11c0-0.6,0.4-1,1-1h3.1c0.6,0,1,0.4,1,1v1.9h9.7V11c0-0.6,0.4-1,1-1H27c0.6,0,1,0.4,1,1v16
6
- C28,27.6,27.6,28,27,28z M10,26h16V12h-1.2v1.9c0,0.6-0.4,1-1,1H12.1c-0.6,0-1-0.4-1-1V12H10V26z"/>
7
- <g>
8
- <g>
9
- <path d="M21,11h-6c-0.6,0-1-0.4-1-1s0.4-1,1-1h6c0.6,0,1,0.4,1,1S21.6,11,21,11z"/>
10
- </g>
11
- <g>
12
- <path d="M18.7,11h-1.5c-0.6,0-1-0.4-1-1V8c0-0.6,0.4-1,1-1h1.5c0.6,0,1,0.4,1,1v2C19.7,10.5,19.3,11,18.7,11z"/>
13
- </g>
14
- </g>
15
- <g>
16
- <path d="M18,36.1c-9.9,0-18-8.1-18-18s8.1-18,18-18s18,8.1,18,18S27.9,36.1,18,36.1z M18,2.1c-8.8,0-16,7.2-16,16s7.2,16,16,16
17
- s16-7.2,16-16S26.8,2.1,18,2.1z"/>
18
- </g>
19
- </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" x="0" y="0" enable-background="new 0 0 36 36" version="1.1" viewBox="0 0 36 36" xml:space="preserve"><path d="M27,28H9c-0.6,0-1-0.4-1-1V11c0-0.6,0.4-1,1-1h3.1c0.6,0,1,0.4,1,1v1.9h9.7V11c0-0.6,0.4-1,1-1H27c0.6,0,1,0.4,1,1v16 C28,27.6,27.6,28,27,28z M10,26h16V12h-1.2v1.9c0,0.6-0.4,1-1,1H12.1c-0.6,0-1-0.4-1-1V12H10V26z"/><g><g><path d="M21,11h-6c-0.6,0-1-0.4-1-1s0.4-1,1-1h6c0.6,0,1,0.4,1,1S21.6,11,21,11z"/></g><g><path d="M18.7,11h-1.5c-0.6,0-1-0.4-1-1V8c0-0.6,0.4-1,1-1h1.5c0.6,0,1,0.4,1,1v2C19.7,10.5,19.3,11,18.7,11z"/></g></g><g><path d="M18,36.1c-9.9,0-18-8.1-18-18s8.1-18,18-18s18,8.1,18,18S27.9,36.1,18,36.1z M18,2.1c-8.8,0-16,7.2-16,16s7.2,16,16,16 s16-7.2,16-16S26.8,2.1,18,2.1z"/></g></svg>
@@ -0,0 +1,40 @@
1
+ ((exports) => {
2
+ class AutoSelectOptionsFromUrl {
3
+ constructor(options = {}) {
4
+ this.$source = options.source;
5
+ this.$select = options.select;
6
+ this.sourceToParams = options.sourceToParams;
7
+ this.run();
8
+ }
9
+
10
+ run() {
11
+ this.$source.on("change", this._onSourceChange.bind(this));
12
+ this._onSourceChange();
13
+ }
14
+
15
+ _onSourceChange() {
16
+ const select = this.$select;
17
+ const params = this.sourceToParams(this.$source);
18
+ const url = this.$source.data("url");
19
+
20
+ $.getJSON(url, params, function (data) {
21
+ select.find("option:not([value=''])").remove();
22
+ const selectedValue = select.data("selected");
23
+
24
+ data.forEach((option) => {
25
+ let optionElement = $(`<option value="${option.id}">${option.body}</option>`).appendTo(select);
26
+ if (option.id === selectedValue) {
27
+ optionElement.attr("selected", true);
28
+ }
29
+ });
30
+
31
+ if (selectedValue) {
32
+ select.val(selectedValue);
33
+ }
34
+ });
35
+ }
36
+ }
37
+
38
+ exports.DecidimAdmin = exports.DecidimAdmin || {};
39
+ exports.DecidimAdmin.AutoSelectOptionsFromUrl = AutoSelectOptionsFromUrl;
40
+ })(window);
@@ -0,0 +1,13 @@
1
+ (() => {
2
+ $("button.collapse-all").on("click", () => {
3
+ $(".collapsible").addClass("hide");
4
+ $(".question--collapse .icon-expand").removeClass("hide");
5
+ $(".question--collapse .icon-collapse").addClass("hide");
6
+ });
7
+
8
+ $("button.expand-all").on("click", () => {
9
+ $(".collapsible").removeClass("hide");
10
+ $(".question--collapse .icon-expand").addClass("hide");
11
+ $(".question--collapse .icon-collapse").removeClass("hide");
12
+ });
13
+ })(window);
@@ -1,8 +1,12 @@
1
+ /* eslint-disable max-lines */
2
+
1
3
  // = require ./auto_buttons_by_min_items.component
2
4
  // = require ./auto_select_options_by_total_items.component
5
+ // = require ./auto_select_options_from_url.component
6
+ // = require ./live_text_update.component
3
7
 
4
8
  ((exports) => {
5
- const { AutoLabelByPositionComponent, AutoButtonsByPositionComponent, AutoButtonsByMinItemsComponent, AutoSelectOptionsByTotalItemsComponent, createFieldDependentInputs, createDynamicFields, createSortList } = exports.DecidimAdmin;
9
+ const { AutoLabelByPositionComponent, AutoButtonsByPositionComponent, AutoButtonsByMinItemsComponent, AutoSelectOptionsByTotalItemsComponent, AutoSelectOptionsFromUrl, createLiveTextUpdateComponent, createFieldDependentInputs, createDynamicFields, createSortList } = exports.DecidimAdmin;
6
10
  const { createQuillEditor } = exports.Decidim;
7
11
 
8
12
  const wrapperSelector = ".questionnaire-questions";
@@ -11,21 +15,60 @@
11
15
  const answerOptionFieldSelector = ".questionnaire-question-answer-option";
12
16
  const answerOptionsWrapperSelector = ".questionnaire-question-answer-options";
13
17
  const answerOptionRemoveFieldButtonSelector = ".remove-answer-option";
18
+ const matrixRowFieldSelector = ".questionnaire-question-matrix-row";
19
+ const matrixRowsWrapperSelector = ".questionnaire-question-matrix-rows";
20
+ const matrixRowRemoveFieldButtonSelector = ".remove-matrix-row";
21
+ const addMatrixRowButtonSelector = ".add-matrix-row";
14
22
  const maxChoicesWrapperSelector = ".questionnaire-question-max-choices";
15
23
 
24
+ const displayConditionFieldSelector = ".questionnaire-question-display-condition";
25
+ const displayConditionsWrapperSelector = ".questionnaire-question-display-conditions";
26
+ const displayConditionRemoveFieldButtonSelector = ".remove-display-condition";
27
+
28
+ const displayConditionQuestionSelector = "select[name$=\\[decidim_condition_question_id\\]]";
29
+ const displayConditionAnswerOptionSelector = "select[name$=\\[decidim_answer_option_id\\]]";
30
+ const displayConditionTypeSelector = "select[name$=\\[condition_type\\]]";
31
+ const deletedInputSelector = "input[name$=\\[deleted\\]]";
32
+
33
+ const displayConditionValueWrapperSelector = ".questionnaire-question-display-condition-value";
34
+ const displayconditionAnswerOptionWrapperSelector = ".questionnaire-question-display-condition-answer-option";
35
+
36
+ const addDisplayConditionButtonSelector = ".add-display-condition";
37
+
38
+ const removeDisplayConditionsForFirstQuestion = () => {
39
+ $(fieldSelector).each((idx, el) => {
40
+ const $question = $(el);
41
+ if (idx) {
42
+ $question.find(displayConditionsWrapperSelector).find(deletedInputSelector).val("false");
43
+ $question.find(displayConditionsWrapperSelector).show();
44
+ }
45
+ else {
46
+ $question.find(displayConditionsWrapperSelector).find(deletedInputSelector).val("true");
47
+ $question.find(displayConditionsWrapperSelector).hide();
48
+ }
49
+ });
50
+ };
51
+
52
+ const autoButtonsByPosition = new AutoButtonsByPositionComponent({
53
+ listSelector: ".questionnaire-question:not(.hidden)",
54
+ hideOnFirstSelector: ".move-up-question",
55
+ hideOnLastSelector: ".move-down-question"
56
+ });
57
+
16
58
  const autoLabelByPosition = new AutoLabelByPositionComponent({
17
59
  listSelector: ".questionnaire-question:not(.hidden)",
18
60
  labelSelector: ".card-title span:first",
19
61
  onPositionComputed: (el, idx) => {
20
62
  $(el).find("input[name$=\\[position\\]]").val(idx);
63
+
64
+ autoButtonsByPosition.run();
65
+
66
+ removeDisplayConditionsForFirstQuestion();
21
67
  }
22
68
  });
23
69
 
24
- const autoButtonsByPosition = new AutoButtonsByPositionComponent({
25
- listSelector: ".questionnaire-question:not(.hidden)",
26
- hideOnFirstSelector: ".move-up-question",
27
- hideOnLastSelector: ".move-down-question"
28
- });
70
+ const MULTIPLE_CHOICE_VALUES = ["single_option", "multiple_option", "sorting", "matrix_single", "matrix_multiple"];
71
+ const MATRIX_VALUES = ["matrix_single", "matrix_multiple"];
29
72
 
30
73
  const createAutoMaxChoicesByNumberOfAnswerOptions = (fieldId) => {
31
74
  return new AutoSelectOptionsByTotalItemsComponent({
@@ -44,15 +87,51 @@
44
87
  })
45
88
  };
46
89
 
90
+ const createAutoSelectOptionsFromUrl = ($field) => {
91
+ return new AutoSelectOptionsFromUrl({
92
+ source: $field.find(displayConditionQuestionSelector),
93
+ select: $field.find(displayConditionAnswerOptionSelector),
94
+ sourceToParams: ($element) => { return { id: $element.val() } }
95
+ })
96
+ };
97
+
47
98
  const createSortableList = () => {
48
99
  createSortList(".questionnaire-questions-list:not(.published)", {
49
100
  handle: ".question-divider",
50
101
  placeholder: '<div style="border-style: dashed; border-color: #000"></div>',
51
102
  forcePlaceholderSize: true,
52
- onSortUpdate: () => { autoLabelByPosition.run() }
103
+ onSortUpdate: () => {
104
+ autoLabelByPosition.run();
105
+ autoButtonsByPosition.run();
106
+ }
53
107
  });
54
108
  };
55
109
 
110
+ const createDynamicQuestionTitle = (fieldId) => {
111
+ const targetSelector = `#${fieldId} .question-title-statement`;
112
+ const locale = $(targetSelector).data("locale");
113
+ const maxLength = $(targetSelector).data("max-length");
114
+ const omission = $(targetSelector).data("omission");
115
+ const placeholder = $(targetSelector).data("placeholder");
116
+
117
+ return createLiveTextUpdateComponent({
118
+ inputSelector: `#${fieldId} input[name$=\\[body_${locale}\\]]`,
119
+ targetSelector: targetSelector,
120
+ maxLength: maxLength,
121
+ omission: omission,
122
+ placeholder: placeholder
123
+ });
124
+ }
125
+
126
+ const createCollapsibleQuestion = ($target) => {
127
+ const $collapsible = $target.find(".collapsible");
128
+ if ($collapsible.length > 0) {
129
+ const collapsibleId = $collapsible.attr("id").replace("-question-card", "");
130
+ const toggleAttr = `${collapsibleId}-question-card button--collapse-question-${collapsibleId} button--expand-question-${collapsibleId}`;
131
+ $target.find(".question--collapse").data("toggle", toggleAttr);
132
+ }
133
+ };
134
+
56
135
  const createDynamicFieldsForAnswerOptions = (fieldId) => {
57
136
  const autoButtons = createAutoButtonsByMinItemsForAnswerOptions(fieldId);
58
137
  const autoSelectOptions = createAutoMaxChoicesByNumberOfAnswerOptions(fieldId);
@@ -63,6 +142,7 @@
63
142
  containerSelector: ".questionnaire-question-answer-options-list",
64
143
  fieldSelector: answerOptionFieldSelector,
65
144
  addFieldButtonSelector: ".add-answer-option",
145
+ fieldTemplateSelector: ".decidim-answer-option-template",
66
146
  removeFieldButtonSelector: answerOptionRemoveFieldButtonSelector,
67
147
  onAddField: () => {
68
148
  autoButtons.run();
@@ -77,23 +157,149 @@
77
157
 
78
158
  const dynamicFieldsForAnswerOptions = {};
79
159
 
80
- const isMultipleChoiceOption = ($selectField) => {
81
- const value = $selectField.val();
160
+ const createDynamicFieldsForMatrixRows = (fieldId) => {
161
+ return createDynamicFields({
162
+ placeholderId: "questionnaire-question-matrix-row-id",
163
+ wrapperSelector: `#${fieldId} ${matrixRowsWrapperSelector}`,
164
+ containerSelector: ".questionnaire-question-matrix-rows-list",
165
+ fieldSelector: matrixRowFieldSelector,
166
+ addFieldButtonSelector: addMatrixRowButtonSelector,
167
+ fieldTemplateSelector: ".decidim-matrix-row-template",
168
+ removeFieldButtonSelector: matrixRowRemoveFieldButtonSelector,
169
+ onAddField: () => {
170
+ },
171
+ onRemoveField: () => {
172
+ }
173
+ });
174
+ };
175
+
176
+ const dynamicFieldsForMatrixRows = {};
177
+
178
+ const isMultipleChoiceOption = (value) => {
179
+ return MULTIPLE_CHOICE_VALUES.indexOf(value) >= 0;
180
+ }
181
+
182
+ const isMatrix = (value) => {
183
+ return MATRIX_VALUES.indexOf(value) >= 0;
184
+ }
185
+
186
+ const getSelectedQuestionType = (select) => {
187
+ const selectedOption = select.options[select.selectedIndex];
188
+ return $(selectedOption).data("type");
189
+ };
190
+
191
+ const onDisplayConditionQuestionChange = ($field) => {
192
+ const $questionSelector = $field.find(displayConditionQuestionSelector);
193
+ const selectedQuestionType = getSelectedQuestionType($questionSelector[0]);
194
+
195
+ const isMultiple = isMultipleChoiceOption(selectedQuestionType);
196
+
197
+ let conditionTypes = ["answered", "not_answered"];
198
+
199
+ if (isMultiple) {
200
+ conditionTypes.push("equal");
201
+ conditionTypes.push("not_equal");
202
+ }
203
+
204
+ conditionTypes.push("match");
205
+
206
+ const $conditionTypeSelect = $field.find(displayConditionTypeSelector);
207
+
208
+ $conditionTypeSelect.find("option").each((idx, option) => {
209
+ const $option = $(option);
210
+ const value = $option.val();
211
+
212
+ if (!value) {
213
+ return;
214
+ }
215
+
216
+ $option.show();
217
+
218
+ if (conditionTypes.indexOf(value) < 0) {
219
+ $option.hide();
220
+ }
221
+ });
222
+
223
+ if (conditionTypes.indexOf($conditionTypeSelect.val()) < 0) {
224
+ $conditionTypeSelect.val(conditionTypes[0]);
225
+ }
226
+
227
+ $conditionTypeSelect.trigger("change");
228
+ };
229
+
230
+ const onDisplayConditionTypeChange = ($field) => {
231
+ const value = $field.find(displayConditionTypeSelector).val();
232
+ const $valueWrapper = $field.find(displayConditionValueWrapperSelector);
233
+ const $answerOptionWrapper = $field.find(displayconditionAnswerOptionWrapperSelector);
234
+
235
+ const $questionSelector = $field.find(displayConditionQuestionSelector);
236
+ const selectedQuestionType = getSelectedQuestionType($questionSelector[0]);
237
+
238
+ const isMultiple = isMultipleChoiceOption(selectedQuestionType);
239
+
240
+ if (value === "match") {
241
+ $valueWrapper.show();
242
+ }
243
+ else {
244
+ $valueWrapper.hide();
245
+ }
246
+
247
+ if (isMultiple && (value === "not_equal" || value === "equal")) {
248
+ $answerOptionWrapper.show();
249
+ }
250
+ else {
251
+ $answerOptionWrapper.hide();
252
+ }
253
+ };
254
+
255
+ const initializeDisplayConditionField = ($field) => {
256
+ const autoSelectByUrl = createAutoSelectOptionsFromUrl($field);
257
+ autoSelectByUrl.run();
258
+
259
+ $field.find(displayConditionQuestionSelector).on("change", () => {
260
+ onDisplayConditionQuestionChange($field);
261
+ });
262
+
263
+ $field.find(displayConditionTypeSelector).on("change", () => {
264
+ onDisplayConditionTypeChange($field);
265
+ });
82
266
 
83
- return value === "single_option" || value === "multiple_option" || value === "sorting"
267
+ onDisplayConditionTypeChange($field);
268
+ onDisplayConditionQuestionChange($field);
84
269
  }
85
270
 
271
+ const createDynamicFieldsForDisplayConditions = (fieldId) => {
272
+ return createDynamicFields({
273
+ placeholderId: "questionnaire-question-display-condition-id",
274
+ wrapperSelector: `#${fieldId} ${displayConditionsWrapperSelector}`,
275
+ containerSelector: ".questionnaire-question-display-conditions-list",
276
+ fieldSelector: displayConditionFieldSelector,
277
+ addFieldButtonSelector: addDisplayConditionButtonSelector,
278
+ removeFieldButtonSelector: displayConditionRemoveFieldButtonSelector,
279
+ onAddField: ($field) => {
280
+ initializeDisplayConditionField($field);
281
+ },
282
+ onRemoveField: () => {
283
+ }
284
+ });
285
+ };
286
+
287
+ const dynamicFieldsForDisplayConditions = {};
288
+
86
289
  const setupInitialQuestionAttributes = ($target) => {
87
290
  const fieldId = $target.attr("id");
88
291
  const $fieldQuestionTypeSelect = $target.find(questionTypeSelector);
89
292
 
293
+ createCollapsibleQuestion($target);
294
+ createDynamicQuestionTitle(fieldId);
295
+
90
296
  createFieldDependentInputs({
91
297
  controllerField: $fieldQuestionTypeSelect,
92
298
  wrapperSelector: fieldSelector,
93
299
  dependentFieldsSelector: answerOptionsWrapperSelector,
94
300
  dependentInputSelector: `${answerOptionFieldSelector} input`,
95
301
  enablingCondition: ($field) => {
96
- return isMultipleChoiceOption($field);
302
+ return isMultipleChoiceOption($field.val());
97
303
  }
98
304
  });
99
305
 
@@ -103,21 +309,43 @@
103
309
  dependentFieldsSelector: maxChoicesWrapperSelector,
104
310
  dependentInputSelector: "select",
105
311
  enablingCondition: ($field) => {
106
- return $field.val() === "multiple_option"
312
+ return $field.val() === "multiple_option" || $field.val() === "matrix_multiple";
313
+ }
314
+ });
315
+
316
+ createFieldDependentInputs({
317
+ controllerField: $fieldQuestionTypeSelect,
318
+ wrapperSelector: fieldSelector,
319
+ dependentFieldsSelector: matrixRowsWrapperSelector,
320
+ dependentInputSelector: `${matrixRowFieldSelector} input`,
321
+ enablingCondition: ($field) => {
322
+ return isMatrix($field.val());
107
323
  }
108
324
  });
109
325
 
110
326
  dynamicFieldsForAnswerOptions[fieldId] = createDynamicFieldsForAnswerOptions(fieldId);
327
+ dynamicFieldsForMatrixRows[fieldId] = createDynamicFieldsForMatrixRows(fieldId);
328
+ dynamicFieldsForDisplayConditions[fieldId] = createDynamicFieldsForDisplayConditions(fieldId);
111
329
 
112
- const dynamicFields = dynamicFieldsForAnswerOptions[fieldId];
330
+ const dynamicFieldsAnswerOptions = dynamicFieldsForAnswerOptions[fieldId];
331
+ const dynamicFieldsMatrixRows = dynamicFieldsForMatrixRows[fieldId];
113
332
 
114
333
  const onQuestionTypeChange = () => {
115
- if (isMultipleChoiceOption($fieldQuestionTypeSelect)) {
334
+ if (isMultipleChoiceOption($fieldQuestionTypeSelect.val())) {
116
335
  const nOptions = $fieldQuestionTypeSelect.parents(fieldSelector).find(answerOptionFieldSelector).length;
117
336
 
118
337
  if (nOptions === 0) {
119
- dynamicFields._addField();
120
- dynamicFields._addField();
338
+ dynamicFieldsAnswerOptions._addField();
339
+ dynamicFieldsAnswerOptions._addField();
340
+ }
341
+ }
342
+
343
+ if (isMatrix($fieldQuestionTypeSelect.val())) {
344
+ const nRows = $fieldQuestionTypeSelect.parents(fieldSelector).find(matrixRowFieldSelector).length;
345
+
346
+ if (nRows === 0) {
347
+ dynamicFieldsMatrixRows._addField();
348
+ dynamicFieldsMatrixRows._addField();
121
349
  }
122
350
  }
123
351
  };
@@ -142,6 +370,9 @@
142
370
  containerSelector: ".questionnaire-questions-list",
143
371
  fieldSelector: fieldSelector,
144
372
  addFieldButtonSelector: ".add-question",
373
+ addSeparatorButtonSelector: ".add-separator",
374
+ fieldTemplateSelector: ".decidim-question-template",
375
+ separatorTemplateSelector: ".decidim-separator-template",
145
376
  removeFieldButtonSelector: ".remove-question",
146
377
  moveUpFieldButtonSelector: ".move-up-question",
147
378
  moveDownFieldButtonSelector: ".move-down-question",
@@ -163,6 +394,14 @@
163
394
  $field.find(answerOptionRemoveFieldButtonSelector).each((idx, el) => {
164
395
  dynamicFieldsForAnswerOptions[$field.attr("id")]._removeField(el);
165
396
  });
397
+
398
+ $field.find(matrixRowRemoveFieldButtonSelector).each((idx, el) => {
399
+ dynamicFieldsForMatrixRows[$field.attr("id")]._removeField(el);
400
+ });
401
+
402
+ $field.find(displayConditionRemoveFieldButtonSelector).each((idx, el) => {
403
+ dynamicFieldsForDisplayConditions[$field.attr("id")]._removeField(el);
404
+ });
166
405
  },
167
406
  onMoveUpField: () => {
168
407
  autoLabelByPosition.run();
@@ -183,6 +422,11 @@
183
422
  setupInitialQuestionAttributes($target);
184
423
  });
185
424
 
425
+ $(displayConditionFieldSelector).each((idx, el) => {
426
+ const $field = $(el);
427
+ initializeDisplayConditionField($field)
428
+ });
429
+
186
430
  autoLabelByPosition.run();
187
431
  autoButtonsByPosition.run();
188
432
  })(window);