decidim-forms 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +65 -0
  3. data/Rakefile +3 -0
  4. data/app/assets/config/admin/decidim_forms_manifest.js +1 -0
  5. data/app/assets/config/decidim_forms_manifest.js +1 -0
  6. data/app/assets/images/decidim/surveys/icon.svg +19 -0
  7. data/app/assets/javascripts/decidim/forms/admin/auto_buttons_by_min_items.component.js.es6 +25 -0
  8. data/app/assets/javascripts/decidim/forms/admin/auto_select_options_by_total_items.component.js.es6 +23 -0
  9. data/app/assets/javascripts/decidim/forms/admin/forms.js.es6 +188 -0
  10. data/app/assets/javascripts/decidim/forms/autosortable_checkboxes.component.js.es6 +65 -0
  11. data/app/assets/javascripts/decidim/forms/forms.js.es6 +20 -0
  12. data/app/assets/javascripts/decidim/forms/option_attached_inputs.component.js.es6 +32 -0
  13. data/app/commands/decidim/forms/admin/update_questionnaire.rb +86 -0
  14. data/app/commands/decidim/forms/answer_questionnaire.rb +54 -0
  15. data/app/controllers/decidim/forms/admin/concerns/has_questionnaire.rb +95 -0
  16. data/app/controllers/decidim/forms/concerns/has_questionnaire.rb +84 -0
  17. data/app/forms/decidim/forms/admin/answer_option_form.rb +23 -0
  18. data/app/forms/decidim/forms/admin/question_form.rb +35 -0
  19. data/app/forms/decidim/forms/admin/questionnaire_form.rb +27 -0
  20. data/app/forms/decidim/forms/answer_choice_form.rb +15 -0
  21. data/app/forms/decidim/forms/answer_form.rb +69 -0
  22. data/app/forms/decidim/forms/questionnaire_form.rb +22 -0
  23. data/app/helpers/decidim/forms/admin/application_helper.rb +19 -0
  24. data/app/models/concerns/decidim/forms/has_questionnaire.rb +20 -0
  25. data/app/models/decidim/forms/answer.rb +45 -0
  26. data/app/models/decidim/forms/answer_choice.rb +15 -0
  27. data/app/models/decidim/forms/answer_option.rb +11 -0
  28. data/app/models/decidim/forms/application_record.rb +10 -0
  29. data/app/models/decidim/forms/question.rb +36 -0
  30. data/app/models/decidim/forms/questionnaire.rb +23 -0
  31. data/app/queries/decidim/forms/questionnaire_user_answers.rb +28 -0
  32. data/app/views/decidim/forms/admin/questionnaires/_answer_option.html.erb +44 -0
  33. data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +51 -0
  34. data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +115 -0
  35. data/app/views/decidim/forms/admin/questionnaires/edit.html.erb +7 -0
  36. data/app/views/decidim/forms/questionnaires/_answer.html.erb +94 -0
  37. data/app/views/decidim/forms/questionnaires/show.html.erb +84 -0
  38. data/config/locales/ca.yml +79 -0
  39. data/config/locales/de.yml +79 -0
  40. data/config/locales/en.yml +79 -0
  41. data/config/locales/es-PY.yml +79 -0
  42. data/config/locales/es.yml +79 -0
  43. data/config/locales/eu.yml +79 -0
  44. data/config/locales/fi-pl.yml +79 -0
  45. data/config/locales/fi.yml +79 -0
  46. data/config/locales/fr.yml +79 -0
  47. data/config/locales/gl.yml +79 -0
  48. data/config/locales/hu.yml +79 -0
  49. data/config/locales/id-ID.yml +1 -0
  50. data/config/locales/it.yml +79 -0
  51. data/config/locales/nl.yml +79 -0
  52. data/config/locales/pl.yml +79 -0
  53. data/config/locales/pt-BR.yml +79 -0
  54. data/config/locales/pt.yml +79 -0
  55. data/config/locales/ru.yml +1 -0
  56. data/config/locales/sv.yml +79 -0
  57. data/config/locales/tr-TR.yml +1 -0
  58. data/config/locales/uk.yml +1 -0
  59. data/db/migrate/20170511092231_create_decidim_forms_questionnaires.rb +15 -0
  60. data/db/migrate/20170515090916_create_decidim_forms_questions.rb +17 -0
  61. data/db/migrate/20170515144119_create_decidim_forms_answers.rb +15 -0
  62. data/db/migrate/20180405015012_create_decidim_forms_answer_options.rb +11 -0
  63. data/db/migrate/20180405015147_create_decidim_forms_answer_choices.rb +13 -0
  64. data/lib/decidim/forms.rb +13 -0
  65. data/lib/decidim/forms/admin.rb +9 -0
  66. data/lib/decidim/forms/admin_engine.rb +21 -0
  67. data/lib/decidim/forms/data_portability_user_answers_serializer.rb +37 -0
  68. data/lib/decidim/forms/engine.rb +14 -0
  69. data/lib/decidim/forms/test.rb +4 -0
  70. data/lib/decidim/forms/test/factories.rb +55 -0
  71. data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +524 -0
  72. data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +626 -0
  73. data/lib/decidim/forms/user_answers_serializer.rb +29 -0
  74. data/lib/decidim/forms/version.rb +10 -0
  75. metadata +165 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ddc9adf1fa3236f89e1a63a9f08ec53daa5c9dca46be2de0ed5855334d9dc81a
4
+ data.tar.gz: 86eb4e54e761e29f03ba5d859bc7303bbaf9770c9f12bb6dda991bfd986e537a
5
+ SHA512:
6
+ metadata.gz: 19cd51ee2b4d5db3bf9857551e840e9a1f5fbfcc839f89e9c6fbbab3af2342d314f7c11baa2da05b8429e58d1cc2e1fb4bcb9ec4ba8e4c7a773a7918064ee1d7
7
+ data.tar.gz: c8da685c765fff9c6d7757a25efc573b3bed4bdb2d441f2c63cd7648224f5560729e6e42a2943740b7cd374689e851a2c0a6b5a613b660c6c9d621ba13c51d7c
data/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # Decidim::Forms
2
+
3
+ This gem encapsulates the logic to create and manage forms, so it can be reused in other modules, like surveys and meetings.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your module's gemspec:
8
+
9
+ ```ruby
10
+ s.add_dependency "decidim-forms", Decidim::YourModule.version
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```bash
16
+ bundle
17
+ ```
18
+
19
+ ## Contributing
20
+
21
+ See [Decidim](https://github.com/decidim/decidim).
22
+
23
+ ## License
24
+
25
+ See [Decidim](https://github.com/decidim/decidim).
26
+
27
+ ## Seeds
28
+
29
+ Since questionnaires cannot exist without a real model we are not including specific seeds for this engine.
30
+
31
+ Other engines are free to include questionnaires on their seeds like this:
32
+
33
+ ```ruby
34
+ Decidim::Forms::Questionnaire.new(
35
+ title: Decidim::Faker::Localized.paragraph,
36
+ description: Decidim::Faker::Localized.wrapped("<p>", "</p>") do
37
+ Decidim::Faker::Localized.paragraph(3)
38
+ end,
39
+ tos: Decidim::Faker::Localized.wrapped("<p>", "</p>") do
40
+ Decidim::Faker::Localized.paragraph(2)
41
+ end,
42
+ )
43
+
44
+ Decidim::Surveys::Survey.create!(component: component, questionnaire: questionnaire)
45
+
46
+ %w(short_answer long_answer).each do |text_question_type|
47
+ Decidim::Forms::Question.create!(
48
+ questionnaire: questionnaire,
49
+ body: Decidim::Faker::Localized.paragraph,
50
+ question_type: text_question_type
51
+ )
52
+ end
53
+
54
+ %w(single_option multiple_option).each do |multiple_choice_question_type|
55
+ question = Decidim::Forms::Question.create!(
56
+ questionnaire: questionnaire,
57
+ body: Decidim::Faker::Localized.paragraph,
58
+ question_type: multiple_choice_question_type
59
+ )
60
+
61
+ 3.times do
62
+ question.answer_options.create!(body: Decidim::Faker::Localized.sentence)
63
+ end
64
+ end
65
+ ```
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/dev/common_rake"
@@ -0,0 +1 @@
1
+ //= link decidim/forms/admin/forms.js
@@ -0,0 +1 @@
1
+ // = link decidim/forms/forms.js
@@ -0,0 +1,19 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
+ <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
4
+ viewBox="0 0 36 36" style="enable-background:new 0 0 36 36;" xml:space="preserve">
5
+ <path d="M27,28H9c-0.6,0-1-0.4-1-1V11c0-0.6,0.4-1,1-1h3.1c0.6,0,1,0.4,1,1v1.9h9.7V11c0-0.6,0.4-1,1-1H27c0.6,0,1,0.4,1,1v16
6
+ C28,27.6,27.6,28,27,28z M10,26h16V12h-1.2v1.9c0,0.6-0.4,1-1,1H12.1c-0.6,0-1-0.4-1-1V12H10V26z"/>
7
+ <g>
8
+ <g>
9
+ <path d="M21,11h-6c-0.6,0-1-0.4-1-1s0.4-1,1-1h6c0.6,0,1,0.4,1,1S21.6,11,21,11z"/>
10
+ </g>
11
+ <g>
12
+ <path d="M18.7,11h-1.5c-0.6,0-1-0.4-1-1V8c0-0.6,0.4-1,1-1h1.5c0.6,0,1,0.4,1,1v2C19.7,10.5,19.3,11,18.7,11z"/>
13
+ </g>
14
+ </g>
15
+ <g>
16
+ <path d="M18,36.1c-9.9,0-18-8.1-18-18s8.1-18,18-18s18,8.1,18,18S27.9,36.1,18,36.1z M18,2.1c-8.8,0-16,7.2-16,16s7.2,16,16,16
17
+ s16-7.2,16-16S26.8,2.1,18,2.1z"/>
18
+ </g>
19
+ </svg>
@@ -0,0 +1,25 @@
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);
@@ -0,0 +1,23 @@
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);
@@ -0,0 +1,188 @@
1
+ // = require ./auto_buttons_by_min_items.component
2
+ // = require ./auto_select_options_by_total_items.component
3
+
4
+ ((exports) => {
5
+ const { AutoLabelByPositionComponent, AutoButtonsByPositionComponent, AutoButtonsByMinItemsComponent, AutoSelectOptionsByTotalItemsComponent, createFieldDependentInputs, createDynamicFields, createSortList } = exports.DecidimAdmin;
6
+ const { createQuillEditor } = exports.Decidim;
7
+
8
+ const wrapperSelector = ".questionnaire-questions";
9
+ const fieldSelector = ".questionnaire-question";
10
+ const questionTypeSelector = "select[name$=\\[question_type\\]]";
11
+ const answerOptionFieldSelector = ".questionnaire-question-answer-option";
12
+ const answerOptionsWrapperSelector = ".questionnaire-question-answer-options";
13
+ const answerOptionRemoveFieldButtonSelector = ".remove-answer-option";
14
+ const maxChoicesWrapperSelector = ".questionnaire-question-max-choices";
15
+
16
+ const autoLabelByPosition = new AutoLabelByPositionComponent({
17
+ listSelector: ".questionnaire-question:not(.hidden)",
18
+ labelSelector: ".card-title span:first",
19
+ onPositionComputed: (el, idx) => {
20
+ $(el).find("input[name$=\\[position\\]]").val(idx);
21
+ }
22
+ });
23
+
24
+ const autoButtonsByPosition = new AutoButtonsByPositionComponent({
25
+ listSelector: ".questionnaire-question:not(.hidden)",
26
+ hideOnFirstSelector: ".move-up-question",
27
+ hideOnLastSelector: ".move-down-question"
28
+ });
29
+
30
+ const createAutoMaxChoicesByNumberOfAnswerOptions = (fieldId) => {
31
+ return new AutoSelectOptionsByTotalItemsComponent({
32
+ wrapperSelector: fieldSelector,
33
+ selectSelector: `${maxChoicesWrapperSelector} select`,
34
+ listSelector: `#${fieldId} ${answerOptionsWrapperSelector} .questionnaire-question-answer-option:not(.hidden)`
35
+ })
36
+ };
37
+
38
+ const createAutoButtonsByMinItemsForAnswerOptions = (fieldId) => {
39
+ return new AutoButtonsByMinItemsComponent({
40
+ wrapperSelector: fieldSelector,
41
+ listSelector: `#${fieldId} ${answerOptionsWrapperSelector} .questionnaire-question-answer-option:not(.hidden)`,
42
+ minItems: 2,
43
+ hideOnMinItemsOrLessSelector: answerOptionRemoveFieldButtonSelector
44
+ })
45
+ };
46
+
47
+ const createSortableList = () => {
48
+ createSortList(".questionnaire-questions-list:not(.published)", {
49
+ handle: ".question-divider",
50
+ placeholder: '<div style="border-style: dashed; border-color: #000"></div>',
51
+ forcePlaceholderSize: true,
52
+ onSortUpdate: () => { autoLabelByPosition.run() }
53
+ });
54
+ };
55
+
56
+ const createDynamicFieldsForAnswerOptions = (fieldId) => {
57
+ const autoButtons = createAutoButtonsByMinItemsForAnswerOptions(fieldId);
58
+ const autoSelectOptions = createAutoMaxChoicesByNumberOfAnswerOptions(fieldId);
59
+
60
+ return createDynamicFields({
61
+ placeholderId: "questionnaire-question-answer-option-id",
62
+ wrapperSelector: `#${fieldId} ${answerOptionsWrapperSelector}`,
63
+ containerSelector: ".questionnaire-question-answer-options-list",
64
+ fieldSelector: answerOptionFieldSelector,
65
+ addFieldButtonSelector: ".add-answer-option",
66
+ removeFieldButtonSelector: answerOptionRemoveFieldButtonSelector,
67
+ onAddField: () => {
68
+ autoButtons.run();
69
+ autoSelectOptions.run();
70
+ },
71
+ onRemoveField: () => {
72
+ autoButtons.run();
73
+ autoSelectOptions.run();
74
+ }
75
+ });
76
+ };
77
+
78
+ const dynamicFieldsForAnswerOptions = {};
79
+
80
+ const isMultipleChoiceOption = ($selectField) => {
81
+ const value = $selectField.val();
82
+
83
+ return value === "single_option" || value === "multiple_option" || value === "sorting"
84
+ }
85
+
86
+ const setupInitialQuestionAttributes = ($target) => {
87
+ const fieldId = $target.attr("id");
88
+ const $fieldQuestionTypeSelect = $target.find(questionTypeSelector);
89
+
90
+ createFieldDependentInputs({
91
+ controllerField: $fieldQuestionTypeSelect,
92
+ wrapperSelector: fieldSelector,
93
+ dependentFieldsSelector: answerOptionsWrapperSelector,
94
+ dependentInputSelector: `${answerOptionFieldSelector} input`,
95
+ enablingCondition: ($field) => {
96
+ return isMultipleChoiceOption($field);
97
+ }
98
+ });
99
+
100
+ createFieldDependentInputs({
101
+ controllerField: $fieldQuestionTypeSelect,
102
+ wrapperSelector: fieldSelector,
103
+ dependentFieldsSelector: maxChoicesWrapperSelector,
104
+ dependentInputSelector: "select",
105
+ enablingCondition: ($field) => {
106
+ return $field.val() === "multiple_option"
107
+ }
108
+ });
109
+
110
+ dynamicFieldsForAnswerOptions[fieldId] = createDynamicFieldsForAnswerOptions(fieldId);
111
+
112
+ const dynamicFields = dynamicFieldsForAnswerOptions[fieldId];
113
+
114
+ const onQuestionTypeChange = () => {
115
+ if (isMultipleChoiceOption($fieldQuestionTypeSelect)) {
116
+ const nOptions = $fieldQuestionTypeSelect.parents(fieldSelector).find(answerOptionFieldSelector).length;
117
+
118
+ if (nOptions === 0) {
119
+ dynamicFields._addField();
120
+ dynamicFields._addField();
121
+ }
122
+ }
123
+ };
124
+
125
+ $fieldQuestionTypeSelect.on("change", onQuestionTypeChange);
126
+
127
+ onQuestionTypeChange();
128
+ }
129
+
130
+ const hideDeletedQuestion = ($target) => {
131
+ const inputDeleted = $target.find("input[name$=\\[deleted\\]]").val();
132
+
133
+ if (inputDeleted === "true") {
134
+ $target.addClass("hidden");
135
+ $target.hide();
136
+ }
137
+ }
138
+
139
+ createDynamicFields({
140
+ placeholderId: "questionnaire-question-id",
141
+ wrapperSelector: wrapperSelector,
142
+ containerSelector: ".questionnaire-questions-list",
143
+ fieldSelector: fieldSelector,
144
+ addFieldButtonSelector: ".add-question",
145
+ removeFieldButtonSelector: ".remove-question",
146
+ moveUpFieldButtonSelector: ".move-up-question",
147
+ moveDownFieldButtonSelector: ".move-down-question",
148
+ onAddField: ($field) => {
149
+ setupInitialQuestionAttributes($field);
150
+ createSortableList();
151
+
152
+ $field.find(".editor-container").each((idx, el) => {
153
+ createQuillEditor(el);
154
+ });
155
+
156
+ autoLabelByPosition.run();
157
+ autoButtonsByPosition.run();
158
+ },
159
+ onRemoveField: ($field) => {
160
+ autoLabelByPosition.run();
161
+ autoButtonsByPosition.run();
162
+
163
+ $field.find(answerOptionRemoveFieldButtonSelector).each((idx, el) => {
164
+ dynamicFieldsForAnswerOptions[$field.attr("id")]._removeField(el);
165
+ });
166
+ },
167
+ onMoveUpField: () => {
168
+ autoLabelByPosition.run();
169
+ autoButtonsByPosition.run();
170
+ },
171
+ onMoveDownField: () => {
172
+ autoLabelByPosition.run();
173
+ autoButtonsByPosition.run();
174
+ }
175
+ });
176
+
177
+ createSortableList();
178
+
179
+ $(fieldSelector).each((idx, el) => {
180
+ const $target = $(el);
181
+
182
+ hideDeletedQuestion($target);
183
+ setupInitialQuestionAttributes($target);
184
+ });
185
+
186
+ autoLabelByPosition.run();
187
+ autoButtonsByPosition.run();
188
+ })(window);
@@ -0,0 +1,65 @@
1
+ ((exports) => {
2
+ class AutosortableCheckboxesComponent {
3
+ constructor(options = {}) {
4
+ this.wrapperField = options.wrapperField;
5
+ this._bindEvent();
6
+ this._run();
7
+ }
8
+
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
+ }
22
+
23
+ $parentLabel.addClass("sorted");
24
+ $parentLabel.addClass("last-sorted");
25
+ } else {
26
+ const $lastUnsorted = this.wrapperField.find("label:not(.sorted)").last();
27
+
28
+ if ($lastUnsorted.length > 0) {
29
+ $parentLabel.insertBefore($lastUnsorted);
30
+ } else {
31
+ $parentLabel.insertAfter(this.wrapperField.find("label:last-child"));
32
+ }
33
+
34
+ $parentLabel.removeClass("sorted");
35
+ }
36
+ });
37
+
38
+ $(this.wrapperField).find("label").each((idx, el) => {
39
+ const $positionSelector = $(el).find(".position");
40
+ const $positionField = $(el).find("input[name$=\\[position\\]]");
41
+
42
+ if ($(el).hasClass("sorted")) {
43
+ $positionField.val(idx);
44
+ $positionField.prop("disabled", false);
45
+ $positionSelector.html(`${idx + 1}. `);
46
+ } else {
47
+ $positionField.val("");
48
+ $positionField.prop("disabled", true);
49
+ $positionSelector.html("");
50
+ }
51
+ });
52
+ }
53
+
54
+ _bindEvent() {
55
+ $(this.wrapperField).find("input[type=checkbox]").on("change", () => {
56
+ this._run();
57
+ });
58
+ }
59
+ }
60
+
61
+ exports.Decidim = exports.Decidim || {};
62
+ exports.Decidim.createAutosortableCheckboxes = (options) => {
63
+ return new AutosortableCheckboxesComponent(options);
64
+ };
65
+ })(window);
@@ -0,0 +1,20 @@
1
+ // = require ./option_attached_inputs.component
2
+ // = require ./autosortable_checkboxes.component
3
+
4
+ ((exports) => {
5
+ const { createOptionAttachedInputs, createAutosortableCheckboxes } = exports.Decidim;
6
+
7
+ $(".radio-button-collection, .check-box-collection").each((idx, el) => {
8
+ createOptionAttachedInputs({
9
+ wrapperField: $(el),
10
+ controllerFieldSelector: "input[type=radio], input[type=checkbox]",
11
+ dependentInputSelector: "input[type=text], input[type=hidden]"
12
+ });
13
+ });
14
+
15
+ $(".sortable-check-box-collection").each((idx, el) => {
16
+ createAutosortableCheckboxes({
17
+ wrapperField: $(el)
18
+ })
19
+ });
20
+ })(window);
@@ -0,0 +1,32 @@
1
+ ((exports) => {
2
+ class OptionAttachedInputsComponent {
3
+ constructor(options = {}) {
4
+ this.wrapperField = options.wrapperField;
5
+ this.controllerFieldSelector = options.controllerFieldSelector;
6
+ this.dependentInputSelector = options.dependentInputSelector;
7
+ this.controllerSelector = this.wrapperField.find(this.controllerFieldSelector);
8
+ this._bindEvent();
9
+ this._run();
10
+ }
11
+
12
+ _run() {
13
+ this.controllerSelector.each((idx, el) => {
14
+ const $field = $(el);
15
+ const enabled = $field.is(":checked");
16
+
17
+ $field.parents("label").find(this.dependentInputSelector).prop("disabled", !enabled);
18
+ });
19
+ }
20
+
21
+ _bindEvent() {
22
+ this.controllerSelector.on("change", () => {
23
+ this._run();
24
+ });
25
+ }
26
+ }
27
+
28
+ exports.Decidim = exports.Decidim || {};
29
+ exports.Decidim.createOptionAttachedInputs = (options) => {
30
+ return new OptionAttachedInputsComponent(options);
31
+ };
32
+ })(window);