decidim-forms 0.30.2 → 0.31.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.
- checksums.yaml +4 -4
- data/README.md +10 -10
- data/app/cells/decidim/forms/matrix_readonly/show.erb +1 -1
- data/app/cells/decidim/forms/matrix_readonly_cell.rb +3 -3
- data/app/cells/decidim/forms/question_readonly/show.erb +5 -5
- data/app/cells/decidim/forms/question_readonly/title_and_description.erb +3 -3
- data/app/cells/decidim/forms/response_readonly_cell.rb +9 -0
- data/app/cells/decidim/forms/step_navigation/show.erb +3 -3
- data/app/cells/decidim/forms/step_navigation_cell.rb +3 -3
- data/app/commands/decidim/forms/admin/update_questions.rb +6 -6
- data/app/commands/decidim/forms/{answer_questionnaire.rb → response_questionnaire.rb} +35 -35
- data/app/controllers/decidim/forms/admin/concerns/has_questionnaire.rb +12 -12
- data/app/controllers/decidim/forms/admin/concerns/{has_questionnaire_answers.rb → has_questionnaire_responses.rb} +23 -19
- data/app/controllers/decidim/forms/concerns/has_questionnaire.rb +38 -33
- data/app/forms/decidim/forms/admin/display_condition_form.rb +14 -14
- data/app/forms/decidim/forms/admin/question_form.rb +3 -3
- data/app/forms/decidim/forms/admin/{answer_option_form.rb → response_option_form.rb} +3 -3
- data/app/forms/decidim/forms/questionnaire_form.rb +8 -9
- data/app/forms/decidim/forms/{answer_choice_form.rb → response_choice_form.rb} +5 -5
- data/app/forms/decidim/forms/{answer_form.rb → response_form.rb} +9 -9
- data/app/helpers/decidim/forms/admin/application_helper.rb +2 -2
- data/app/helpers/decidim/forms/admin/concerns/{has_questionnaire_answers_pagination_helper.rb → has_questionnaire_responses_pagination_helper.rb} +4 -4
- data/app/helpers/decidim/forms/admin/concerns/{has_questionnaire_answers_url_helper.rb → has_questionnaire_responses_url_helper.rb} +5 -5
- data/app/helpers/decidim/forms/admin/questionnaire_responses_helper.rb +32 -0
- data/app/helpers/decidim/forms/application_helper.rb +1 -2
- data/app/jobs/decidim/forms/{export_questionnaire_answers_job.rb → export_questionnaire_responses_job.rb} +5 -5
- data/app/models/decidim/forms/display_condition.rb +20 -20
- data/app/models/decidim/forms/question.rb +14 -13
- data/app/models/decidim/forms/question_matrix_row.rb +1 -1
- data/app/models/decidim/forms/questionnaire.rb +11 -6
- data/app/models/decidim/forms/{answer.rb → response.rb} +9 -9
- data/app/models/decidim/forms/response_choice.rb +22 -0
- data/app/models/decidim/forms/{answer_option.rb → response_option.rb} +5 -5
- data/app/packs/entrypoints/decidim_forms_admin.js +3 -3
- data/app/packs/src/decidim/forms/admin/collapsible_questions.js +12 -10
- data/app/packs/src/decidim/forms/admin/forms.js +35 -35
- data/app/packs/src/decidim/forms/admin/{publish_answers_buttons.js → publish_responses_buttons.js} +12 -12
- data/app/packs/src/decidim/forms/display_conditions.component.js +12 -12
- data/app/packs/src/decidim/forms/forms.js +4 -4
- data/app/packs/stylesheets/decidim/forms/forms.scss +2 -2
- data/app/presenters/decidim/forms/admin/questionnaire_participant_presenter.rb +13 -13
- data/app/presenters/decidim/forms/admin/{questionnaire_answer_presenter.rb → questionnaire_response_presenter.rb} +15 -15
- data/app/presenters/decidim/forms/admin_log/question_presenter.rb +3 -3
- data/app/presenters/decidim/forms/{answer_option_presenter.rb → response_option_presenter.rb} +2 -2
- data/app/queries/decidim/forms/questionnaire_participant.rb +5 -5
- data/app/queries/decidim/forms/questionnaire_participants.rb +6 -6
- data/app/queries/decidim/forms/questionnaire_user_responses.rb +32 -0
- data/app/views/decidim/forms/admin/questionnaires/_display_condition.html.erb +9 -9
- data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +2 -2
- data/app/views/decidim/forms/admin/questionnaires/_matrix_row.html.erb +3 -3
- data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +16 -16
- data/app/views/decidim/forms/admin/questionnaires/_questions_form.html.erb +11 -10
- data/app/views/decidim/forms/admin/questionnaires/{_answer_option.html.erb → _response_option.html.erb} +7 -7
- data/app/views/decidim/forms/admin/questionnaires/_response_option_template.html.erb +7 -0
- data/app/views/decidim/forms/admin/questionnaires/_separator.html.erb +10 -7
- data/app/views/decidim/forms/admin/questionnaires/_title_and_description.html.erb +7 -7
- data/app/views/decidim/forms/admin/questionnaires/edit.html.erb +1 -1
- data/app/views/decidim/forms/admin/questionnaires/edit_questions.html.erb +8 -8
- data/app/views/decidim/forms/admin/questionnaires/responses/index.html.erb +80 -0
- data/app/views/decidim/forms/admin/questionnaires/responses/show.html.erb +43 -0
- data/app/views/decidim/forms/questionnaires/_questionnaire.html.erb +22 -26
- data/app/views/decidim/forms/questionnaires/_questionnaire_readonly.html.erb +8 -3
- data/app/views/decidim/forms/questionnaires/_response.html.erb +61 -0
- data/app/views/decidim/forms/questionnaires/edit.html.erb +2 -2
- data/app/views/decidim/forms/questionnaires/responses/_files.html.erb +1 -0
- data/app/views/decidim/forms/questionnaires/responses/_long_response.html.erb +3 -0
- data/app/views/decidim/forms/questionnaires/{answers → responses}/_matrix_multiple.html.erb +16 -15
- data/app/views/decidim/forms/questionnaires/{answers → responses}/_matrix_single.html.erb +17 -16
- data/app/views/decidim/forms/questionnaires/responses/_multiple_option.html.erb +26 -0
- data/app/views/decidim/forms/questionnaires/responses/_separator.html.erb +1 -0
- data/app/views/decidim/forms/questionnaires/responses/_short_response.html.erb +3 -0
- data/app/views/decidim/forms/questionnaires/responses/_single_option.html.erb +33 -0
- data/app/views/decidim/forms/questionnaires/responses/_sorting.html.erb +26 -0
- data/app/views/decidim/forms/questionnaires/responses/_title_and_description.html.erb +1 -0
- data/app/views/decidim/forms/questionnaires/show.html.erb +10 -10
- data/config/assets.rb +2 -2
- data/config/locales/ar.yml +0 -22
- data/config/locales/bg.yml +3 -36
- data/config/locales/ca-IT.yml +73 -73
- data/config/locales/ca.yml +73 -73
- data/config/locales/cs.yml +72 -75
- data/config/locales/de.yml +72 -72
- data/config/locales/el.yml +3 -36
- data/config/locales/en.yml +83 -83
- data/config/locales/es-MX.yml +75 -75
- data/config/locales/es-PY.yml +75 -75
- data/config/locales/es.yml +73 -73
- data/config/locales/eu.yml +71 -71
- data/config/locales/fi-plain.yml +71 -71
- data/config/locales/fi.yml +69 -69
- data/config/locales/fr-CA.yml +70 -67
- data/config/locales/fr.yml +70 -67
- data/config/locales/ga-IE.yml +0 -7
- data/config/locales/gl.yml +0 -22
- data/config/locales/hu.yml +0 -22
- data/config/locales/id-ID.yml +0 -22
- data/config/locales/it.yml +3 -40
- data/config/locales/ja.yml +80 -80
- data/config/locales/lb.yml +3 -36
- data/config/locales/lt.yml +3 -36
- data/config/locales/lv.yml +0 -22
- data/config/locales/nl.yml +3 -36
- data/config/locales/no.yml +3 -36
- data/config/locales/pl.yml +3 -36
- data/config/locales/pt-BR.yml +3 -36
- data/config/locales/pt.yml +3 -36
- data/config/locales/ro-RO.yml +22 -51
- data/config/locales/ru.yml +0 -9
- data/config/locales/sk.yml +0 -22
- data/config/locales/sl.yml +0 -5
- data/config/locales/sv.yml +82 -54
- data/config/locales/tr-TR.yml +3 -36
- data/config/locales/zh-CN.yml +3 -36
- data/config/locales/zh-TW.yml +3 -36
- data/db/migrate/20190315203056_add_session_token_to_decidim_forms_answers.rb +1 -1
- data/db/migrate/20250314150250_rename_answer_to_response_in_decidim_forms.rb +30 -0
- data/db/migrate/20250319130003_change_question_types_in_questions.rb +14 -0
- data/lib/decidim/api/question_matrix_row_type.rb +13 -0
- data/lib/decidim/api/question_type.rb +4 -3
- data/lib/decidim/api/questionnaire_type.rb +1 -0
- data/lib/decidim/api/response_option_type.rb +13 -0
- data/lib/decidim/exporters/form_pdf.rb +33 -33
- data/lib/decidim/forms/api.rb +2 -1
- data/lib/decidim/forms/{download_your_data_user_answers_serializer.rb → download_your_data_user_responses_serializer.rb} +3 -3
- data/lib/decidim/forms/engine.rb +2 -2
- data/lib/decidim/forms/test/factories.rb +24 -24
- data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +176 -176
- data/lib/decidim/forms/test/shared_examples/manage_questionnaire_responses.rb +159 -0
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions.rb +19 -19
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_questions.rb +44 -44
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_display_conditions.rb +10 -10
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_questions.rb +18 -18
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +4 -4
- data/lib/decidim/forms/test.rb +1 -1
- data/lib/decidim/forms/user_responses_serializer.rb +110 -0
- data/lib/decidim/forms/version.rb +1 -1
- data/lib/decidim/forms.rb +2 -2
- metadata +48 -45
- data/app/cells/decidim/forms/answer_readonly_cell.rb +0 -9
- data/app/helpers/decidim/forms/admin/questionnaire_answers_helper.rb +0 -30
- data/app/models/decidim/forms/answer_choice.rb +0 -22
- data/app/queries/decidim/forms/questionnaire_user_answers.rb +0 -32
- data/app/views/decidim/forms/admin/questionnaires/_answer_option_template.html.erb +0 -7
- data/app/views/decidim/forms/admin/questionnaires/answers/index.html.erb +0 -49
- data/app/views/decidim/forms/admin/questionnaires/answers/show.html.erb +0 -43
- data/app/views/decidim/forms/questionnaires/_answer.html.erb +0 -61
- data/app/views/decidim/forms/questionnaires/answers/_files.html.erb +0 -1
- data/app/views/decidim/forms/questionnaires/answers/_long_answer.html.erb +0 -3
- data/app/views/decidim/forms/questionnaires/answers/_multiple_option.html.erb +0 -25
- data/app/views/decidim/forms/questionnaires/answers/_separator.html.erb +0 -1
- data/app/views/decidim/forms/questionnaires/answers/_short_answer.html.erb +0 -3
- data/app/views/decidim/forms/questionnaires/answers/_single_option.html.erb +0 -32
- data/app/views/decidim/forms/questionnaires/answers/_sorting.html.erb +0 -26
- data/app/views/decidim/forms/questionnaires/answers/_title_and_description.html.erb +0 -1
- data/lib/decidim/api/answer_option_type.rb +0 -13
- data/lib/decidim/forms/test/shared_examples/manage_questionnaire_answers.rb +0 -149
- data/lib/decidim/forms/user_answers_serializer.rb +0 -105
- /data/app/cells/decidim/forms/{answer_readonly → response_readonly}/show.erb +0 -0
@@ -6,7 +6,7 @@ module Decidim
|
|
6
6
|
class Question < Forms::ApplicationRecord
|
7
7
|
include Decidim::TranslatableResource
|
8
8
|
|
9
|
-
QUESTION_TYPES = %w(
|
9
|
+
QUESTION_TYPES = %w(short_response long_response single_option multiple_option sorting files matrix_single matrix_multiple).freeze
|
10
10
|
SEPARATOR_TYPE = "separator"
|
11
11
|
TITLE_AND_DESCRIPTION_TYPE = "title_and_description"
|
12
12
|
TYPES = (QUESTION_TYPES + [SEPARATOR_TYPE, TITLE_AND_DESCRIPTION_TYPE]).freeze
|
@@ -21,8 +21,8 @@ module Decidim
|
|
21
21
|
dependent: :destroy,
|
22
22
|
inverse_of: :question
|
23
23
|
|
24
|
-
has_many :
|
25
|
-
class_name: "
|
24
|
+
has_many :response_options,
|
25
|
+
class_name: "ResponseOption",
|
26
26
|
foreign_key: "decidim_question_id",
|
27
27
|
dependent: :destroy,
|
28
28
|
inverse_of: :question
|
@@ -34,21 +34,22 @@ module Decidim
|
|
34
34
|
dependent: :destroy,
|
35
35
|
inverse_of: :question
|
36
36
|
|
37
|
-
# Conditions to display other questions based on the value of this question's
|
37
|
+
# Conditions to display other questions based on the value of this question's response
|
38
38
|
has_many :display_conditions_for_other_questions,
|
39
39
|
class_name: "DisplayCondition",
|
40
40
|
foreign_key: "decidim_condition_question_id",
|
41
41
|
dependent: :destroy,
|
42
|
-
inverse_of: :question
|
42
|
+
inverse_of: :question,
|
43
|
+
counter_cache: :display_conditions_for_other_questions_count
|
43
44
|
|
44
|
-
# Questions which have display conditions based on the value of this question's
|
45
|
+
# Questions which have display conditions based on the value of this question's response
|
45
46
|
has_many :conditioned_questions,
|
46
47
|
through: :display_conditions_for_other_questions,
|
47
48
|
foreign_key: "decidim_condition_question_id",
|
48
49
|
class_name: "Question"
|
49
50
|
|
50
|
-
has_many :
|
51
|
-
class_name: "
|
51
|
+
has_many :responses,
|
52
|
+
class_name: "Response",
|
52
53
|
foreign_key: "decidim_question_id",
|
53
54
|
dependent: :destroy,
|
54
55
|
inverse_of: :question
|
@@ -58,8 +59,8 @@ module Decidim
|
|
58
59
|
scope :not_separator, -> { where.not(question_type: SEPARATOR_TYPE) }
|
59
60
|
scope :not_title_and_description, -> { where.not(question_type: TITLE_AND_DESCRIPTION_TYPE) }
|
60
61
|
|
61
|
-
scope :with_body, -> { where(question_type: %w(
|
62
|
-
scope :with_choices, -> { where.not(question_type: %w(
|
62
|
+
scope :with_body, -> { where(question_type: %w(short_response long_response)) }
|
63
|
+
scope :with_choices, -> { where.not(question_type: %w(short_response long_response)) }
|
63
64
|
|
64
65
|
scope :conditioned, -> { includes(:display_conditions).where.not(decidim_forms_display_conditions: { id: nil }) }
|
65
66
|
scope :not_conditioned, -> { includes(:display_conditions).where(decidim_forms_display_conditions: { id: nil }) }
|
@@ -81,7 +82,7 @@ module Decidim
|
|
81
82
|
end
|
82
83
|
|
83
84
|
def number_of_options
|
84
|
-
|
85
|
+
response_options.size
|
85
86
|
end
|
86
87
|
|
87
88
|
def translated_body
|
@@ -100,8 +101,8 @@ module Decidim
|
|
100
101
|
question_type.to_s == "files"
|
101
102
|
end
|
102
103
|
|
103
|
-
def
|
104
|
-
questionnaire.
|
104
|
+
def responses_count
|
105
|
+
questionnaire.responses.where(question: self).count
|
105
106
|
end
|
106
107
|
|
107
108
|
def self.log_presenter_class_for(_log)
|
@@ -9,7 +9,7 @@ module Decidim
|
|
9
9
|
translatable_fields :body
|
10
10
|
belongs_to :question, class_name: "Question", foreign_key: "decidim_question_id", counter_cache: :matrix_rows_count
|
11
11
|
|
12
|
-
delegate :
|
12
|
+
delegate :response_options, :mandatory, :max_choices, to: :question
|
13
13
|
|
14
14
|
scope :by_position, -> { order(:position) }
|
15
15
|
default_scope { by_position }
|
@@ -13,22 +13,27 @@ module Decidim
|
|
13
13
|
belongs_to :questionnaire_for, polymorphic: true
|
14
14
|
|
15
15
|
has_many :questions, -> { order(:position) }, class_name: "Question", foreign_key: "decidim_questionnaire_id", dependent: :destroy
|
16
|
-
has_many :
|
16
|
+
has_many :responses, class_name: "Response", foreign_key: "decidim_questionnaire_id", dependent: :destroy
|
17
17
|
|
18
18
|
after_initialize :set_default_salt
|
19
19
|
|
20
20
|
attr_accessor :questionnaire_template_id
|
21
|
+
attr_reader :override_edit
|
21
22
|
|
22
23
|
# Public: returns whether the questionnaire questions can be modified or not.
|
23
24
|
def questions_editable?
|
24
25
|
has_component = questionnaire_for.respond_to? :component
|
25
|
-
(has_component && !questionnaire_for.component.published?) ||
|
26
|
+
(has_component && !questionnaire_for.component.published?) || override_edit.presence || responses.empty?
|
26
27
|
end
|
27
28
|
|
28
|
-
|
29
|
-
|
29
|
+
def override_edit!
|
30
|
+
@override_edit = true
|
31
|
+
end
|
32
|
+
|
33
|
+
# Public: returns whether the questionnaire is responded by the user or not.
|
34
|
+
def responded_by?(user)
|
30
35
|
query = user.is_a?(String) ? { session_token: user } : { user: }
|
31
|
-
|
36
|
+
responses.where(query).any? if questions.present?
|
32
37
|
end
|
33
38
|
|
34
39
|
def pristine?
|
@@ -45,7 +50,7 @@ module Decidim
|
|
45
50
|
|
46
51
|
private
|
47
52
|
|
48
|
-
# salt is used to generate secure hash in anonymous
|
53
|
+
# salt is used to generate secure hash in anonymous responses
|
49
54
|
def set_default_salt
|
50
55
|
return unless defined?(salt)
|
51
56
|
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module Decidim
|
4
4
|
module Forms
|
5
|
-
# The data store for an
|
6
|
-
class
|
5
|
+
# The data store for an Response in the Decidim::Forms
|
6
|
+
class Response < Forms::ApplicationRecord
|
7
7
|
include Decidim::DownloadYourData
|
8
8
|
include Decidim::NewsletterParticipant
|
9
9
|
include Decidim::HasAttachments
|
@@ -13,10 +13,10 @@ module Decidim
|
|
13
13
|
belongs_to :question, class_name: "Question", foreign_key: "decidim_question_id"
|
14
14
|
|
15
15
|
has_many :choices,
|
16
|
-
class_name: "
|
17
|
-
foreign_key: "
|
16
|
+
class_name: "ResponseChoice",
|
17
|
+
foreign_key: "decidim_response_id",
|
18
18
|
dependent: :destroy,
|
19
|
-
inverse_of: :
|
19
|
+
inverse_of: :response
|
20
20
|
|
21
21
|
validate :user_questionnaire_same_organization
|
22
22
|
validate :question_belongs_to_questionnaire
|
@@ -29,7 +29,7 @@ module Decidim
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def self.export_serializer
|
32
|
-
Decidim::Forms::
|
32
|
+
Decidim::Forms::DownloadYourDataUserResponsesSerializer
|
33
33
|
end
|
34
34
|
|
35
35
|
def self.newsletter_participant_ids(component)
|
@@ -37,10 +37,10 @@ module Decidim
|
|
37
37
|
questionnaires = Decidim::Forms::Questionnaire.includes(:questionnaire_for)
|
38
38
|
.where(questionnaire_for_type: Decidim::Surveys::Survey.name, questionnaire_for_id: surveys.pluck(:id))
|
39
39
|
|
40
|
-
|
41
|
-
|
40
|
+
responses = Decidim::Forms::Response.joins(:questionnaire)
|
41
|
+
.where(questionnaire: questionnaires)
|
42
42
|
|
43
|
-
|
43
|
+
responses.pluck(:decidim_user_id).flatten.compact.uniq
|
44
44
|
end
|
45
45
|
|
46
46
|
def organization
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Forms
|
5
|
+
class ResponseChoice < Forms::ApplicationRecord
|
6
|
+
belongs_to :response,
|
7
|
+
class_name: "Response",
|
8
|
+
foreign_key: "decidim_response_id"
|
9
|
+
|
10
|
+
belongs_to :response_option,
|
11
|
+
class_name: "ResponseOption",
|
12
|
+
foreign_key: "decidim_response_option_id"
|
13
|
+
|
14
|
+
belongs_to :matrix_row,
|
15
|
+
class_name: "QuestionMatrixRow",
|
16
|
+
foreign_key: "decidim_question_matrix_row_id",
|
17
|
+
optional: true
|
18
|
+
|
19
|
+
validates :matrix_row, presence: true, if: -> { response.question.matrix? }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -2,23 +2,23 @@
|
|
2
2
|
|
3
3
|
module Decidim
|
4
4
|
module Forms
|
5
|
-
class
|
5
|
+
class ResponseOption < Forms::ApplicationRecord
|
6
6
|
include Decidim::TranslatableResource
|
7
7
|
|
8
8
|
default_scope { order(arel_table[:id].asc) }
|
9
9
|
|
10
10
|
translatable_fields :body
|
11
11
|
|
12
|
-
belongs_to :question, class_name: "Question", foreign_key: "decidim_question_id", counter_cache: :
|
12
|
+
belongs_to :question, class_name: "Question", foreign_key: "decidim_question_id", counter_cache: :response_options_count
|
13
13
|
|
14
14
|
has_many :display_conditions,
|
15
15
|
class_name: "DisplayCondition",
|
16
|
-
foreign_key: "
|
16
|
+
foreign_key: "decidim_response_option_id",
|
17
17
|
dependent: :nullify,
|
18
|
-
inverse_of: :
|
18
|
+
inverse_of: :response_option
|
19
19
|
|
20
20
|
def translated_body
|
21
|
-
Decidim::Forms::
|
21
|
+
Decidim::Forms::ResponseOptionPresenter.new(self).translated_body
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import "src/decidim/forms/admin/collapsible_questions"
|
2
2
|
|
3
3
|
import createEditableForm from "src/decidim/forms/admin/forms"
|
4
|
-
import
|
4
|
+
import createPublicableQuestionResponsesButtons from "src/decidim/forms/admin/publish_responses_buttons"
|
5
5
|
|
6
6
|
window.Decidim.createEditableForm = createEditableForm
|
7
7
|
|
8
|
-
document.addEventListener("
|
9
|
-
document.querySelectorAll("[data-publish-question-
|
8
|
+
document.addEventListener("turbo:load", () => {
|
9
|
+
document.querySelectorAll("[data-publish-question-response-action]").forEach((el) => createPublicableQuestionResponsesButtons(el));
|
10
10
|
});
|
@@ -1,19 +1,21 @@
|
|
1
|
-
(() => {
|
1
|
+
document.addEventListener("turbo:load", () => {
|
2
2
|
const getButtons = document.querySelectorAll("button.question--collapse");
|
3
3
|
|
4
4
|
setTimeout(() => {
|
5
|
-
|
5
|
+
getButtons.forEach((button) => {
|
6
6
|
if (button.classList.contains("question-error")) {
|
7
|
-
button.click()
|
7
|
+
button.click();
|
8
8
|
}
|
9
|
-
})
|
10
|
-
}, 100)
|
9
|
+
});
|
10
|
+
}, 100);
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
document.querySelector("button.collapse-all")?.addEventListener("click", () => {
|
13
|
+
document.querySelectorAll("[id$=field] button.question--collapse[aria-expanded='true']").
|
14
|
+
forEach((button) => button.click());
|
14
15
|
});
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
document.querySelector("button.expand-all")?.addEventListener("click", () => {
|
18
|
+
document.querySelectorAll("[id$=field] button.question--collapse[aria-expanded='false']").
|
19
|
+
forEach((button) => button.click());
|
18
20
|
});
|
19
|
-
})
|
21
|
+
});
|
@@ -16,9 +16,9 @@ export default function createEditableForm() {
|
|
16
16
|
const wrapperSelector = ".questionnaire-questions";
|
17
17
|
const fieldSelector = ".questionnaire-question";
|
18
18
|
const questionTypeSelector = "select[name$=\\[question_type\\]]";
|
19
|
-
const
|
20
|
-
const
|
21
|
-
const
|
19
|
+
const responseOptionFieldSelector = ".questionnaire-question-response-option";
|
20
|
+
const responseOptionsWrapperSelector = ".questionnaire-question-response-options";
|
21
|
+
const responseOptionRemoveFieldButtonSelector = ".remove-response-option";
|
22
22
|
const matrixRowFieldSelector = ".questionnaire-question-matrix-row";
|
23
23
|
const matrixRowsWrapperSelector = ".questionnaire-question-matrix-rows";
|
24
24
|
const matrixRowRemoveFieldButtonSelector = ".remove-matrix-row";
|
@@ -30,12 +30,12 @@ export default function createEditableForm() {
|
|
30
30
|
const displayConditionRemoveFieldButtonSelector = ".remove-display-condition";
|
31
31
|
|
32
32
|
const displayConditionQuestionSelector = "select[name$=\\[decidim_condition_question_id\\]]";
|
33
|
-
const
|
33
|
+
const displayConditionResponseOptionSelector = "select[name$=\\[decidim_response_option_id\\]]";
|
34
34
|
const displayConditionTypeSelector = "select[name$=\\[condition_type\\]]";
|
35
35
|
const deletedInputSelector = "input[name$=\\[deleted\\]]";
|
36
36
|
|
37
37
|
const displayConditionValueWrapperSelector = ".questionnaire-question-display-condition-value";
|
38
|
-
const
|
38
|
+
const displayconditionResponseOptionWrapperSelector = ".questionnaire-question-display-condition-response-option";
|
39
39
|
|
40
40
|
const addDisplayConditionButtonSelector = ".add-display-condition";
|
41
41
|
|
@@ -74,27 +74,27 @@ export default function createEditableForm() {
|
|
74
74
|
const MULTIPLE_CHOICE_VALUES = ["single_option", "multiple_option", "sorting", "matrix_single", "matrix_multiple"];
|
75
75
|
const MATRIX_VALUES = ["matrix_single", "matrix_multiple"];
|
76
76
|
|
77
|
-
const
|
77
|
+
const createAutoMaxChoicesByNumberOfResponseOptions = (fieldId) => {
|
78
78
|
return new AutoSelectOptionsByTotalItemsComponent({
|
79
79
|
wrapperSelector: fieldSelector,
|
80
80
|
selectSelector: `${maxChoicesWrapperSelector} select`,
|
81
|
-
listSelector: `#${fieldId} ${
|
81
|
+
listSelector: `#${fieldId} ${responseOptionsWrapperSelector} .questionnaire-question-response-option:not(.hidden)`
|
82
82
|
})
|
83
83
|
};
|
84
84
|
|
85
|
-
const
|
85
|
+
const createAutoButtonsByMinItemsForResponseOptions = (fieldId) => {
|
86
86
|
return new AutoButtonsByMinItemsComponent({
|
87
87
|
wrapperSelector: fieldSelector,
|
88
|
-
listSelector: `#${fieldId} ${
|
88
|
+
listSelector: `#${fieldId} ${responseOptionsWrapperSelector} .questionnaire-question-response-option:not(.hidden)`,
|
89
89
|
minItems: 2,
|
90
|
-
hideOnMinItemsOrLessSelector:
|
90
|
+
hideOnMinItemsOrLessSelector: responseOptionRemoveFieldButtonSelector
|
91
91
|
})
|
92
92
|
};
|
93
93
|
|
94
94
|
const createAutoSelectOptionsFromUrl = ($field) => {
|
95
95
|
return new AutoSelectOptionsFromUrl({
|
96
96
|
source: $field.find(displayConditionQuestionSelector),
|
97
|
-
select: $field.find(
|
97
|
+
select: $field.find(displayConditionResponseOptionSelector),
|
98
98
|
sourceToParams: ($element) => { return { id: $element.val() } }
|
99
99
|
})
|
100
100
|
};
|
@@ -138,18 +138,18 @@ export default function createEditableForm() {
|
|
138
138
|
}
|
139
139
|
};
|
140
140
|
|
141
|
-
const
|
142
|
-
const autoButtons =
|
143
|
-
const autoSelectOptions =
|
141
|
+
const createDynamicFieldsForResponseOptions = (fieldId) => {
|
142
|
+
const autoButtons = createAutoButtonsByMinItemsForResponseOptions(fieldId);
|
143
|
+
const autoSelectOptions = createAutoMaxChoicesByNumberOfResponseOptions(fieldId);
|
144
144
|
|
145
145
|
return createDynamicFields({
|
146
|
-
placeholderId: "questionnaire-question-
|
147
|
-
wrapperSelector: `#${fieldId} ${
|
148
|
-
containerSelector: ".questionnaire-question-
|
149
|
-
fieldSelector:
|
150
|
-
addFieldButtonSelector: ".add-
|
151
|
-
fieldTemplateSelector: ".decidim-
|
152
|
-
removeFieldButtonSelector:
|
146
|
+
placeholderId: "questionnaire-question-response-option-id",
|
147
|
+
wrapperSelector: `#${fieldId} ${responseOptionsWrapperSelector}`,
|
148
|
+
containerSelector: ".questionnaire-question-response-options-list",
|
149
|
+
fieldSelector: responseOptionFieldSelector,
|
150
|
+
addFieldButtonSelector: ".add-response-option",
|
151
|
+
fieldTemplateSelector: ".decidim-response-option-template",
|
152
|
+
removeFieldButtonSelector: responseOptionRemoveFieldButtonSelector,
|
153
153
|
onAddField: () => {
|
154
154
|
autoButtons.run();
|
155
155
|
autoSelectOptions.run();
|
@@ -161,7 +161,7 @@ export default function createEditableForm() {
|
|
161
161
|
});
|
162
162
|
};
|
163
163
|
|
164
|
-
const
|
164
|
+
const dynamicFieldsForResponseOptions = {};
|
165
165
|
|
166
166
|
const createDynamicFieldsForMatrixRows = (fieldId) => {
|
167
167
|
return createDynamicFields({
|
@@ -200,7 +200,7 @@ export default function createEditableForm() {
|
|
200
200
|
|
201
201
|
const isMultiple = isMultipleChoiceOption(selectedQuestionType);
|
202
202
|
|
203
|
-
let conditionTypes = ["
|
203
|
+
let conditionTypes = ["responded", "not_responded"];
|
204
204
|
|
205
205
|
if (isMultiple) {
|
206
206
|
conditionTypes.push("equal");
|
@@ -236,7 +236,7 @@ export default function createEditableForm() {
|
|
236
236
|
const onDisplayConditionTypeChange = ($field) => {
|
237
237
|
const value = $field.find(displayConditionTypeSelector).val();
|
238
238
|
const $valueWrapper = $field.find(displayConditionValueWrapperSelector);
|
239
|
-
const $
|
239
|
+
const $responseOptionWrapper = $field.find(displayconditionResponseOptionWrapperSelector);
|
240
240
|
|
241
241
|
const $questionSelector = $field.find(displayConditionQuestionSelector);
|
242
242
|
const selectedQuestionType = getSelectedQuestionType($questionSelector[0]);
|
@@ -251,10 +251,10 @@ export default function createEditableForm() {
|
|
251
251
|
}
|
252
252
|
|
253
253
|
if (isMultiple && (value === "not_equal" || value === "equal")) {
|
254
|
-
$
|
254
|
+
$responseOptionWrapper.show();
|
255
255
|
}
|
256
256
|
else {
|
257
|
-
$
|
257
|
+
$responseOptionWrapper.hide();
|
258
258
|
}
|
259
259
|
};
|
260
260
|
|
@@ -302,8 +302,8 @@ export default function createEditableForm() {
|
|
302
302
|
createFieldDependentInputs({
|
303
303
|
controllerField: $fieldQuestionTypeSelect,
|
304
304
|
wrapperSelector: fieldSelector,
|
305
|
-
dependentFieldsSelector:
|
306
|
-
dependentInputSelector: `${
|
305
|
+
dependentFieldsSelector: responseOptionsWrapperSelector,
|
306
|
+
dependentInputSelector: `${responseOptionFieldSelector} input`,
|
307
307
|
enablingCondition: ($field) => {
|
308
308
|
return isMultipleChoiceOption($field.val());
|
309
309
|
}
|
@@ -329,20 +329,20 @@ export default function createEditableForm() {
|
|
329
329
|
}
|
330
330
|
});
|
331
331
|
|
332
|
-
|
332
|
+
dynamicFieldsForResponseOptions[fieldId] = createDynamicFieldsForResponseOptions(fieldId);
|
333
333
|
dynamicFieldsForMatrixRows[fieldId] = createDynamicFieldsForMatrixRows(fieldId);
|
334
334
|
dynamicFieldsForDisplayConditions[fieldId] = createDynamicFieldsForDisplayConditions(fieldId);
|
335
335
|
|
336
|
-
const
|
336
|
+
const dynamicFieldsResponseOptions = dynamicFieldsForResponseOptions[fieldId];
|
337
337
|
const dynamicFieldsMatrixRows = dynamicFieldsForMatrixRows[fieldId];
|
338
338
|
|
339
339
|
const onQuestionTypeChange = () => {
|
340
340
|
if (isMultipleChoiceOption($fieldQuestionTypeSelect.val())) {
|
341
|
-
const nOptions = $fieldQuestionTypeSelect.parents(fieldSelector).find(
|
341
|
+
const nOptions = $fieldQuestionTypeSelect.parents(fieldSelector).find(responseOptionFieldSelector).length;
|
342
342
|
|
343
343
|
if (nOptions === 0) {
|
344
|
-
|
345
|
-
|
344
|
+
dynamicFieldsResponseOptions._addField();
|
345
|
+
dynamicFieldsResponseOptions._addField();
|
346
346
|
}
|
347
347
|
}
|
348
348
|
|
@@ -400,8 +400,8 @@ export default function createEditableForm() {
|
|
400
400
|
autoLabelByPosition.run();
|
401
401
|
autoButtonsByPosition.run();
|
402
402
|
|
403
|
-
$field.find(
|
404
|
-
|
403
|
+
$field.find(responseOptionRemoveFieldButtonSelector).each((idx, el) => {
|
404
|
+
dynamicFieldsForResponseOptions[$field.attr("id")]._removeField(el);
|
405
405
|
});
|
406
406
|
|
407
407
|
$field.find(matrixRowRemoveFieldButtonSelector).each((idx, el) => {
|
data/app/packs/src/decidim/forms/admin/{publish_answers_buttons.js → publish_responses_buttons.js}
RENAMED
@@ -1,7 +1,7 @@
|
|
1
1
|
/**
|
2
|
-
* Initializes event listeners for a button to toggle the publication status of question
|
2
|
+
* Initializes event listeners for a button to toggle the publication status of question responses.
|
3
3
|
*
|
4
|
-
* The button's `data-publish-question-
|
4
|
+
* The button's `data-publish-question-response-action` attribute determines whether the action is
|
5
5
|
* to "publish" or "unpublish." Based on this attribute, the function makes an AJAX request using
|
6
6
|
* Rails' AJAX helper and updates the button's state and associated labels.
|
7
7
|
*
|
@@ -10,8 +10,8 @@
|
|
10
10
|
* @returns {void}
|
11
11
|
*
|
12
12
|
* Button element must have the following data attributes:
|
13
|
-
* - `data-publish-question-
|
14
|
-
* - `data-publish-question-
|
13
|
+
* - `data-publish-question-response-action`: Specifies the current action ("publish" or "unpublish").
|
14
|
+
* - `data-publish-question-response-question-url`: Specifies the endpoint URL for the AJAX request.
|
15
15
|
*
|
16
16
|
* The DOM structure must include:
|
17
17
|
* - A parent element with the class `toggle__switch-toggle`.
|
@@ -28,16 +28,16 @@
|
|
28
28
|
* <span class="label alert hidden">Unpublished</span>
|
29
29
|
* <span>
|
30
30
|
* <input
|
31
|
-
* data-publish-question-
|
32
|
-
* data-publish-question-
|
31
|
+
* data-publish-question-response-action="unpublish"
|
32
|
+
* data-publish-question-response-question-url="/path/to/publish/or/unpublish">
|
33
33
|
* </span>
|
34
34
|
* </label>
|
35
35
|
* ```
|
36
36
|
*/
|
37
|
-
export default function
|
37
|
+
export default function createPublicableQuestionResponsesButtons(button) {
|
38
38
|
button.addEventListener("click", () => {
|
39
|
-
const action = button.dataset.
|
40
|
-
const url = button.dataset.
|
39
|
+
const action = button.dataset.publishQuestionResponseAction;
|
40
|
+
const url = button.dataset.publishQuestionResponseQuestionUrl;
|
41
41
|
const buttonText = button.closest(".toggle__switch-toggle").querySelector(".toggle__switch-trigger-text");
|
42
42
|
const publishedLabel = buttonText.querySelector(".label.success");
|
43
43
|
const unpublishedLabel = buttonText.querySelector(".label.alert");
|
@@ -48,7 +48,7 @@ export default function createPublicableQuestionAnswersButtons(button) {
|
|
48
48
|
url: url,
|
49
49
|
type: "PUT",
|
50
50
|
success: function() {
|
51
|
-
button.setAttribute("data-publish-question-
|
51
|
+
button.setAttribute("data-publish-question-response-action", "unpublish")
|
52
52
|
publishedLabel.classList.remove("hidden");
|
53
53
|
unpublishedLabel.classList.add("hidden");
|
54
54
|
}
|
@@ -59,14 +59,14 @@ export default function createPublicableQuestionAnswersButtons(button) {
|
|
59
59
|
url: url,
|
60
60
|
type: "DELETE",
|
61
61
|
success: function() {
|
62
|
-
button.setAttribute("data-publish-question-
|
62
|
+
button.setAttribute("data-publish-question-response-action", "publish")
|
63
63
|
unpublishedLabel.classList.remove("hidden");
|
64
64
|
publishedLabel.classList.add("hidden");
|
65
65
|
}
|
66
66
|
});
|
67
67
|
break;
|
68
68
|
default:
|
69
|
-
console.log(`Publish questions
|
69
|
+
console.log(`Publish questions responses: Unknown action ${action}`);
|
70
70
|
}
|
71
71
|
});
|
72
72
|
}
|
@@ -5,7 +5,7 @@ class DisplayCondition {
|
|
5
5
|
this.wrapperField = options.wrapperField;
|
6
6
|
this.type = options.type;
|
7
7
|
this.conditionQuestion = options.conditionQuestion;
|
8
|
-
this.
|
8
|
+
this.responseOption = options.responseOption;
|
9
9
|
this.mandatory = options.mandatory;
|
10
10
|
this.value = options.value;
|
11
11
|
this.onFulfilled = options.onFulfilled;
|
@@ -34,7 +34,7 @@ class DisplayCondition {
|
|
34
34
|
if (checked) {
|
35
35
|
const text = $(el).find("input[name$=\\[custom_body\\]]").val();
|
36
36
|
const value = $input.val();
|
37
|
-
const id = $(el).find("input[name$=\\[
|
37
|
+
const id = $(el).find("input[name$=\\[response_option_id\\]]").val();
|
38
38
|
|
39
39
|
multipleInput.push({ id, value, text });
|
40
40
|
}
|
@@ -54,7 +54,7 @@ class DisplayCondition {
|
|
54
54
|
return $conditionWrapperField.find(".js-collection-input").find("input:not([type='hidden'])");
|
55
55
|
}
|
56
56
|
|
57
|
-
|
57
|
+
checkRespondedCondition(value) {
|
58
58
|
if (typeof (value) !== "object") {
|
59
59
|
return Boolean(value);
|
60
60
|
}
|
@@ -62,20 +62,20 @@ class DisplayCondition {
|
|
62
62
|
return Boolean(value.some((it) => it.value));
|
63
63
|
}
|
64
64
|
|
65
|
-
|
66
|
-
return !this.
|
65
|
+
checkNotRespondedCondition(value) {
|
66
|
+
return !this.checkRespondedCondition(value);
|
67
67
|
}
|
68
68
|
|
69
69
|
checkEqualCondition(value) {
|
70
70
|
if (value.length) {
|
71
|
-
return value.some((it) => it.id === this.
|
71
|
+
return value.some((it) => it.id === this.responseOption.toString());
|
72
72
|
}
|
73
73
|
return false;
|
74
74
|
}
|
75
75
|
|
76
76
|
checkNotEqualCondition(value) {
|
77
77
|
if (value.length) {
|
78
|
-
return value.every((it) => it.id !== this.
|
78
|
+
return value.every((it) => it.id !== this.responseOption.toString());
|
79
79
|
}
|
80
80
|
return false;
|
81
81
|
}
|
@@ -99,11 +99,11 @@ class DisplayCondition {
|
|
99
99
|
let fulfilled = false;
|
100
100
|
|
101
101
|
switch (this.type) {
|
102
|
-
case "
|
103
|
-
fulfilled = this.
|
102
|
+
case "responded":
|
103
|
+
fulfilled = this.checkRespondedCondition(value);
|
104
104
|
break;
|
105
|
-
case "
|
106
|
-
fulfilled = this.
|
105
|
+
case "not_responded":
|
106
|
+
fulfilled = this.checkNotRespondedCondition(value);
|
107
107
|
break;
|
108
108
|
case "equal":
|
109
109
|
fulfilled = this.checkEqualCondition(value);
|
@@ -143,7 +143,7 @@ class DisplayConditionsComponent {
|
|
143
143
|
wrapperField: this.wrapperField,
|
144
144
|
type: $condition.data("type"),
|
145
145
|
conditionQuestion: $condition.data("condition"),
|
146
|
-
|
146
|
+
responseOption: $condition.data("option"),
|
147
147
|
mandatory: $condition.data("mandatory"),
|
148
148
|
value: $condition.data("value"),
|
149
149
|
onFulfilled: (fulfilled) => {
|
@@ -13,7 +13,7 @@ import createDisplayConditions from "src/decidim/forms/display_conditions.compon
|
|
13
13
|
import createMaxChoicesAlertComponent from "src/decidim/forms/max_choices_alert.component"
|
14
14
|
import { preventUnload } from "src/decidim/utilities/dom"
|
15
15
|
|
16
|
-
|
16
|
+
document.addEventListener("turbo:load", () => {
|
17
17
|
$(".js-radio-button-collection, .js-check-box-collection").each((idx, el) => {
|
18
18
|
createOptionAttachedInputs({
|
19
19
|
wrapperField: $(el),
|
@@ -22,7 +22,7 @@ $(() => {
|
|
22
22
|
});
|
23
23
|
});
|
24
24
|
|
25
|
-
$.unique($(".js-check-box-collection").parents(".
|
25
|
+
$.unique($(".js-check-box-collection").parents(".response")).each((idx, el) => {
|
26
26
|
const maxChoices = $(el).data("max-choices");
|
27
27
|
if (maxChoices) {
|
28
28
|
createMaxChoicesAlertComponent({
|
@@ -40,13 +40,13 @@ $(() => {
|
|
40
40
|
item: ".js-collection-input"
|
41
41
|
}));
|
42
42
|
|
43
|
-
$(".
|
43
|
+
$(".response-questionnaire .question[data-conditioned='true']").each((idx, el) => {
|
44
44
|
createDisplayConditions({
|
45
45
|
wrapperField: $(el)
|
46
46
|
});
|
47
47
|
});
|
48
48
|
|
49
|
-
const form = document.querySelector("form.
|
49
|
+
const form = document.querySelector("form.response-questionnaire");
|
50
50
|
if (form) {
|
51
51
|
const safePath = form.dataset.safePath.split("?")[0];
|
52
52
|
let exitUrl = "";
|
@@ -1,4 +1,4 @@
|
|
1
|
-
.
|
1
|
+
.response-questionnaire {
|
2
2
|
@apply border-t-2 border-background pt-8;
|
3
3
|
|
4
4
|
&__step {
|
@@ -22,7 +22,7 @@
|
|
22
22
|
}
|
23
23
|
|
24
24
|
&__question-label {
|
25
|
-
@apply text-black text-xl font-semibold relative before:content-[attr(data-
|
25
|
+
@apply text-black text-xl font-semibold relative before:content-[attr(data-response-idx)] before:w-6 before:h-6 md:before:absolute md:before:-left-4 md:before:-translate-x-full before:inline-flex before:justify-center before:rounded-full before:bg-background before:text-lg before:text-gray-2 before:font-semibold;
|
26
26
|
}
|
27
27
|
|
28
28
|
&__question-description {
|