decidim-forms 0.19.0 → 0.22.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- 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 +7 -2
- data/app/controllers/decidim/forms/admin/concerns/has_questionnaire.rb +6 -2
- data/app/controllers/decidim/forms/concerns/has_questionnaire.rb +58 -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 +33 -3
- data/app/helpers/decidim/forms/admin/application_helper.rb +16 -0
- data/app/models/decidim/forms/answer.rb +2 -2
- 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/models/decidim/forms/questionnaire.rb +2 -1
- data/app/queries/decidim/forms/questionnaire_user_answers.rb +1 -1
- data/app/types/decidim/forms/answer_option_type.rb +14 -0
- data/app/types/decidim/forms/question_type.rb +23 -0
- data/app/types/decidim/forms/questionnaire_type.rb +22 -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 +60 -27
- data/config/locales/ar.yml +12 -3
- data/config/locales/bg-BG.yml +16 -0
- data/config/locales/ca.yml +45 -7
- data/config/locales/cs.yml +41 -3
- data/config/locales/da-DK.yml +1 -0
- data/config/locales/de.yml +41 -3
- data/config/locales/el-GR.yml +1 -0
- data/config/locales/el.yml +120 -0
- data/config/locales/en.yml +41 -3
- data/config/locales/es-MX.yml +41 -3
- data/config/locales/es-PY.yml +41 -3
- data/config/locales/es.yml +41 -3
- data/config/locales/et-EE.yml +1 -0
- data/config/locales/eu.yml +7 -3
- data/config/locales/fi-plain.yml +41 -3
- data/config/locales/fi.yml +42 -4
- data/config/locales/fr-CA.yml +120 -0
- data/config/locales/fr.yml +41 -3
- 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 +18 -4
- data/config/locales/id-ID.yml +7 -3
- data/config/locales/is-IS.yml +1 -0
- data/config/locales/it.yml +42 -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 +41 -3
- data/config/locales/no.yml +86 -1
- 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 +47 -0
- 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 +41 -3
- data/config/locales/tr-TR.yml +7 -3
- data/db/migrate/20190315203056_add_session_token_to_decidim_forms_answers.rb +17 -0
- data/db/migrate/20190930094710_add_ip_hash_to_decidim_form_answers.rb +12 -0
- 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/api/questionnaire_entity_interface.rb +18 -0
- data/lib/decidim/forms.rb +1 -0
- data/lib/decidim/forms/api.rb +7 -0
- data/lib/decidim/forms/test/factories.rb +55 -11
- data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +320 -43
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +347 -16
- data/lib/decidim/forms/user_answers_serializer.rb +23 -4
- data/lib/decidim/forms/version.rb +1 -1
- metadata +56 -9
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
|
data/README.md
CHANGED
@@ -54,7 +54,7 @@ See [Decidim](https://github.com/decidim/decidim).
|
|
54
54
|
|
55
55
|
## Seeds
|
56
56
|
|
57
|
-
Since questionnaires cannot exist without a
|
57
|
+
Since questionnaires cannot exist without a component we are not including specific seeds for this engine.
|
58
58
|
|
59
59
|
Other engines are free to include questionnaires on their seeds like this:
|
60
60
|
|
@@ -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
|
+
}
|