From 280c6bf1d6d823cde7aae1608aca4e4c36a80f22 Mon Sep 17 00:00:00 2001 From: David Beguin Date: Wed, 4 Mar 2020 08:54:15 +0000 Subject: [PATCH] [IMP] survey: auto submit for questions and matrix with simple choice Purpose ======= Speed up survey completion. Specifications ============== This commit apply an auto commit when user select a choice on a simple choice question or on a matrix question with simple choice. The auto commit happens following those conditions: - Only on simple choice and matrix with simple choice questions - For matrix, only when last subquestion is answered - Only when Back mode is active - If this is not the last question Link ==== PR #46768 Task 2208574 --- addons/survey/controllers/main.py | 6 ++--- .../controllers/survey_session_manage.py | 3 ++- addons/survey/models/survey_survey.py | 23 ++++++++++++++++++- addons/survey/static/src/js/survey_form.js | 18 +++++++++++++++ addons/survey/views/survey_templates.xml | 15 ++++++------ 5 files changed, 52 insertions(+), 13 deletions(-) diff --git a/addons/survey/controllers/main.py b/addons/survey/controllers/main.py index 8f931ae5cf8..0d0a32ee9a2 100644 --- a/addons/survey/controllers/main.py +++ b/addons/survey/controllers/main.py @@ -286,9 +286,9 @@ class Survey(http.Controller): answer_sudo.last_displayed_page_id.id if answer_sudo.last_displayed_page_id else 0) if next_page_or_question: - pages_or_questions = survey_sudo._get_pages_or_questions(answer_sudo) - if pages_or_questions.ids.index(next_page_or_question.id) == len(pages_or_questions) - 1: - data.update({'survey_last': True}) + data.update({ + 'survey_last': survey_sudo._is_last_page_or_question(answer_sudo, next_page_or_question) + }) if answer_sudo.is_session_answer and next_page_or_question.is_time_limited: data.update({ diff --git a/addons/survey/controllers/survey_session_manage.py b/addons/survey/controllers/survey_session_manage.py index cdcbabfdfe2..e81626ce95b 100644 --- a/addons/survey/controllers/survey_session_manage.py +++ b/addons/survey/controllers/survey_session_manage.py @@ -188,7 +188,8 @@ class UserInputSession(http.Controller): def _prepare_manage_session_values(self, survey): is_last_question = False if survey.question_ids: - is_last_question = survey.session_question_id == survey.question_ids[-1] + most_voted_answers = survey._get_session_most_voted_answers() + is_last_question = survey._is_last_page_or_question(most_voted_answers, survey.session_question_id) values = { 'survey': survey, diff --git a/addons/survey/models/survey_survey.py b/addons/survey/models/survey_survey.py index c5d0c5b1367..60558a94924 100644 --- a/addons/survey/models/survey_survey.py +++ b/addons/survey/models/survey_survey.py @@ -549,7 +549,7 @@ class Survey(models.Model): if page_or_question_id == 0: return pages_or_questions[0] - current_page_index = pages_or_questions.ids.index(next(p.id for p in pages_or_questions if p.id == page_or_question_id)) + current_page_index = pages_or_questions.ids.index(page_or_question_id) # Get previous and we are on first page OR Get Next and we are on last page if (go_back and current_page_index == 0) or (not go_back and current_page_index == len(pages_or_questions) - 1): @@ -582,6 +582,27 @@ class Survey(models.Model): return Question + def _is_last_page_or_question(self, user_input, page_or_question): + """ This method checks if the given question or page is the last one. + This includes conditional questions configuration. If the given question is normally not the last one but + every following questions are inactive due to conditional questions configurations (and user choices), + the given question will be the last one. + For section, we check in each following section if there is an active question. + If yes, the given page is not the last one. + """ + pages_or_questions = self._get_pages_or_questions(user_input) + current_page_index = pages_or_questions.ids.index(page_or_question.id) + next_page_or_question_candidates = pages_or_questions[current_page_index + 1:] + if next_page_or_question_candidates: + inactive_questions = user_input._get_inactive_conditional_questions() + if self.questions_layout == 'page_per_question': + return not any(next_question not in inactive_questions for next_question in next_page_or_question_candidates) + elif self.questions_layout == 'page_per_section': + for section in next_page_or_question_candidates: + return not any(next_question not in inactive_questions for next_question in section.question_ids) + + return True + def _get_survey_questions(self, answer=None, page_id=None, question_id=None): """ Returns a tuple containing: the survey question and the passed question_id / page_id based on the question_layout and the fact that it's a session or not. diff --git a/addons/survey/static/src/js/survey_form.js b/addons/survey/static/src/js/survey_form.js index 9827062e6b4..7d77dcab579 100644 --- a/addons/survey/static/src/js/survey_form.js +++ b/addons/survey/static/src/js/survey_form.js @@ -111,6 +111,7 @@ publicWidget.registry.SurveyFormWidget = publicWidget.Widget.extend({ } else { $choiceInput.prop("checked", !$choiceInput.prop("checked")).trigger('change'); } + // Avoid selection key to be typed into the textbox if 'other' is selected by key event.preventDefault(); } @@ -146,9 +147,20 @@ publicWidget.registry.SurveyFormWidget = publicWidget.Widget.extend({ var $matrixBtn = $target.closest('.o_survey_matrix_btn'); if ($target.attr('type') === 'radio') { + var isQuestionComplete = false; if ($matrixBtn.length > 0) { $matrixBtn.closest('tr').find('td').removeClass('o_survey_selected'); $matrixBtn.addClass('o_survey_selected'); + if (this.options.questionsLayout === 'page_per_question') { + var subQuestionsIds = $matrixBtn.closest('table').data('subQuestions'); + var completedQuestions = []; + subQuestionsIds.forEach(function (id) { + if (self.$('tr#' + id).find('input:checked').length !== 0) { + completedQuestions.push(id); + } + }); + isQuestionComplete = completedQuestions.length === subQuestionsIds.length; + } } else { var previouslySelectedAnswer = $choiceItemGroup.find('label.o_survey_selected'); previouslySelectedAnswer.removeClass('o_survey_selected'); @@ -156,6 +168,7 @@ publicWidget.registry.SurveyFormWidget = publicWidget.Widget.extend({ var newlySelectedAnswer = $target.closest('label'); if (newlySelectedAnswer.find('input').val() !== previouslySelectedAnswer.find('input').val()) { newlySelectedAnswer.addClass('o_survey_selected'); + isQuestionComplete = this.options.questionsLayout === 'page_per_question'; } // Conditional display @@ -187,6 +200,11 @@ publicWidget.registry.SurveyFormWidget = publicWidget.Widget.extend({ } } } + // Submit Form + var isLastQuestion = this.$('button[value="finish"]').length !== 0; + if (!isLastQuestion && this.options.usersCanGoBack && isQuestionComplete) { + this._submitForm({}); + } } else { // $target.attr('type') === 'checkbox' if ($matrixBtn.length > 0) { $matrixBtn.toggleClass('o_survey_selected', !$matrixBtn.hasClass('o_survey_selected')); diff --git a/addons/survey/views/survey_templates.xml b/addons/survey/views/survey_templates.xml index c26189a31ce..7a008e7e162 100644 --- a/addons/survey/views/survey_templates.xml +++ b/addons/survey/views/survey_templates.xml @@ -88,6 +88,7 @@ class="d-flex flex-grow-1" t-att-data-answer-token="answer.access_token" t-att-data-survey-token="survey.access_token" + t-att-data-users-can-go-back="survey.users_can_go_back" t-att-data-session-in-progress="answer.is_session_answer" t-att-data-is-start-screen="answer.state == 'new'" t-att-data-readonly="survey_form_readonly" @@ -186,7 +187,9 @@
or press Enter + Continue + Submit + or press Enter
@@ -221,12 +224,8 @@
or press Enter
@@ -532,7 +531,7 @@ - +