decidim-forms 0.24.3 → 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 (66) 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/db/migrate/20170515144119_create_decidim_forms_answers.rb +1 -2
  46. data/db/migrate/20210616153042_set_position_to_question_matrix_rows.rb +11 -0
  47. data/lib/decidim/forms/admin_engine.rb +0 -4
  48. data/lib/decidim/forms/engine.rb +2 -4
  49. data/lib/decidim/forms/test/factories.rb +39 -2
  50. data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +2 -0
  51. data/lib/decidim/forms/user_answers_serializer.rb +3 -0
  52. data/lib/decidim/forms/version.rb +1 -1
  53. metadata +35 -32
  54. data/app/assets/config/admin/decidim_forms_manifest.css +0 -3
  55. data/app/assets/config/admin/decidim_forms_manifest.js +0 -2
  56. data/app/assets/config/decidim_forms_manifest.css +0 -4
  57. data/app/assets/config/decidim_forms_manifest.js +0 -1
  58. data/app/assets/javascripts/decidim/forms/admin/auto_buttons_by_min_items.component.js.es6 +0 -25
  59. data/app/assets/javascripts/decidim/forms/admin/auto_select_options_by_total_items.component.js.es6 +0 -23
  60. data/app/assets/javascripts/decidim/forms/admin/auto_select_options_from_url.component.js.es6 +0 -40
  61. data/app/assets/javascripts/decidim/forms/admin/live_text_update.component.js.es6 +0 -52
  62. data/app/assets/javascripts/decidim/forms/autosortable_checkboxes.component.js.es6 +0 -85
  63. data/app/assets/javascripts/decidim/forms/display_conditions.component.js.es6 +0 -203
  64. data/app/assets/javascripts/decidim/forms/max_choices_alert.component.js.es6 +0 -44
  65. data/app/assets/javascripts/decidim/forms/option_attached_inputs.component.js.es6 +0 -32
  66. data/config/locales/ja-JP.yml +0 -170
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fb0b91d5017ae65bea07ce4f4d7f8ce52d6100f25d67375c3f8b298e7814234f
4
- data.tar.gz: 2e8b006412c4cb58b06062f8d6747c760a29167ba866a26cc51647a21ff2b4f0
3
+ metadata.gz: 6d6a89d9130f70f34752048e73c5326d2da80e71f44e3da9c70115ec4cb9bbc0
4
+ data.tar.gz: be2fcaae153df09c162d1b9878c1163042f4802968bd4626ce1a279a67830b20
5
5
  SHA512:
6
- metadata.gz: 685c2eca4d5c9ff771b1bb699c08de24369705ccc7404b30a3e34ebf00536277963cfa1636e1757b3eb4365d14d4259e00d20b250f4a750392406b7d5e0b24d0
7
- data.tar.gz: a5ba675fb9bb0e912435e2926d336f6ef05cee3d4db6d8d66eb29b6f6899ef8d0534997549c4aa8d0d3914b51942038604861cbf09d74c0b7a4be4cf345ff774
6
+ metadata.gz: 2f58f802c1bb233ef62fd86cb08fd382c4e67f95417759371f0685ae5ad92bdf00576d3b57854e3da73665822ea13918ef522aa980af1ea8fc918717df66b4a2
7
+ data.tar.gz: c6b772ae8123a55dc7f36ea3297984a91f7f81ba19fcb1fce27d1378e007c279a3edeec7970f984ebac720ae637f81a542ead1fb5bcfdbab4e8392fc5da4de11
@@ -3,7 +3,7 @@
3
3
  <a></a>
4
4
  <% else %>
5
5
  <%= link_to(
6
- icon("caret-left", class: "icon--small", role: "img") + " " + t("decidim.forms.step_navigation.show.back"),
6
+ icon("caret-left", class: "icon--small", role: "img", "aria-hidden": true) + " " + t("decidim.forms.step_navigation.show.back"),
7
7
  "#",
8
8
  class: "hollow secondary",
9
9
  data: {
@@ -78,9 +78,10 @@ module Decidim
78
78
  update_nested_model(form_display_condition, display_condition_attributes, question.display_conditions)
79
79
  end
80
80
 
81
- form_question.matrix_rows.each do |form_matrix_row|
81
+ form_question.matrix_rows_by_position.each_with_index do |form_matrix_row, idx|
82
82
  matrix_row_attributes = {
83
- body: form_matrix_row.body
83
+ body: form_matrix_row.body,
84
+ position: form_matrix_row.position || idx
84
85
  }
85
86
 
86
87
  update_nested_model(form_matrix_row, matrix_row_attributes, question.matrix_rows)
@@ -42,6 +42,20 @@ module Decidim
42
42
  question_type == Decidim::Forms::Question::SEPARATOR_TYPE
43
43
  end
44
44
 
45
+ def matrix_rows_by_position
46
+ matrix_rows.sort do |a, b|
47
+ if a.position && b.position
48
+ a.position <=> b.position
49
+ elsif a.position
50
+ -1
51
+ elsif b.position
52
+ 1
53
+ else
54
+ 0
55
+ end
56
+ end
57
+ end
58
+
45
59
  private
46
60
 
47
61
  def matrix?
@@ -7,12 +7,12 @@ module Decidim
7
7
  class QuestionMatrixRowForm < Decidim::Form
8
8
  include TranslatableAttributes
9
9
 
10
- attribute :position, Integer, default: 0
10
+ attribute :position, Integer
11
11
  attribute :deleted, Boolean, default: false
12
12
 
13
13
  translatable_attribute :body, String
14
14
 
15
- validates :position, numericality: { greater_than_or_equal_to: 0 }
15
+ validates :position, numericality: { greater_than_or_equal_to: 0 }, if: -> { position.present? }
16
16
  validates :body, translatable_presence: true, unless: :deleted
17
17
 
18
18
  def to_param
@@ -8,6 +8,7 @@ module Decidim
8
8
  # important not to use the same word here to avoid querying all the entries, resulting in a high performance penalty
9
9
  attribute :responses, Array[AnswerForm]
10
10
  attribute :user_group_id, Integer
11
+ attribute :public_participation, Boolean, default: false
11
12
 
12
13
  attribute :tos_agreement, Boolean
13
14
 
@@ -10,6 +10,7 @@ module Decidim
10
10
 
11
11
  permited_models.include?(model_name)
12
12
  end
13
+ alias show_public_participation? show_represent_user_group?
13
14
 
14
15
  def permited_models
15
16
  %(meeting)
@@ -3,7 +3,7 @@
3
3
  module Decidim
4
4
  module Forms
5
5
  class ExportQuestionnaireAnswersJob < ApplicationJob
6
- queue_as :default
6
+ queue_as :exports
7
7
 
8
8
  def perform(user, title, answers)
9
9
  return if user&.email.blank?
@@ -87,6 +87,10 @@ module Decidim
87
87
  def has_attachments?
88
88
  question_type.to_s == "files"
89
89
  end
90
+
91
+ def answers_count
92
+ questionnaire.answers.where(question: self).count
93
+ end
90
94
  end
91
95
  end
92
96
  end
@@ -10,6 +10,9 @@ module Decidim
10
10
  belongs_to :question, class_name: "Question", foreign_key: "decidim_question_id"
11
11
 
12
12
  delegate :answer_options, :mandatory, :max_choices, to: :question
13
+
14
+ scope :by_position, -> { order(:position) }
15
+ default_scope { by_position }
13
16
  end
14
17
  end
15
18
  end
@@ -0,0 +1,4 @@
1
+ import "src/decidim/forms/forms"
2
+
3
+ // Images
4
+ require.context("../images", true)
@@ -0,0 +1,4 @@
1
+ import "src/decidim/forms/admin/collapsible_questions"
2
+
3
+ import createEditableForm from "../src/decidim/forms/admin/forms"
4
+ window.Decidim.createEditableForm = createEditableForm
@@ -0,0 +1 @@
1
+ import "entrypoints/decidim_questionnaire_answers_pdf.scss"
@@ -0,0 +1 @@
1
+ @import "stylesheets/decidim/forms/questionnaire-answers-pdf.scss";
@@ -0,0 +1,20 @@
1
+ export default class AutoButtonsByMinItemsComponent {
2
+ constructor(options = {}) {
3
+ this.listSelector = options.listSelector;
4
+ this.minItems = options.minItems;
5
+ this.hideOnMinItemsOrLessSelector = options.hideOnMinItemsOrLessSelector;
6
+
7
+ this.run();
8
+ }
9
+
10
+ run() {
11
+ const $list = $(this.listSelector);
12
+ const $items = $list.find(this.hideOnMinItemsOrLessSelector);
13
+
14
+ if ($list.length <= this.minItems) {
15
+ $items.hide();
16
+ } else {
17
+ $items.show();
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,18 @@
1
+ export default class AutoSelectOptionsByTotalItemsComponent {
2
+ constructor(options = {}) {
3
+ this.wrapperSelector = options.wrapperSelector;
4
+ this.selectSelector = options.selectSelector;
5
+ this.listSelector = options.listSelector;
6
+ }
7
+
8
+ run() {
9
+ const $list = $(this.listSelector);
10
+ const $selectField = $list.parents(this.wrapperSelector).find(this.selectSelector);
11
+
12
+ $selectField.find("option").slice(1).remove();
13
+
14
+ for (let idx = 2; idx <= $list.length; idx += 1) {
15
+ $(`<option value="${idx}">${idx}</option>`).appendTo($selectField);
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,35 @@
1
+ export default class AutoSelectOptionsFromUrl {
2
+ constructor(options = {}) {
3
+ this.$source = options.source;
4
+ this.$select = options.select;
5
+ this.sourceToParams = options.sourceToParams;
6
+ this.run();
7
+ }
8
+
9
+ run() {
10
+ this.$source.on("change", this._onSourceChange.bind(this));
11
+ this._onSourceChange();
12
+ }
13
+
14
+ _onSourceChange() {
15
+ const select = this.$select;
16
+ const params = this.sourceToParams(this.$source);
17
+ const url = this.$source.data("url");
18
+
19
+ $.getJSON(url, params, function (data) {
20
+ select.find("option:not([value=''])").remove();
21
+ const selectedValue = select.data("selected");
22
+
23
+ data.forEach((option) => {
24
+ let optionElement = $(`<option value="${option.id}">${option.body}</option>`).appendTo(select);
25
+ if (option.id === selectedValue) {
26
+ optionElement.attr("selected", true);
27
+ }
28
+ });
29
+
30
+ if (selectedValue) {
31
+ select.val(selectedValue);
32
+ }
33
+ });
34
+ }
35
+ }
@@ -1,14 +1,18 @@
1
1
  /* eslint-disable max-lines */
2
-
3
- // = require ./auto_buttons_by_min_items.component
4
- // = require ./auto_select_options_by_total_items.component
5
- // = require ./auto_select_options_from_url.component
6
- // = require ./live_text_update.component
7
-
8
- ((exports) => {
9
- const { AutoLabelByPositionComponent, AutoButtonsByPositionComponent, AutoButtonsByMinItemsComponent, AutoSelectOptionsByTotalItemsComponent, AutoSelectOptionsFromUrl, createLiveTextUpdateComponent, createFieldDependentInputs, createDynamicFields, createSortList } = exports.DecidimAdmin;
10
- const { createQuillEditor } = exports.Decidim;
11
-
2
+ /* eslint-disable require-jsdoc */
3
+
4
+ import AutoButtonsByMinItemsComponent from "src/decidim/forms/admin/auto_buttons_by_min_items.component"
5
+ import AutoSelectOptionsByTotalItemsComponent from "src/decidim/forms/admin/auto_select_options_by_total_items.component"
6
+ import AutoSelectOptionsFromUrl from "src/decidim/forms/admin/auto_select_options_from_url.component"
7
+ import createLiveTextUpdateComponent from "src/decidim/forms/admin/live_text_update.component"
8
+ import AutoButtonsByPositionComponent from "src/decidim/admin/auto_buttons_by_position.component"
9
+ import AutoLabelByPositionComponent from "src/decidim/admin/auto_label_by_position.component"
10
+ import createSortList from "src/decidim/admin/sort_list.component"
11
+ import createDynamicFields from "src/decidim/admin/dynamic_fields.component"
12
+ import createFieldDependentInputs from "src/decidim/admin/field_dependent_inputs.component"
13
+ import createQuillEditor from "src/decidim/editor"
14
+
15
+ export default function createEditableForm() {
12
16
  const wrapperSelector = ".questionnaire-questions";
13
17
  const fieldSelector = ".questionnaire-question";
14
18
  const questionTypeSelector = "select[name$=\\[question_type\\]]";
@@ -59,7 +63,7 @@
59
63
  listSelector: ".questionnaire-question:not(.hidden)",
60
64
  labelSelector: ".card-title span:first",
61
65
  onPositionComputed: (el, idx) => {
62
- $(el).find("input[name$=\\[position\\]]").val(idx);
66
+ $(el).find("input[name$=\\[position\\]]:not([name*=\\[matrix_rows\\]])").val(idx);
63
67
 
64
68
  autoButtonsByPosition.run();
65
69
 
@@ -429,4 +433,4 @@
429
433
 
430
434
  autoLabelByPosition.run();
431
435
  autoButtonsByPosition.run();
432
- })(window);
436
+ }
@@ -0,0 +1,49 @@
1
+ /* eslint-disable require-jsdoc */
2
+
3
+ /**
4
+ * This component allows for an element's text value to be updated with the value
5
+ * of an input whenever this input's value is changed.
6
+ *
7
+ * @param {object} options
8
+ *
9
+ * Available options:
10
+ * {string} `inputSelector`: The query selector to locate the input element
11
+ * {string} `targetSelector`: The query selector to locate the target element
12
+ * {number} `maxLength`: The maximum characters from the input value to be displayed in the target
13
+ * {string} `omission`: The string used to shorten the value to the given maxLength (e.g. "...")
14
+ * {string} `placeholder`: The string to be displayed in the target element when the input has no value
15
+ */
16
+ class LiveTextUpdateComponent {
17
+ constructor(options = {}) {
18
+ this.inputSelector = options.inputSelector;
19
+ this.targetSelector = options.targetSelector;
20
+ this.maxLength = options.maxLength;
21
+ this.omission = options.omission;
22
+ this.placeholder = options.placeholder;
23
+ this._bindEvent();
24
+ this._run();
25
+ }
26
+
27
+ _run() {
28
+ const $input = $(this.inputSelector);
29
+ const $target = $(this.targetSelector);
30
+
31
+ let text = $input.val() || this.placeholder;
32
+
33
+ // truncate string
34
+ if (text.length > this.maxLength) {
35
+ text = text.substring(0, this.maxLength - this.omission.length) + this.omission;
36
+ }
37
+
38
+ $target.text(text);
39
+ }
40
+
41
+ _bindEvent() {
42
+ const $input = $(this.inputSelector);
43
+ $input.on("change", this._run.bind(this));
44
+ }
45
+ }
46
+
47
+ export default function createLiveTextUpdateComponent(options) {
48
+ return new LiveTextUpdateComponent(options);
49
+ }
@@ -0,0 +1,83 @@
1
+ /* eslint-disable require-jsdoc */
2
+ /* eslint-disable no-ternary */
3
+
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
+ export default function createAutosortableCheckboxes(options) {
82
+ return new AutosortableCheckboxesComponent(options);
83
+ }
@@ -0,0 +1,200 @@
1
+ /* eslint-disable no-ternary, no-plusplus, require-jsdoc */
2
+
3
+ class DisplayCondition {
4
+ constructor(options = {}) {
5
+ this.wrapperField = options.wrapperField;
6
+ this.type = options.type;
7
+ this.conditionQuestion = options.conditionQuestion;
8
+ this.answerOption = options.answerOption;
9
+ this.mandatory = options.mandatory;
10
+ this.value = options.value;
11
+ this.onFulfilled = options.onFulfilled;
12
+ this.bindEvent();
13
+ }
14
+
15
+ bindEvent() {
16
+ this.checkCondition();
17
+ this.getInputsToListen().on("change", this.checkCondition.bind(this));
18
+ }
19
+
20
+ getInputValue() {
21
+ const $conditionWrapperField = $(`.question[data-question-id='${this.conditionQuestion}']`);
22
+ const $textInput = $conditionWrapperField.find("textarea, input[type='text']:not([name$=\\[custom_body\\]])");
23
+
24
+ if ($textInput.length) {
25
+ return $textInput.val();
26
+ }
27
+
28
+ let multipleInput = [];
29
+
30
+ $conditionWrapperField.find(".radio-button-collection, .check-box-collection").find(".collection-input").each((idx, el) => {
31
+ const $input = $(el).find("input[name$=\\[body\\]]");
32
+ const checked = $input.is(":checked");
33
+
34
+ if (checked) {
35
+ const text = $(el).find("input[name$=\\[custom_body\\]]").val();
36
+ const value = $input.val();
37
+ const id = $(el).find("input[name$=\\[answer_option_id\\]]").val();
38
+
39
+ multipleInput.push({ id, value, text });
40
+ }
41
+ });
42
+
43
+ return multipleInput;
44
+ }
45
+
46
+ getInputsToListen() {
47
+ const $conditionWrapperField = $(`.question[data-question-id='${this.conditionQuestion}']`);
48
+ const $textInput = $conditionWrapperField.find("textarea, input[type='text']:not([name$=\\[custom_body\\]])");
49
+
50
+ if ($textInput.length) {
51
+ return $textInput;
52
+ }
53
+
54
+ return $conditionWrapperField.find(".collection-input").find("input:not([type='hidden'])");
55
+ }
56
+
57
+ checkAnsweredCondition(value) {
58
+ if (typeof (value) !== "object") {
59
+ return Boolean(value);
60
+ }
61
+
62
+ return Boolean(value.some((it) => it.value));
63
+ }
64
+
65
+ checkNotAnsweredCondition(value) {
66
+ return !this.checkAnsweredCondition(value);
67
+ }
68
+
69
+ checkEqualCondition(value) {
70
+ if (value.length) {
71
+ return value.some((it) => it.id === this.answerOption.toString());
72
+ }
73
+ return false;
74
+ }
75
+
76
+ checkNotEqualCondition(value) {
77
+ if (value.length) {
78
+ return value.every((it) => it.id !== this.answerOption.toString());
79
+ }
80
+ return false;
81
+ }
82
+
83
+ checkMatchCondition(value) {
84
+ let regexp = new RegExp(this.value, "i");
85
+
86
+ if (typeof (value) !== "object") {
87
+ return Boolean(value.match(regexp));
88
+ }
89
+
90
+ return value.some(function (it) {
91
+ return it.text
92
+ ? it.text.match(regexp)
93
+ : it.value.match(regexp)
94
+ });
95
+ }
96
+
97
+ checkCondition() {
98
+ const value = this.getInputValue();
99
+ let fulfilled = false;
100
+
101
+ switch (this.type) {
102
+ case "answered":
103
+ fulfilled = this.checkAnsweredCondition(value);
104
+ break;
105
+ case "not_answered":
106
+ fulfilled = this.checkNotAnsweredCondition(value);
107
+ break;
108
+ case "equal":
109
+ fulfilled = this.checkEqualCondition(value);
110
+ break;
111
+ case "not_equal":
112
+ fulfilled = this.checkNotEqualCondition(value);
113
+ break;
114
+ case "match":
115
+ fulfilled = this.checkMatchCondition(value);
116
+ break;
117
+ default:
118
+ fulfilled = false;
119
+ break;
120
+ }
121
+
122
+ this.onFulfilled(fulfilled);
123
+ }
124
+ }
125
+
126
+ class DisplayConditionsComponent {
127
+ constructor(options = {}) {
128
+ this.wrapperField = options.wrapperField;
129
+ this.conditions = {};
130
+ this.showCount = 0;
131
+ this.initializeConditions();
132
+ }
133
+
134
+ initializeConditions() {
135
+ const $conditionElements = this.wrapperField.find(".display-condition");
136
+
137
+ $conditionElements.each((idx, el) => {
138
+ const $condition = $(el);
139
+ const id = $condition.data("id");
140
+ this.conditions[id] = {};
141
+
142
+ this.conditions[id] = new DisplayCondition({
143
+ wrapperField: this.wrapperField,
144
+ type: $condition.data("type"),
145
+ conditionQuestion: $condition.data("condition"),
146
+ answerOption: $condition.data("option"),
147
+ mandatory: $condition.data("mandatory"),
148
+ value: $condition.data("value"),
149
+ onFulfilled: (fulfilled) => {
150
+ this.onFulfilled(id, fulfilled);
151
+ }
152
+ });
153
+ });
154
+ }
155
+
156
+ mustShow() {
157
+ const conditions = Object.values(this.conditions);
158
+ const mandatoryConditions = conditions.filter((condition) => condition.mandatory);
159
+ const nonMandatoryConditions = conditions.filter((condition) => !condition.mandatory);
160
+
161
+ if (mandatoryConditions.length) {
162
+ return mandatoryConditions.every((condition) => condition.fulfilled);
163
+ }
164
+
165
+ return nonMandatoryConditions.some((condition) => condition.fulfilled);
166
+
167
+ }
168
+
169
+ onFulfilled(id, fulfilled) {
170
+ this.conditions[id].fulfilled = fulfilled;
171
+
172
+ if (this.mustShow()) {
173
+ this.showQuestion();
174
+ }
175
+ else {
176
+ this.hideQuestion();
177
+ }
178
+ }
179
+
180
+ showQuestion() {
181
+ this.wrapperField.fadeIn();
182
+ this.wrapperField.find("input, textarea").prop("disabled", null);
183
+ this.showCount++;
184
+ }
185
+
186
+ hideQuestion() {
187
+ if (this.showCount) {
188
+ this.wrapperField.fadeOut();
189
+ }
190
+ else {
191
+ this.wrapperField.hide();
192
+ }
193
+
194
+ this.wrapperField.find("input, textarea").prop("disabled", "disabled");
195
+ }
196
+ }
197
+
198
+ export default function createDisplayConditions(options) {
199
+ return new DisplayConditionsComponent(options);
200
+ }