decidim-forms 0.22.0 → 0.23.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/admin/decidim_forms_manifest.css +3 -0
  3. data/app/assets/config/decidim_forms_manifest.css +1 -0
  4. data/app/assets/javascripts/decidim/forms/admin/auto_select_options_from_url.component.js.es6 +40 -0
  5. data/app/assets/javascripts/decidim/forms/admin/forms.js.es6 +181 -25
  6. data/app/assets/javascripts/decidim/forms/autosortable_checkboxes.component.js.es6 +54 -34
  7. data/app/assets/javascripts/decidim/forms/display_conditions.component.js.es6 +203 -0
  8. data/app/assets/javascripts/decidim/forms/forms.js.es6 +8 -1
  9. data/app/assets/stylesheets/decidim/forms/questionnaire-answers-pdf.scss +69 -0
  10. data/app/commands/decidim/forms/admin/update_questionnaire.rb +25 -1
  11. data/app/commands/decidim/forms/answer_questionnaire.rb +1 -1
  12. data/app/controllers/decidim/forms/admin/concerns/has_questionnaire.rb +47 -1
  13. data/app/controllers/decidim/forms/admin/concerns/has_questionnaire_answers.rb +97 -0
  14. data/app/controllers/decidim/forms/concerns/has_questionnaire.rb +3 -2
  15. data/app/forms/decidim/forms/admin/display_condition_form.rb +100 -0
  16. data/app/forms/decidim/forms/admin/question_form.rb +1 -0
  17. data/app/forms/decidim/forms/answer_form.rb +15 -0
  18. data/app/forms/decidim/forms/questionnaire_form.rb +5 -0
  19. data/app/helpers/decidim/forms/admin/application_helper.rb +21 -0
  20. data/app/helpers/decidim/forms/admin/concerns/has_questionnaire_answers_pagination_helper.rb +49 -0
  21. data/app/helpers/decidim/forms/admin/concerns/has_questionnaire_answers_url_helper.rb +40 -0
  22. data/app/helpers/decidim/forms/admin/questionnaire_answers_helper.rb +30 -0
  23. data/app/jobs/decidim/forms/export_questionnaire_answers_job.rb +19 -0
  24. data/app/models/decidim/forms/answer.rb +0 -3
  25. data/app/models/decidim/forms/answer_option.rb +14 -0
  26. data/app/models/decidim/forms/display_condition.rb +65 -0
  27. data/app/models/decidim/forms/question.rb +34 -0
  28. data/app/models/decidim/forms/question_matrix_row.rb +3 -0
  29. data/app/models/decidim/forms/questionnaire.rb +22 -1
  30. data/app/presenters/decidim/forms/admin/questionnaire_answer_presenter.rb +43 -0
  31. data/app/presenters/decidim/forms/admin/questionnaire_participant_presenter.rb +60 -0
  32. data/app/presenters/decidim/forms/answer_option_presenter.rb +20 -0
  33. data/app/presenters/decidim/forms/question_presenter.rb +16 -0
  34. data/app/queries/decidim/forms/questionnaire_participant.rb +35 -0
  35. data/app/queries/decidim/forms/questionnaire_participants.rb +43 -0
  36. data/app/views/decidim/forms/admin/questionnaires/_display_condition.html.erb +88 -0
  37. data/app/views/decidim/forms/admin/questionnaires/_display_condition_template.html.erb +7 -0
  38. data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +30 -4
  39. data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +19 -3
  40. data/app/views/decidim/forms/admin/questionnaires/answers/export/_answer.html.erb +31 -0
  41. data/app/views/decidim/forms/admin/questionnaires/answers/export/pdf.html.erb +13 -0
  42. data/app/views/decidim/forms/admin/questionnaires/answers/index.html.erb +53 -0
  43. data/app/views/decidim/forms/admin/questionnaires/answers/show.html.erb +48 -0
  44. data/app/views/decidim/forms/admin/questionnaires/edit.html.erb +9 -5
  45. data/app/views/decidim/forms/questionnaires/_answer.html.erb +1 -1
  46. data/app/views/decidim/forms/questionnaires/show.html.erb +22 -2
  47. data/app/views/layouts/decidim/forms/admin/questionnaires/questionnaire_answers.html.erb +12 -0
  48. data/config/initializers/wicked_pdf.rb +25 -0
  49. data/config/locales/am-ET.yml +1 -0
  50. data/config/locales/ar.yml +0 -1
  51. data/config/locales/bg-BG.yml +0 -2
  52. data/config/locales/bg.yml +14 -0
  53. data/config/locales/ca.yml +56 -4
  54. data/config/locales/cs.yml +56 -4
  55. data/config/locales/da.yml +1 -0
  56. data/config/locales/de.yml +53 -1
  57. data/config/locales/el.yml +0 -2
  58. data/config/locales/en.yml +54 -2
  59. data/config/locales/eo.yml +1 -0
  60. data/config/locales/es-MX.yml +53 -1
  61. data/config/locales/es-PY.yml +53 -1
  62. data/config/locales/es.yml +54 -2
  63. data/config/locales/et.yml +1 -0
  64. data/config/locales/eu.yml +0 -1
  65. data/config/locales/fi-plain.yml +53 -1
  66. data/config/locales/fi.yml +53 -1
  67. data/config/locales/fr-CA.yml +54 -2
  68. data/config/locales/fr.yml +55 -3
  69. data/config/locales/gl.yml +1 -1
  70. data/config/locales/hr.yml +1 -0
  71. data/config/locales/hu.yml +0 -2
  72. data/config/locales/id-ID.yml +0 -1
  73. data/config/locales/is.yml +1 -0
  74. data/config/locales/it.yml +53 -1
  75. data/config/locales/ja-JP.yml +51 -1
  76. data/config/locales/ja.yml +170 -0
  77. data/config/locales/ko-KR.yml +1 -0
  78. data/config/locales/ko.yml +1 -0
  79. data/config/locales/lt.yml +1 -0
  80. data/config/locales/{lv-LV.yml → lv.yml} +0 -1
  81. data/config/locales/mt.yml +1 -0
  82. data/config/locales/nl.yml +59 -7
  83. data/config/locales/no.yml +48 -2
  84. data/config/locales/om-ET.yml +1 -0
  85. data/config/locales/pl.yml +52 -3
  86. data/config/locales/pt-BR.yml +0 -1
  87. data/config/locales/pt.yml +51 -2
  88. data/config/locales/ro-RO.yml +51 -2
  89. data/config/locales/ru.yml +0 -1
  90. data/config/locales/si-LK.yml +1 -0
  91. data/config/locales/sk.yml +0 -2
  92. data/config/locales/sl.yml +7 -0
  93. data/config/locales/so-SO.yml +1 -0
  94. data/config/locales/sv.yml +51 -2
  95. data/config/locales/sw-KE.yml +1 -0
  96. data/config/locales/ti-ER.yml +1 -0
  97. data/config/locales/tr-TR.yml +88 -2
  98. data/config/locales/vi-VN.yml +1 -0
  99. data/config/locales/vi.yml +1 -0
  100. data/config/locales/zh-CN.yml +172 -0
  101. data/config/locales/zh-TW.yml +1 -0
  102. data/db/migrate/20200130194123_create_decidim_forms_display_conditions.rb +20 -0
  103. data/db/migrate/20201110152921_add_salt_to_decidim_forms_questionnaires.rb +16 -0
  104. data/lib/decidim/exporters/form_pdf.rb +33 -0
  105. data/lib/decidim/exporters/form_pdf_controller_helper.rb +11 -0
  106. data/lib/decidim/forms.rb +5 -0
  107. data/lib/decidim/forms/admin_engine.rb +1 -1
  108. data/lib/decidim/forms/test.rb +6 -0
  109. data/lib/decidim/forms/test/factories.rb +31 -0
  110. data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +619 -38
  111. data/lib/decidim/forms/test/shared_examples/manage_questionnaire_answers.rb +108 -0
  112. data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +21 -894
  113. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions.rb +179 -0
  114. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_questions.rb +463 -0
  115. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_display_conditions.rb +93 -0
  116. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_questions.rb +461 -0
  117. data/lib/decidim/forms/user_answers_serializer.rb +1 -1
  118. data/lib/decidim/forms/version.rb +1 -1
  119. metadata +97 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 73b7dd5e0d7e94151c79b989666d5a3d1e3790db9c97cee7a35c587a0a00977e
4
- data.tar.gz: 4e7f6a2d27f58079d5eed9d08404373a66636f6960a220dc1572809a482dfbb3
3
+ metadata.gz: 8c64f5c2dbb8ae561a2e8db75db766f978c2a445e7c38563a2fa7416c2566149
4
+ data.tar.gz: e0b9f7121d658512cf17d39878753365c0dde22355db67f266c84ba237de2361
5
5
  SHA512:
6
- metadata.gz: b2eed83cff858299ee6fef944b1951150ad4634a193fec095ca20a393bfec8de0f1a2fe1e09447728d40dbb2898ce4b884d4ab82cdecaf93c6025efd1d677bd5
7
- data.tar.gz: e1e84f6aa8d5a1cb2ea2fe95593bd0ba0977d536c4abb3a3cc66726cf66a425dd7c1622f462cc9324c5fbf0d375e0dcc43c2844eb0b0fafc5457f97d34a6de70
6
+ metadata.gz: c622686680eba06c10eb5106938ea376ffcdfdc9196060975317f648c2119430ec8b5ec4b18016a6ca3268056ee4949958484ac1be9a4a4acea5055a858163a3
7
+ data.tar.gz: 4ea7be1f3ba73666074f04757de50d1fd95fca1aa01f4b91f04e5d0c6a01999fb2803243cc288bfdd3ac857a4ba619b68d7d0108aaa3c0f586a878e95ac80ac9
@@ -0,0 +1,3 @@
1
+ /*
2
+ *= link decidim/forms/questionnaire-answers-pdf.scss
3
+ */
@@ -1,3 +1,4 @@
1
1
  /*
2
2
  *= link decidim/forms/forms.scss
3
+ *= link decidim/forms/questionnaire-answers-pdf.scss
3
4
  */
@@ -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);
@@ -1,9 +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
3
6
  // = require ./live_text_update.component
4
7
 
5
8
  ((exports) => {
6
- const { AutoLabelByPositionComponent, AutoButtonsByPositionComponent, AutoButtonsByMinItemsComponent, AutoSelectOptionsByTotalItemsComponent, createLiveTextUpdateComponent, createFieldDependentInputs, createDynamicFields, createSortList } = exports.DecidimAdmin;
9
+ const { AutoLabelByPositionComponent, AutoButtonsByPositionComponent, AutoButtonsByMinItemsComponent, AutoSelectOptionsByTotalItemsComponent, AutoSelectOptionsFromUrl, createLiveTextUpdateComponent, createFieldDependentInputs, createDynamicFields, createSortList } = exports.DecidimAdmin;
7
10
  const { createQuillEditor } = exports.Decidim;
8
11
 
9
12
  const wrapperSelector = ".questionnaire-questions";
@@ -18,22 +21,54 @@
18
21
  const addMatrixRowButtonSelector = ".add-matrix-row";
19
22
  const maxChoicesWrapperSelector = ".questionnaire-question-max-choices";
20
23
 
21
- const MULTIPLE_CHOICE_VALUES = ["single_option", "multiple_option", "sorting", "matrix_single", "matrix_multiple"];
22
- const MATRIX_VALUES = ["matrix_single", "matrix_multiple"];
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
+ });
23
57
 
24
58
  const autoLabelByPosition = new AutoLabelByPositionComponent({
25
59
  listSelector: ".questionnaire-question:not(.hidden)",
26
60
  labelSelector: ".card-title span:first",
27
61
  onPositionComputed: (el, idx) => {
28
62
  $(el).find("input[name$=\\[position\\]]").val(idx);
63
+
64
+ autoButtonsByPosition.run();
65
+
66
+ removeDisplayConditionsForFirstQuestion();
29
67
  }
30
68
  });
31
69
 
32
- const autoButtonsByPosition = new AutoButtonsByPositionComponent({
33
- listSelector: ".questionnaire-question:not(.hidden)",
34
- hideOnFirstSelector: ".move-up-question",
35
- hideOnLastSelector: ".move-down-question"
36
- });
70
+ const MULTIPLE_CHOICE_VALUES = ["single_option", "multiple_option", "sorting", "matrix_single", "matrix_multiple"];
71
+ const MATRIX_VALUES = ["matrix_single", "matrix_multiple"];
37
72
 
38
73
  const createAutoMaxChoicesByNumberOfAnswerOptions = (fieldId) => {
39
74
  return new AutoSelectOptionsByTotalItemsComponent({
@@ -52,6 +87,14 @@
52
87
  })
53
88
  };
54
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
+
55
98
  const createSortableList = () => {
56
99
  createSortList(".questionnaire-questions-list:not(.published)", {
57
100
  handle: ".question-divider",
@@ -80,6 +123,15 @@
80
123
  });
81
124
  }
82
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
+
83
135
  const createDynamicFieldsForAnswerOptions = (fieldId) => {
84
136
  const autoButtons = createAutoButtonsByMinItemsForAnswerOptions(fieldId);
85
137
  const autoSelectOptions = createAutoMaxChoicesByNumberOfAnswerOptions(fieldId);
@@ -123,22 +175,122 @@
123
175
 
124
176
  const dynamicFieldsForMatrixRows = {};
125
177
 
126
- const isMultipleChoiceOption = ($selectField) => {
127
- const value = $selectField.val();
128
-
178
+ const isMultipleChoiceOption = (value) => {
129
179
  return MULTIPLE_CHOICE_VALUES.indexOf(value) >= 0;
130
180
  }
131
181
 
132
- const isMatrix = ($selectField) => {
133
- const value = $selectField.val();
134
-
182
+ const isMatrix = (value) => {
135
183
  return MATRIX_VALUES.indexOf(value) >= 0;
136
184
  }
137
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
+ });
266
+
267
+ onDisplayConditionTypeChange($field);
268
+ onDisplayConditionQuestionChange($field);
269
+ }
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
+
138
289
  const setupInitialQuestionAttributes = ($target) => {
139
290
  const fieldId = $target.attr("id");
140
291
  const $fieldQuestionTypeSelect = $target.find(questionTypeSelector);
141
292
 
293
+ createCollapsibleQuestion($target);
142
294
  createDynamicQuestionTitle(fieldId);
143
295
 
144
296
  createFieldDependentInputs({
@@ -147,7 +299,7 @@
147
299
  dependentFieldsSelector: answerOptionsWrapperSelector,
148
300
  dependentInputSelector: `${answerOptionFieldSelector} input`,
149
301
  enablingCondition: ($field) => {
150
- return isMultipleChoiceOption($field);
302
+ return isMultipleChoiceOption($field.val());
151
303
  }
152
304
  });
153
305
 
@@ -167,18 +319,19 @@
167
319
  dependentFieldsSelector: matrixRowsWrapperSelector,
168
320
  dependentInputSelector: `${matrixRowFieldSelector} input`,
169
321
  enablingCondition: ($field) => {
170
- return isMatrix($field);
322
+ return isMatrix($field.val());
171
323
  }
172
324
  });
173
325
 
174
326
  dynamicFieldsForAnswerOptions[fieldId] = createDynamicFieldsForAnswerOptions(fieldId);
175
327
  dynamicFieldsForMatrixRows[fieldId] = createDynamicFieldsForMatrixRows(fieldId);
328
+ dynamicFieldsForDisplayConditions[fieldId] = createDynamicFieldsForDisplayConditions(fieldId);
176
329
 
177
330
  const dynamicFieldsAnswerOptions = dynamicFieldsForAnswerOptions[fieldId];
178
331
  const dynamicFieldsMatrixRows = dynamicFieldsForMatrixRows[fieldId];
179
332
 
180
333
  const onQuestionTypeChange = () => {
181
- if (isMultipleChoiceOption($fieldQuestionTypeSelect)) {
334
+ if (isMultipleChoiceOption($fieldQuestionTypeSelect.val())) {
182
335
  const nOptions = $fieldQuestionTypeSelect.parents(fieldSelector).find(answerOptionFieldSelector).length;
183
336
 
184
337
  if (nOptions === 0) {
@@ -187,7 +340,7 @@
187
340
  }
188
341
  }
189
342
 
190
- if (isMatrix($fieldQuestionTypeSelect)) {
343
+ if (isMatrix($fieldQuestionTypeSelect.val())) {
191
344
  const nRows = $fieldQuestionTypeSelect.parents(fieldSelector).find(matrixRowFieldSelector).length;
192
345
 
193
346
  if (nRows === 0) {
@@ -224,13 +377,6 @@
224
377
  moveUpFieldButtonSelector: ".move-up-question",
225
378
  moveDownFieldButtonSelector: ".move-down-question",
226
379
  onAddField: ($field) => {
227
- const $collapsible = $field.find(".collapsible");
228
- if ($collapsible.length > 0) {
229
- const collapsibleId = $collapsible.attr("id").replace("-question-card", "");
230
- const toggleAttr = `${collapsibleId}-question-card button--collapse-question-${collapsibleId} button--expand-question-${collapsibleId}`;
231
- $field.find(".question--collapse").data("toggle", toggleAttr);
232
- }
233
-
234
380
  setupInitialQuestionAttributes($field);
235
381
  createSortableList();
236
382
 
@@ -248,9 +394,14 @@
248
394
  $field.find(answerOptionRemoveFieldButtonSelector).each((idx, el) => {
249
395
  dynamicFieldsForAnswerOptions[$field.attr("id")]._removeField(el);
250
396
  });
397
+
251
398
  $field.find(matrixRowRemoveFieldButtonSelector).each((idx, el) => {
252
399
  dynamicFieldsForMatrixRows[$field.attr("id")]._removeField(el);
253
400
  });
401
+
402
+ $field.find(displayConditionRemoveFieldButtonSelector).each((idx, el) => {
403
+ dynamicFieldsForDisplayConditions[$field.attr("id")]._removeField(el);
404
+ });
254
405
  },
255
406
  onMoveUpField: () => {
256
407
  autoLabelByPosition.run();
@@ -271,6 +422,11 @@
271
422
  setupInitialQuestionAttributes($target);
272
423
  });
273
424
 
425
+ $(displayConditionFieldSelector).each((idx, el) => {
426
+ const $field = $(el);
427
+ initializeDisplayConditionField($field)
428
+ });
429
+
274
430
  autoLabelByPosition.run();
275
431
  autoButtonsByPosition.run();
276
432
  })(window);
@@ -1,59 +1,79 @@
1
+ /* eslint-disable no-ternary */
2
+
1
3
  ((exports) => {
2
4
  class AutosortableCheckboxesComponent {
3
5
  constructor(options = {}) {
4
6
  this.wrapperField = options.wrapperField;
5
7
  this._bindEvent();
6
- this._run();
8
+ this._order();
9
+ this._normalize();
7
10
  }
8
11
 
9
- _run() {
10
- $(this.wrapperField).find("input[type=checkbox]").each((idx, el) => {
11
- const $parentLabel = $(el).parents("label");
12
-
13
- if ($(el).is(":checked")) {
14
- const $lastSorted = this.wrapperField.find("label.sorted").last();
15
-
16
- if ($lastSorted.length > 0) {
17
- $lastSorted.removeClass("last-sorted");
18
- $parentLabel.insertAfter($lastSorted);
19
- } else {
20
- $parentLabel.insertBefore(this.wrapperField.find("label:first-child"));
21
- }
12
+ // Order by position
13
+ _order() {
14
+ const max = $(this.wrapperField).find(".collection-input").length;
15
+ $(this.wrapperField).find(".collection-input").each((idx, el) => {
16
+ const $positionField = $(el).find("input[name$=\\[position\\]]");
17
+ const position = $positionField.val()
18
+ ? parseInt($positionField.val(), 10)
19
+ : max;
22
20
 
23
- $parentLabel.addClass("sorted");
24
- $parentLabel.addClass("last-sorted");
25
- } else {
26
- const $lastUnsorted = this.wrapperField.find("label:not(.sorted)").last();
21
+ let $next = $(el).next();
22
+ while ($next.length > 0) {
23
+ const $nextPositionField = $next.find("input[name$=\\[position\\]]");
24
+ const nextPosition = $nextPositionField.val()
25
+ ? parseInt($nextPositionField.val(), 10)
26
+ : max;
27
27
 
28
- if ($lastUnsorted.length > 0) {
29
- $parentLabel.insertBefore($lastUnsorted);
30
- } else {
31
- $parentLabel.insertAfter(this.wrapperField.find("label:last-child"));
28
+ if (position > nextPosition) {
29
+ $next.insertBefore($(el));
32
30
  }
33
-
34
- $parentLabel.removeClass("sorted");
31
+ $next = $next.next();
35
32
  }
36
33
  });
34
+ }
37
35
 
38
- $(this.wrapperField).find("label").each((idx, el) => {
39
- const $positionSelector = $(el).find(".position");
36
+ _findLastPosition() {
37
+ let lastPosition = 0;
38
+ $(this.wrapperField).find(".collection-input").each((idx, el) => {
40
39
  const $positionField = $(el).find("input[name$=\\[position\\]]");
40
+ const position = parseInt($positionField.val(), 10);
41
+ if (position > lastPosition) {
42
+ lastPosition = position;
43
+ }
44
+ });
45
+ return lastPosition;
46
+ }
41
47
 
42
- if ($(el).hasClass("sorted")) {
48
+ _normalize() {
49
+ $(this.wrapperField).find(".collection-input .position").each((idx, el) => {
50
+ const $positionField = $(el).parent().find("input[name$=\\[position\\]]");
51
+ if ($positionField.val()) {
43
52
  $positionField.val(idx);
44
53
  $positionField.prop("disabled", false);
45
- $positionSelector.html(`${idx + 1}. `);
46
- } else {
47
- $positionField.val("");
48
- $positionField.prop("disabled", true);
49
- $positionSelector.html("");
54
+ $(el).html(`${idx + 1}. `);
50
55
  }
51
56
  });
52
57
  }
53
58
 
54
59
  _bindEvent() {
55
- $(this.wrapperField).find("input[type=checkbox]").on("change", () => {
56
- this._run();
60
+ $(this.wrapperField).find("input[type=checkbox]").on("change", (el) => {
61
+ const $parentLabel = $(el.target).parents("label");
62
+ const $positionSelector = $parentLabel.find(".position");
63
+ const $positionField = $parentLabel.find("input[name$=\\[position\\]]");
64
+ const lastPosition = this._findLastPosition();
65
+
66
+ if (el.target.checked) {
67
+ $positionField.val(lastPosition + 1);
68
+ $positionField.prop("disabled", false);
69
+ $positionSelector.html(lastPosition + 1);
70
+ } else {
71
+ $positionField.val("");
72
+ $positionField.prop("disabled", true);
73
+ $positionSelector.html("");
74
+ }
75
+ this._order();
76
+ this._normalize();
57
77
  });
58
78
  }
59
79
  }