decidim-forms 0.20.1 → 0.23.1

Sign up to get free protection for your applications and to get access to all the features.
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);