decidim-forms 0.24.0 → 0.25.0.rc1

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/forms/step_navigation/show.erb +1 -1
  3. data/app/commands/decidim/forms/admin/update_questionnaire.rb +3 -2
  4. data/app/forms/decidim/forms/admin/question_form.rb +14 -0
  5. data/app/forms/decidim/forms/admin/question_matrix_row_form.rb +2 -2
  6. data/app/forms/decidim/forms/questionnaire_form.rb +1 -0
  7. data/app/helpers/decidim/forms/application_helper.rb +1 -0
  8. data/app/jobs/decidim/forms/export_questionnaire_answers_job.rb +1 -1
  9. data/app/models/decidim/forms/question.rb +4 -0
  10. data/app/models/decidim/forms/question_matrix_row.rb +3 -0
  11. data/app/packs/entrypoints/decidim_forms.js +4 -0
  12. data/app/packs/entrypoints/decidim_forms_admin.js +4 -0
  13. data/app/packs/entrypoints/decidim_questionnaire_answers_pdf.js +1 -0
  14. data/app/packs/entrypoints/decidim_questionnaire_answers_pdf.scss +1 -0
  15. data/app/{assets/images/decidim/surveys/icon.svg → packs/images/decidim/surveys/decidim_surveys.svg} +0 -0
  16. data/app/packs/src/decidim/forms/admin/auto_buttons_by_min_items.component.js +20 -0
  17. data/app/packs/src/decidim/forms/admin/auto_select_options_by_total_items.component.js +18 -0
  18. data/app/packs/src/decidim/forms/admin/auto_select_options_from_url.component.js +35 -0
  19. data/app/{assets/javascripts/decidim/forms/admin/collapsible_questions.js.es6 → packs/src/decidim/forms/admin/collapsible_questions.js} +0 -0
  20. data/app/{assets/javascripts/decidim/forms/admin/forms.js.es6 → packs/src/decidim/forms/admin/forms.js} +16 -12
  21. data/app/packs/src/decidim/forms/admin/live_text_update.component.js +49 -0
  22. data/app/packs/src/decidim/forms/autosortable_checkboxes.component.js +83 -0
  23. data/app/packs/src/decidim/forms/display_conditions.component.js +200 -0
  24. data/app/{assets/javascripts/decidim/forms/forms.js.es6 → packs/src/decidim/forms/forms.js} +7 -7
  25. data/app/packs/src/decidim/forms/max_choices_alert.component.js +43 -0
  26. data/app/packs/src/decidim/forms/option_attached_inputs.component.js +31 -0
  27. data/app/{assets → packs}/stylesheets/decidim/forms/forms.scss +5 -0
  28. data/app/{assets → packs}/stylesheets/decidim/forms/questionnaire-answers-pdf.scss +0 -0
  29. data/app/views/decidim/forms/admin/questionnaires/_display_condition.html.erb +2 -2
  30. data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +5 -3
  31. data/app/views/decidim/forms/admin/questionnaires/_matrix_row.html.erb +1 -0
  32. data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +1 -1
  33. data/app/views/decidim/forms/questionnaires/answers/_matrix_multiple.html.erb +1 -1
  34. data/app/views/decidim/forms/questionnaires/answers/_matrix_single.html.erb +1 -1
  35. data/app/views/decidim/forms/questionnaires/show.html.erb +7 -1
  36. data/app/views/layouts/decidim/forms/admin/questionnaires/questionnaire_answers.html.erb +1 -1
  37. data/config/assets.rb +10 -0
  38. data/config/locales/fr-LU.yml +178 -0
  39. data/config/locales/hu.yml +2 -0
  40. data/config/locales/it.yml +7 -0
  41. data/config/locales/ja.yml +8 -0
  42. data/config/locales/lb-LU.yml +1 -0
  43. data/config/locales/pl.yml +2 -2
  44. data/config/locales/pt-BR.yml +93 -0
  45. data/config/locales/sv.yml +9 -0
  46. data/db/migrate/20170515144119_create_decidim_forms_answers.rb +1 -2
  47. data/db/migrate/20210616153042_set_position_to_question_matrix_rows.rb +11 -0
  48. data/lib/decidim/forms/admin_engine.rb +0 -4
  49. data/lib/decidim/forms/engine.rb +2 -4
  50. data/lib/decidim/forms/test/factories.rb +39 -2
  51. data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +2 -0
  52. data/lib/decidim/forms/user_answers_serializer.rb +3 -0
  53. data/lib/decidim/forms/version.rb +1 -1
  54. metadata +35 -32
  55. data/app/assets/config/admin/decidim_forms_manifest.css +0 -3
  56. data/app/assets/config/admin/decidim_forms_manifest.js +0 -2
  57. data/app/assets/config/decidim_forms_manifest.css +0 -4
  58. data/app/assets/config/decidim_forms_manifest.js +0 -1
  59. data/app/assets/javascripts/decidim/forms/admin/auto_buttons_by_min_items.component.js.es6 +0 -25
  60. data/app/assets/javascripts/decidim/forms/admin/auto_select_options_by_total_items.component.js.es6 +0 -23
  61. data/app/assets/javascripts/decidim/forms/admin/auto_select_options_from_url.component.js.es6 +0 -40
  62. data/app/assets/javascripts/decidim/forms/admin/live_text_update.component.js.es6 +0 -52
  63. data/app/assets/javascripts/decidim/forms/autosortable_checkboxes.component.js.es6 +0 -85
  64. data/app/assets/javascripts/decidim/forms/display_conditions.component.js.es6 +0 -203
  65. data/app/assets/javascripts/decidim/forms/max_choices_alert.component.js.es6 +0 -44
  66. data/app/assets/javascripts/decidim/forms/option_attached_inputs.component.js.es6 +0 -32
  67. data/config/locales/ja-JP.yml +0 -170
@@ -1,3 +0,0 @@
1
- /*
2
- *= link decidim/forms/questionnaire-answers-pdf.scss
3
- */
@@ -1,2 +0,0 @@
1
- //= link decidim/forms/admin/forms.js
2
- //= link decidim/forms/admin/collapsible_questions.js
@@ -1,4 +0,0 @@
1
- /*
2
- *= link decidim/forms/forms.scss
3
- *= link decidim/forms/questionnaire-answers-pdf.scss
4
- */
@@ -1 +0,0 @@
1
- // = link decidim/forms/forms.js
@@ -1,25 +0,0 @@
1
- ((exports) => {
2
- class AutoButtonsByMinItemsComponent {
3
- constructor(options = {}) {
4
- this.listSelector = options.listSelector;
5
- this.minItems = options.minItems;
6
- this.hideOnMinItemsOrLessSelector = options.hideOnMinItemsOrLessSelector;
7
-
8
- this.run();
9
- }
10
-
11
- run() {
12
- const $list = $(this.listSelector);
13
- const $items = $list.find(this.hideOnMinItemsOrLessSelector);
14
-
15
- if ($list.length <= this.minItems) {
16
- $items.hide();
17
- } else {
18
- $items.show();
19
- }
20
- }
21
- }
22
-
23
- exports.DecidimAdmin = exports.DecidimAdmin || {};
24
- exports.DecidimAdmin.AutoButtonsByMinItemsComponent = AutoButtonsByMinItemsComponent;
25
- })(window);
@@ -1,23 +0,0 @@
1
- ((exports) => {
2
- class AutoSelectOptionsByTotalItemsComponent {
3
- constructor(options = {}) {
4
- this.wrapperSelector = options.wrapperSelector;
5
- this.selectSelector = options.selectSelector;
6
- this.listSelector = options.listSelector;
7
- }
8
-
9
- run() {
10
- const $list = $(this.listSelector);
11
- const $selectField = $list.parents(this.wrapperSelector).find(this.selectSelector);
12
-
13
- $selectField.find("option").slice(1).remove();
14
-
15
- for (let idx = 2; idx <= $list.length; idx += 1) {
16
- $(`<option value="${idx}">${idx}</option>`).appendTo($selectField);
17
- }
18
- }
19
- }
20
-
21
- exports.DecidimAdmin = exports.DecidimAdmin || {};
22
- exports.DecidimAdmin.AutoSelectOptionsByTotalItemsComponent = AutoSelectOptionsByTotalItemsComponent;
23
- })(window);
@@ -1,40 +0,0 @@
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,52 +0,0 @@
1
- /**
2
- * This component allows for an element's text value to be updated with the value
3
- * of an input whenever this input's value is changed.
4
- *
5
- * @param {object} options
6
- *
7
- * Available options:
8
- * {string} `inputSelector`: The query selector to locate the input element
9
- * {string} `targetSelector`: The query selector to locate the target element
10
- * {number} `maxLength`: The maximum characters from the input value to be displayed in the target
11
- * {string} `omission`: The string used to shorten the value to the given maxLength (e.g. "...")
12
- * {string} `placeholder`: The string to be displayed in the target element when the input has no value
13
- */
14
- ((exports) => {
15
- class LiveTextUpdateComponent {
16
- constructor(options = {}) {
17
- this.inputSelector = options.inputSelector;
18
- this.targetSelector = options.targetSelector;
19
- this.maxLength = options.maxLength;
20
- this.omission = options.omission;
21
- this.placeholder = options.placeholder;
22
- this._bindEvent();
23
- this._run();
24
- }
25
-
26
- _run() {
27
- const $input = $(this.inputSelector);
28
- const $target = $(this.targetSelector);
29
-
30
- let text = $input.val() || this.placeholder;
31
-
32
- // truncate string
33
- if (text.length > this.maxLength) {
34
- text = text.substring(0, this.maxLength - this.omission.length) + this.omission;
35
- }
36
-
37
- $target.text(text);
38
- }
39
-
40
- _bindEvent() {
41
- const $input = $(this.inputSelector);
42
- $input.on("change", this._run.bind(this));
43
- }
44
-
45
- }
46
-
47
- exports.DecidimAdmin = exports.DecidimAdmin || {};
48
- exports.DecidimAdmin.LiveTextUpdateComponent = LiveTextUpdateComponent;
49
- exports.DecidimAdmin.createLiveTextUpdateComponent = (options) => {
50
- return new LiveTextUpdateComponent(options);
51
- }
52
- })(window);
@@ -1,85 +0,0 @@
1
- /* eslint-disable no-ternary */
2
-
3
- ((exports) => {
4
- class AutosortableCheckboxesComponent {
5
- constructor(options = {}) {
6
- this.wrapperField = options.wrapperField;
7
- this._bindEvent();
8
- this._order();
9
- this._normalize();
10
- }
11
-
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;
20
-
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
-
28
- if (position > nextPosition) {
29
- $next.insertBefore($(el));
30
- }
31
- $next = $next.next();
32
- }
33
- });
34
- }
35
-
36
- _findLastPosition() {
37
- let lastPosition = 0;
38
- $(this.wrapperField).find(".collection-input").each((idx, el) => {
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
- }
47
-
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()) {
52
- $positionField.val(idx);
53
- $positionField.prop("disabled", false);
54
- $(el).html(`${idx + 1}. `);
55
- }
56
- });
57
- }
58
-
59
- _bindEvent() {
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();
77
- });
78
- }
79
- }
80
-
81
- exports.Decidim = exports.Decidim || {};
82
- exports.Decidim.createAutosortableCheckboxes = (options) => {
83
- return new AutosortableCheckboxesComponent(options);
84
- };
85
- })(window);
@@ -1,203 +0,0 @@
1
- /* eslint-disable no-ternary, no-plusplus */
2
-
3
- ((exports) => {
4
- class DisplayCondition {
5
- constructor(options = {}) {
6
- this.wrapperField = options.wrapperField;
7
- this.type = options.type;
8
- this.conditionQuestion = options.conditionQuestion;
9
- this.answerOption = options.answerOption;
10
- this.mandatory = options.mandatory;
11
- this.value = options.value;
12
- this.onFulfilled = options.onFulfilled;
13
- this.bindEvent();
14
- }
15
-
16
- bindEvent() {
17
- this.checkCondition();
18
- this.getInputsToListen().on("change", this.checkCondition.bind(this));
19
- }
20
-
21
- getInputValue() {
22
- const $conditionWrapperField = $(`.question[data-question-id='${this.conditionQuestion}']`);
23
- const $textInput = $conditionWrapperField.find("textarea, input[type='text']:not([name$=\\[custom_body\\]])");
24
-
25
- if ($textInput.length) {
26
- return $textInput.val();
27
- }
28
-
29
- let multipleInput = [];
30
-
31
- $conditionWrapperField.find(".radio-button-collection, .check-box-collection").find(".collection-input").each((idx, el) => {
32
- const $input = $(el).find("input[name$=\\[body\\]]");
33
- const checked = $input.is(":checked");
34
-
35
- if (checked) {
36
- const text = $(el).find("input[name$=\\[custom_body\\]]").val();
37
- const value = $input.val();
38
- const id = $(el).find("input[name$=\\[answer_option_id\\]]").val();
39
-
40
- multipleInput.push({ id, value, text });
41
- }
42
- });
43
-
44
- return multipleInput;
45
- }
46
-
47
- getInputsToListen() {
48
- const $conditionWrapperField = $(`.question[data-question-id='${this.conditionQuestion}']`);
49
- const $textInput = $conditionWrapperField.find("textarea, input[type='text']:not([name$=\\[custom_body\\]])");
50
-
51
- if ($textInput.length) {
52
- return $textInput;
53
- }
54
-
55
- return $conditionWrapperField.find(".collection-input").find("input:not([type='hidden'])");
56
- }
57
-
58
- checkAnsweredCondition(value) {
59
- if (typeof (value) !== "object") {
60
- return Boolean(value);
61
- }
62
-
63
- return Boolean(value.some((it) => it.value));
64
- }
65
-
66
- checkNotAnsweredCondition(value) {
67
- return !this.checkAnsweredCondition(value);
68
- }
69
-
70
- checkEqualCondition(value) {
71
- if (value.length) {
72
- return value.some((it) => it.id === this.answerOption.toString());
73
- }
74
- return false;
75
- }
76
-
77
- checkNotEqualCondition(value) {
78
- if (value.length) {
79
- return value.every((it) => it.id !== this.answerOption.toString());
80
- }
81
- return false;
82
- }
83
-
84
- checkMatchCondition(value) {
85
- let regexp = new RegExp(this.value, "i");
86
-
87
- if (typeof (value) !== "object") {
88
- return Boolean(value.match(regexp));
89
- }
90
-
91
- return value.some(function (it) {
92
- return it.text
93
- ? it.text.match(regexp)
94
- : it.value.match(regexp)
95
- });
96
- }
97
-
98
- checkCondition() {
99
- const value = this.getInputValue();
100
- let fulfilled = false;
101
-
102
- switch (this.type) {
103
- case "answered":
104
- fulfilled = this.checkAnsweredCondition(value);
105
- break;
106
- case "not_answered":
107
- fulfilled = this.checkNotAnsweredCondition(value);
108
- break;
109
- case "equal":
110
- fulfilled = this.checkEqualCondition(value);
111
- break;
112
- case "not_equal":
113
- fulfilled = this.checkNotEqualCondition(value);
114
- break;
115
- case "match":
116
- fulfilled = this.checkMatchCondition(value);
117
- break;
118
- default:
119
- fulfilled = false;
120
- break;
121
- }
122
-
123
- this.onFulfilled(fulfilled);
124
- }
125
- }
126
-
127
- class DisplayConditionsComponent {
128
- constructor(options = {}) {
129
- this.wrapperField = options.wrapperField;
130
- this.conditions = {};
131
- this.showCount = 0;
132
- this.initializeConditions();
133
- }
134
-
135
- initializeConditions() {
136
- const $conditionElements = this.wrapperField.find(".display-condition");
137
-
138
- $conditionElements.each((idx, el) => {
139
- const $condition = $(el);
140
- const id = $condition.data("id");
141
- this.conditions[id] = {};
142
-
143
- this.conditions[id] = new DisplayCondition({
144
- wrapperField: this.wrapperField,
145
- type: $condition.data("type"),
146
- conditionQuestion: $condition.data("condition"),
147
- answerOption: $condition.data("option"),
148
- mandatory: $condition.data("mandatory"),
149
- value: $condition.data("value"),
150
- onFulfilled: (fulfilled) => {
151
- this.onFulfilled(id, fulfilled);
152
- }
153
- });
154
- });
155
- }
156
-
157
- mustShow() {
158
- const conditions = Object.values(this.conditions);
159
- const mandatoryConditions = conditions.filter((condition) => condition.mandatory);
160
- const nonMandatoryConditions = conditions.filter((condition) => !condition.mandatory);
161
-
162
- if (mandatoryConditions.length) {
163
- return mandatoryConditions.every((condition) => condition.fulfilled);
164
- }
165
-
166
- return nonMandatoryConditions.some((condition) => condition.fulfilled);
167
-
168
- }
169
-
170
- onFulfilled(id, fulfilled) {
171
- this.conditions[id].fulfilled = fulfilled;
172
-
173
- if (this.mustShow()) {
174
- this.showQuestion();
175
- }
176
- else {
177
- this.hideQuestion();
178
- }
179
- }
180
-
181
- showQuestion() {
182
- this.wrapperField.fadeIn();
183
- this.wrapperField.find("input, textarea").prop("disabled", null);
184
- this.showCount++;
185
- }
186
-
187
- hideQuestion() {
188
- if (this.showCount) {
189
- this.wrapperField.fadeOut();
190
- }
191
- else {
192
- this.wrapperField.hide();
193
- }
194
-
195
- this.wrapperField.find("input, textarea").prop("disabled", "disabled");
196
- }
197
- }
198
-
199
- exports.Decidim = exports.Decidim || {};
200
- exports.Decidim.createDisplayConditions = (options) => {
201
- return new DisplayConditionsComponent(options);
202
- };
203
- })(window);