decidim-forms 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/config/admin/decidim_forms_manifest.js +1 -0
- data/app/assets/images/decidim/surveys/icon.svg +1 -19
- data/app/assets/javascripts/decidim/forms/admin/collapsible_questions.js.es6 +13 -0
- data/app/assets/javascripts/decidim/forms/admin/forms.js.es6 +95 -7
- data/app/assets/javascripts/decidim/forms/admin/live_text_update.component.js.es6 +52 -0
- data/app/assets/javascripts/decidim/forms/forms.js.es6 +42 -1
- data/app/assets/javascripts/decidim/forms/max_choices_alert.component.js.es6 +44 -0
- data/app/assets/stylesheets/decidim/forms/forms.scss +39 -0
- data/app/cells/decidim/forms/matrix_readonly/show.erb +5 -0
- data/app/cells/decidim/forms/matrix_readonly_cell.rb +12 -0
- data/app/cells/decidim/forms/question_readonly/show.erb +5 -1
- data/app/cells/decidim/forms/question_readonly_cell.rb +5 -0
- data/app/cells/decidim/forms/step_navigation/show.erb +35 -0
- data/app/cells/decidim/forms/step_navigation_cell.rb +46 -0
- data/app/commands/decidim/forms/admin/update_questionnaire.rb +8 -0
- data/app/commands/decidim/forms/answer_questionnaire.rb +2 -1
- data/app/controllers/decidim/forms/admin/concerns/has_questionnaire.rb +6 -2
- data/app/controllers/decidim/forms/concerns/has_questionnaire.rb +11 -2
- data/app/forms/decidim/forms/admin/question_form.rb +20 -1
- data/app/forms/decidim/forms/admin/question_matrix_row_form.rb +26 -0
- data/app/forms/decidim/forms/answer_choice_form.rb +1 -0
- data/app/forms/decidim/forms/answer_form.rb +16 -2
- data/app/forms/decidim/forms/questionnaire_form.rb +25 -3
- data/app/helpers/decidim/forms/admin/application_helper.rb +16 -0
- data/app/models/decidim/forms/answer_choice.rb +7 -0
- data/app/models/decidim/forms/question.rb +18 -2
- data/app/models/decidim/forms/question_matrix_row.rb +12 -0
- data/app/views/decidim/forms/admin/questionnaires/_answer_option_template.html.erb +1 -1
- data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +37 -4
- data/app/views/decidim/forms/admin/questionnaires/_matrix_row.html.erb +34 -0
- data/app/views/decidim/forms/admin/questionnaires/_matrix_row_template.html.erb +7 -0
- data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +29 -6
- data/app/views/decidim/forms/admin/questionnaires/_separator.html.erb +41 -0
- data/app/views/decidim/forms/questionnaires/_answer.html.erb +21 -92
- data/app/views/decidim/forms/questionnaires/answers/_long_answer.html.erb +1 -0
- data/app/views/decidim/forms/questionnaires/answers/_matrix_multiple.html.erb +43 -0
- data/app/views/decidim/forms/questionnaires/answers/_matrix_single.html.erb +43 -0
- data/app/views/decidim/forms/questionnaires/answers/_multiple_option.html.erb +23 -0
- data/app/views/decidim/forms/questionnaires/answers/_separator.html.erb +1 -0
- data/app/views/decidim/forms/questionnaires/answers/_short_answer.html.erb +1 -0
- data/app/views/decidim/forms/questionnaires/answers/_single_option.html.erb +30 -0
- data/app/views/decidim/forms/questionnaires/answers/_sorting.html.erb +23 -0
- data/app/views/decidim/forms/questionnaires/show.html.erb +57 -25
- data/config/locales/ar.yml +7 -3
- data/config/locales/bg-BG.yml +16 -0
- data/config/locales/ca.yml +35 -3
- data/config/locales/cs.yml +35 -3
- data/config/locales/da-DK.yml +1 -0
- data/config/locales/de.yml +41 -3
- data/config/locales/el.yml +119 -0
- data/config/locales/en.yml +35 -3
- data/config/locales/es-MX.yml +35 -3
- data/config/locales/es-PY.yml +35 -3
- data/config/locales/es.yml +35 -3
- data/config/locales/et-EE.yml +1 -0
- data/config/locales/eu.yml +7 -3
- data/config/locales/fi-plain.yml +35 -3
- data/config/locales/fi.yml +36 -4
- data/config/locales/fr-CA.yml +120 -0
- data/config/locales/fr.yml +36 -4
- data/config/locales/ga-IE.yml +1 -0
- data/config/locales/gl.yml +7 -3
- data/config/locales/hr-HR.yml +1 -0
- data/config/locales/hu.yml +11 -3
- data/config/locales/id-ID.yml +7 -3
- data/config/locales/it.yml +36 -4
- data/config/locales/ja-JP.yml +120 -0
- data/config/locales/lt-LT.yml +1 -0
- data/config/locales/lv-LV.yml +119 -0
- data/config/locales/mt-MT.yml +1 -0
- data/config/locales/nl.yml +35 -3
- data/config/locales/no.yml +7 -3
- data/config/locales/pl.yml +63 -25
- data/config/locales/pt-BR.yml +8 -4
- data/config/locales/pt.yml +62 -24
- data/config/locales/ro-RO.yml +118 -0
- data/config/locales/ru.yml +4 -1
- data/config/locales/sk-SK.yml +88 -0
- data/config/locales/sk.yml +92 -0
- data/config/locales/sl.yml +5 -0
- data/config/locales/sr-CS.yml +1 -0
- data/config/locales/sv.yml +38 -6
- data/config/locales/tr-TR.yml +7 -3
- data/db/migrate/20200225123810_create_decidim_forms_question_matrix_rows.rb +11 -0
- data/db/migrate/20200304152939_add_matrix_row_id_to_decidim_forms_answer_choices.rb +11 -0
- data/lib/decidim/forms/test/factories.rb +20 -0
- data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +313 -36
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +346 -15
- data/lib/decidim/forms/user_answers_serializer.rb +21 -4
- data/lib/decidim/forms/version.rb +1 -1
- metadata +45 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 73b7dd5e0d7e94151c79b989666d5a3d1e3790db9c97cee7a35c587a0a00977e
|
|
4
|
+
data.tar.gz: 4e7f6a2d27f58079d5eed9d08404373a66636f6960a220dc1572809a482dfbb3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b2eed83cff858299ee6fef944b1951150ad4634a193fec095ca20a393bfec8de0f1a2fe1e09447728d40dbb2898ce4b884d4ab82cdecaf93c6025efd1d677bd5
|
|
7
|
+
data.tar.gz: e1e84f6aa8d5a1cb2ea2fe95593bd0ba0977d536c4abb3a3cc66726cf66a425dd7c1622f462cc9324c5fbf0d375e0dcc43c2844eb0b0fafc5457f97d34a6de70
|
|
@@ -1,19 +1 @@
|
|
|
1
|
-
|
|
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,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,9 @@
|
|
|
1
1
|
// = require ./auto_buttons_by_min_items.component
|
|
2
2
|
// = require ./auto_select_options_by_total_items.component
|
|
3
|
+
// = require ./live_text_update.component
|
|
3
4
|
|
|
4
5
|
((exports) => {
|
|
5
|
-
const { AutoLabelByPositionComponent, AutoButtonsByPositionComponent, AutoButtonsByMinItemsComponent, AutoSelectOptionsByTotalItemsComponent, createFieldDependentInputs, createDynamicFields, createSortList } = exports.DecidimAdmin;
|
|
6
|
+
const { AutoLabelByPositionComponent, AutoButtonsByPositionComponent, AutoButtonsByMinItemsComponent, AutoSelectOptionsByTotalItemsComponent, createLiveTextUpdateComponent, createFieldDependentInputs, createDynamicFields, createSortList } = exports.DecidimAdmin;
|
|
6
7
|
const { createQuillEditor } = exports.Decidim;
|
|
7
8
|
|
|
8
9
|
const wrapperSelector = ".questionnaire-questions";
|
|
@@ -11,8 +12,15 @@
|
|
|
11
12
|
const answerOptionFieldSelector = ".questionnaire-question-answer-option";
|
|
12
13
|
const answerOptionsWrapperSelector = ".questionnaire-question-answer-options";
|
|
13
14
|
const answerOptionRemoveFieldButtonSelector = ".remove-answer-option";
|
|
15
|
+
const matrixRowFieldSelector = ".questionnaire-question-matrix-row";
|
|
16
|
+
const matrixRowsWrapperSelector = ".questionnaire-question-matrix-rows";
|
|
17
|
+
const matrixRowRemoveFieldButtonSelector = ".remove-matrix-row";
|
|
18
|
+
const addMatrixRowButtonSelector = ".add-matrix-row";
|
|
14
19
|
const maxChoicesWrapperSelector = ".questionnaire-question-max-choices";
|
|
15
20
|
|
|
21
|
+
const MULTIPLE_CHOICE_VALUES = ["single_option", "multiple_option", "sorting", "matrix_single", "matrix_multiple"];
|
|
22
|
+
const MATRIX_VALUES = ["matrix_single", "matrix_multiple"];
|
|
23
|
+
|
|
16
24
|
const autoLabelByPosition = new AutoLabelByPositionComponent({
|
|
17
25
|
listSelector: ".questionnaire-question:not(.hidden)",
|
|
18
26
|
labelSelector: ".card-title span:first",
|
|
@@ -49,10 +57,29 @@
|
|
|
49
57
|
handle: ".question-divider",
|
|
50
58
|
placeholder: '<div style="border-style: dashed; border-color: #000"></div>',
|
|
51
59
|
forcePlaceholderSize: true,
|
|
52
|
-
onSortUpdate: () => {
|
|
60
|
+
onSortUpdate: () => {
|
|
61
|
+
autoLabelByPosition.run();
|
|
62
|
+
autoButtonsByPosition.run();
|
|
63
|
+
}
|
|
53
64
|
});
|
|
54
65
|
};
|
|
55
66
|
|
|
67
|
+
const createDynamicQuestionTitle = (fieldId) => {
|
|
68
|
+
const targetSelector = `#${fieldId} .question-title-statement`;
|
|
69
|
+
const locale = $(targetSelector).data("locale");
|
|
70
|
+
const maxLength = $(targetSelector).data("max-length");
|
|
71
|
+
const omission = $(targetSelector).data("omission");
|
|
72
|
+
const placeholder = $(targetSelector).data("placeholder");
|
|
73
|
+
|
|
74
|
+
return createLiveTextUpdateComponent({
|
|
75
|
+
inputSelector: `#${fieldId} input[name$=\\[body_${locale}\\]]`,
|
|
76
|
+
targetSelector: targetSelector,
|
|
77
|
+
maxLength: maxLength,
|
|
78
|
+
omission: omission,
|
|
79
|
+
placeholder: placeholder
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
56
83
|
const createDynamicFieldsForAnswerOptions = (fieldId) => {
|
|
57
84
|
const autoButtons = createAutoButtonsByMinItemsForAnswerOptions(fieldId);
|
|
58
85
|
const autoSelectOptions = createAutoMaxChoicesByNumberOfAnswerOptions(fieldId);
|
|
@@ -63,6 +90,7 @@
|
|
|
63
90
|
containerSelector: ".questionnaire-question-answer-options-list",
|
|
64
91
|
fieldSelector: answerOptionFieldSelector,
|
|
65
92
|
addFieldButtonSelector: ".add-answer-option",
|
|
93
|
+
fieldTemplateSelector: ".decidim-answer-option-template",
|
|
66
94
|
removeFieldButtonSelector: answerOptionRemoveFieldButtonSelector,
|
|
67
95
|
onAddField: () => {
|
|
68
96
|
autoButtons.run();
|
|
@@ -77,16 +105,42 @@
|
|
|
77
105
|
|
|
78
106
|
const dynamicFieldsForAnswerOptions = {};
|
|
79
107
|
|
|
108
|
+
const createDynamicFieldsForMatrixRows = (fieldId) => {
|
|
109
|
+
return createDynamicFields({
|
|
110
|
+
placeholderId: "questionnaire-question-matrix-row-id",
|
|
111
|
+
wrapperSelector: `#${fieldId} ${matrixRowsWrapperSelector}`,
|
|
112
|
+
containerSelector: ".questionnaire-question-matrix-rows-list",
|
|
113
|
+
fieldSelector: matrixRowFieldSelector,
|
|
114
|
+
addFieldButtonSelector: addMatrixRowButtonSelector,
|
|
115
|
+
fieldTemplateSelector: ".decidim-matrix-row-template",
|
|
116
|
+
removeFieldButtonSelector: matrixRowRemoveFieldButtonSelector,
|
|
117
|
+
onAddField: () => {
|
|
118
|
+
},
|
|
119
|
+
onRemoveField: () => {
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const dynamicFieldsForMatrixRows = {};
|
|
125
|
+
|
|
80
126
|
const isMultipleChoiceOption = ($selectField) => {
|
|
81
127
|
const value = $selectField.val();
|
|
82
128
|
|
|
83
|
-
return value
|
|
129
|
+
return MULTIPLE_CHOICE_VALUES.indexOf(value) >= 0;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const isMatrix = ($selectField) => {
|
|
133
|
+
const value = $selectField.val();
|
|
134
|
+
|
|
135
|
+
return MATRIX_VALUES.indexOf(value) >= 0;
|
|
84
136
|
}
|
|
85
137
|
|
|
86
138
|
const setupInitialQuestionAttributes = ($target) => {
|
|
87
139
|
const fieldId = $target.attr("id");
|
|
88
140
|
const $fieldQuestionTypeSelect = $target.find(questionTypeSelector);
|
|
89
141
|
|
|
142
|
+
createDynamicQuestionTitle(fieldId);
|
|
143
|
+
|
|
90
144
|
createFieldDependentInputs({
|
|
91
145
|
controllerField: $fieldQuestionTypeSelect,
|
|
92
146
|
wrapperSelector: fieldSelector,
|
|
@@ -103,21 +157,42 @@
|
|
|
103
157
|
dependentFieldsSelector: maxChoicesWrapperSelector,
|
|
104
158
|
dependentInputSelector: "select",
|
|
105
159
|
enablingCondition: ($field) => {
|
|
106
|
-
return $field.val() === "multiple_option"
|
|
160
|
+
return $field.val() === "multiple_option" || $field.val() === "matrix_multiple";
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
createFieldDependentInputs({
|
|
165
|
+
controllerField: $fieldQuestionTypeSelect,
|
|
166
|
+
wrapperSelector: fieldSelector,
|
|
167
|
+
dependentFieldsSelector: matrixRowsWrapperSelector,
|
|
168
|
+
dependentInputSelector: `${matrixRowFieldSelector} input`,
|
|
169
|
+
enablingCondition: ($field) => {
|
|
170
|
+
return isMatrix($field);
|
|
107
171
|
}
|
|
108
172
|
});
|
|
109
173
|
|
|
110
174
|
dynamicFieldsForAnswerOptions[fieldId] = createDynamicFieldsForAnswerOptions(fieldId);
|
|
175
|
+
dynamicFieldsForMatrixRows[fieldId] = createDynamicFieldsForMatrixRows(fieldId);
|
|
111
176
|
|
|
112
|
-
const
|
|
177
|
+
const dynamicFieldsAnswerOptions = dynamicFieldsForAnswerOptions[fieldId];
|
|
178
|
+
const dynamicFieldsMatrixRows = dynamicFieldsForMatrixRows[fieldId];
|
|
113
179
|
|
|
114
180
|
const onQuestionTypeChange = () => {
|
|
115
181
|
if (isMultipleChoiceOption($fieldQuestionTypeSelect)) {
|
|
116
182
|
const nOptions = $fieldQuestionTypeSelect.parents(fieldSelector).find(answerOptionFieldSelector).length;
|
|
117
183
|
|
|
118
184
|
if (nOptions === 0) {
|
|
119
|
-
|
|
120
|
-
|
|
185
|
+
dynamicFieldsAnswerOptions._addField();
|
|
186
|
+
dynamicFieldsAnswerOptions._addField();
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (isMatrix($fieldQuestionTypeSelect)) {
|
|
191
|
+
const nRows = $fieldQuestionTypeSelect.parents(fieldSelector).find(matrixRowFieldSelector).length;
|
|
192
|
+
|
|
193
|
+
if (nRows === 0) {
|
|
194
|
+
dynamicFieldsMatrixRows._addField();
|
|
195
|
+
dynamicFieldsMatrixRows._addField();
|
|
121
196
|
}
|
|
122
197
|
}
|
|
123
198
|
};
|
|
@@ -142,10 +217,20 @@
|
|
|
142
217
|
containerSelector: ".questionnaire-questions-list",
|
|
143
218
|
fieldSelector: fieldSelector,
|
|
144
219
|
addFieldButtonSelector: ".add-question",
|
|
220
|
+
addSeparatorButtonSelector: ".add-separator",
|
|
221
|
+
fieldTemplateSelector: ".decidim-question-template",
|
|
222
|
+
separatorTemplateSelector: ".decidim-separator-template",
|
|
145
223
|
removeFieldButtonSelector: ".remove-question",
|
|
146
224
|
moveUpFieldButtonSelector: ".move-up-question",
|
|
147
225
|
moveDownFieldButtonSelector: ".move-down-question",
|
|
148
226
|
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
|
+
|
|
149
234
|
setupInitialQuestionAttributes($field);
|
|
150
235
|
createSortableList();
|
|
151
236
|
|
|
@@ -163,6 +248,9 @@
|
|
|
163
248
|
$field.find(answerOptionRemoveFieldButtonSelector).each((idx, el) => {
|
|
164
249
|
dynamicFieldsForAnswerOptions[$field.attr("id")]._removeField(el);
|
|
165
250
|
});
|
|
251
|
+
$field.find(matrixRowRemoveFieldButtonSelector).each((idx, el) => {
|
|
252
|
+
dynamicFieldsForMatrixRows[$field.attr("id")]._removeField(el);
|
|
253
|
+
});
|
|
166
254
|
},
|
|
167
255
|
onMoveUpField: () => {
|
|
168
256
|
autoLabelByPosition.run();
|
|
@@ -0,0 +1,52 @@
|
|
|
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,8 +1,9 @@
|
|
|
1
1
|
// = require ./option_attached_inputs.component
|
|
2
2
|
// = require ./autosortable_checkboxes.component
|
|
3
|
+
// = require ./max_choices_alert.component
|
|
3
4
|
|
|
4
5
|
((exports) => {
|
|
5
|
-
const { createOptionAttachedInputs, createAutosortableCheckboxes } = exports.Decidim;
|
|
6
|
+
const { createOptionAttachedInputs, createAutosortableCheckboxes, createMaxChoicesAlertComponent } = exports.Decidim;
|
|
6
7
|
|
|
7
8
|
$(".radio-button-collection, .check-box-collection").each((idx, el) => {
|
|
8
9
|
createOptionAttachedInputs({
|
|
@@ -12,9 +13,49 @@
|
|
|
12
13
|
});
|
|
13
14
|
});
|
|
14
15
|
|
|
16
|
+
$.unique($(".check-box-collection").parents(".answer")).each((idx, el) => {
|
|
17
|
+
const maxChoices = $(el).data("max-choices");
|
|
18
|
+
if (maxChoices) {
|
|
19
|
+
createMaxChoicesAlertComponent({
|
|
20
|
+
wrapperField: $(el),
|
|
21
|
+
controllerFieldSelector: "input[type=checkbox]",
|
|
22
|
+
controllerCollectionSelector: ".check-box-collection",
|
|
23
|
+
alertElement: $(el).find(".max-choices-alert"),
|
|
24
|
+
maxChoices: maxChoices
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
15
29
|
$(".sortable-check-box-collection").each((idx, el) => {
|
|
16
30
|
createAutosortableCheckboxes({
|
|
17
31
|
wrapperField: $(el)
|
|
18
32
|
})
|
|
19
33
|
});
|
|
34
|
+
|
|
35
|
+
const $form = $("form.answer-questionnaire");
|
|
36
|
+
if ($form.length > 0) {
|
|
37
|
+
$form.find("input, textarea, select").on("change", () => {
|
|
38
|
+
$form.data("changed", true);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const safePath = $form.data("safe-path").split("?")[0];
|
|
42
|
+
$(document).on("click", "a", (event) => {
|
|
43
|
+
window.exitUrl = event.currentTarget.href;
|
|
44
|
+
});
|
|
45
|
+
$(document).on("submit", "form", (event) => {
|
|
46
|
+
window.exitUrl = event.currentTarget.action;
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
window.onbeforeunload = () => {
|
|
50
|
+
const exitUrl = window.exitUrl;
|
|
51
|
+
const hasChanged = $form.data("changed");
|
|
52
|
+
window.exitUrl = null;
|
|
53
|
+
|
|
54
|
+
if (!hasChanged || (exitUrl && exitUrl.includes(safePath))) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return "";
|
|
59
|
+
}
|
|
60
|
+
}
|
|
20
61
|
})(window);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
((exports) => {
|
|
2
|
+
class MaxChoicesAlertComponent {
|
|
3
|
+
constructor(options = {}) {
|
|
4
|
+
this.wrapperField = options.wrapperField;
|
|
5
|
+
this.alertElement = options.alertElement;
|
|
6
|
+
this.controllerFieldSelector = options.controllerFieldSelector;
|
|
7
|
+
this.controllerCollectionSelector = options.controllerCollectionSelector;
|
|
8
|
+
this.maxChoices = options.maxChoices;
|
|
9
|
+
this.controllerSelector = this.wrapperField.find(this.controllerFieldSelector);
|
|
10
|
+
this._bindEvent();
|
|
11
|
+
this._run();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
_run() {
|
|
15
|
+
const rows = this.wrapperField.find(this.controllerCollectionSelector);
|
|
16
|
+
|
|
17
|
+
let alert = false;
|
|
18
|
+
|
|
19
|
+
rows.each((rowIdx, row) => {
|
|
20
|
+
const checked = $(row).find(this.controllerFieldSelector).filter((checkboxIdx, checkbox) => $(checkbox).is(":checked"));
|
|
21
|
+
|
|
22
|
+
alert = alert || checked.length > this.maxChoices;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (alert) {
|
|
26
|
+
this.alertElement.show();
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
this.alertElement.hide();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
_bindEvent() {
|
|
34
|
+
this.controllerSelector.on("change", () => {
|
|
35
|
+
this._run();
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
exports.Decidim = exports.Decidim || {};
|
|
41
|
+
exports.Decidim.createMaxChoicesAlertComponent = (options) => {
|
|
42
|
+
return new MaxChoicesAlertComponent(options);
|
|
43
|
+
};
|
|
44
|
+
})(window);
|
|
@@ -35,3 +35,42 @@
|
|
|
35
35
|
.questionnaire-question_readonly-answer{
|
|
36
36
|
font-weight: normal;
|
|
37
37
|
}
|
|
38
|
+
|
|
39
|
+
.questionnaire-question-matrix{
|
|
40
|
+
.collection-input{
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
justify-content: center;
|
|
44
|
+
flex-grow: 1;
|
|
45
|
+
flex-basis: 0;
|
|
46
|
+
|
|
47
|
+
input[type="text"]{
|
|
48
|
+
margin-top: auto;
|
|
49
|
+
margin-bottom: auto;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
input[type="checkbox"],
|
|
53
|
+
input[type="radio"]{
|
|
54
|
+
margin-bottom: 0;
|
|
55
|
+
|
|
56
|
+
& ~ input[type="text"]{
|
|
57
|
+
margin-left: .5rem;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
tr,
|
|
63
|
+
tr:nth-child(2n){
|
|
64
|
+
background: initial;
|
|
65
|
+
border-bottom: 1px solid #f0f0f0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
thead td{
|
|
69
|
+
text-align: center;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
td{
|
|
73
|
+
min-width: 100px;
|
|
74
|
+
border-right: 1px solid #f0f0f0;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Forms
|
|
5
|
+
# This cell renders a possible matrix answer of a question (readonly)
|
|
6
|
+
class MatrixReadonlyCell < Decidim::ViewModel
|
|
7
|
+
def answer_options
|
|
8
|
+
model.question.answer_options.map { |option| translated_attribute(option.body) }.join(" / ")
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|