summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--addons/survey/controllers/main.py53
-rw-r--r--addons/survey/data/survey_demo_certification.xml1
-rw-r--r--addons/survey/data/survey_demo_quiz.xml42
-rw-r--r--addons/survey/models/survey_survey.py5
-rw-r--r--addons/survey/static/src/img/survey_background.jpgbin0 -> 166837 bytes
-rw-r--r--addons/survey/static/src/img/survey_background_2.jpgbin0 -> 86252 bytes
-rw-r--r--addons/survey/static/src/js/survey_form.js115
-rw-r--r--addons/survey/static/src/js/survey_print.js31
-rw-r--r--addons/survey/static/src/scss/survey_form.scss193
-rw-r--r--addons/survey/static/src/scss/survey_templates.scss28
-rw-r--r--addons/survey/static/src/xml/survey_breadcrumb_templates.xml10
-rw-r--r--addons/survey/static/tests/tours/certification_failure.js24
-rw-r--r--addons/survey/static/tests/tours/certification_success.js24
-rw-r--r--addons/survey/static/tests/tours/survey.js16
-rw-r--r--addons/survey/static/tests/tours/survey_prefill.js16
-rw-r--r--addons/survey/views/assets.xml4
-rw-r--r--addons/survey/views/survey_survey_views.xml2
-rw-r--r--addons/survey/views/survey_templates.xml305
-rw-r--r--addons/survey/views/survey_templates_management.xml2
-rw-r--r--addons/survey/views/survey_templates_print.xml6
-rw-r--r--addons/test_website_slides_full/tests/tours/slides_certification_member.js18
21 files changed, 700 insertions, 195 deletions
diff --git a/addons/survey/controllers/main.py b/addons/survey/controllers/main.py
index 94ced8b83f8..7b9491d3ed2 100644
--- a/addons/survey/controllers/main.py
+++ b/addons/survey/controllers/main.py
@@ -15,6 +15,8 @@ from odoo.http import request, content_disposition
from odoo.osv import expression
from odoo.tools import format_datetime, format_date
+from odoo.addons.web.controllers.main import Binary
+
_logger = logging.getLogger(__name__)
@@ -283,6 +285,24 @@ class Survey(http.Controller):
return request.render('survey.survey_page_fill',
self._prepare_survey_data(access_data['survey_sudo'], access_data['answer_sudo'], **post))
+ @http.route('/survey/get_background_image/<string:survey_token>/<string:answer_token>', type='http', auth="public", website=True, sitemap=False)
+ def survey_get_background(self, survey_token, answer_token):
+ access_data = self._get_access_data(survey_token, answer_token, ensure_token=True)
+ if access_data['validity_code'] is not True:
+ return werkzeug.exceptions.Forbidden()
+
+ survey_sudo, answer_sudo = access_data['survey_sudo'], access_data['answer_sudo']
+
+ status, headers, image_base64 = request.env['ir.http'].sudo().binary_content(
+ model='survey.survey', id=survey_sudo.id, field='background_image',
+ default_mimetype='image/png')
+
+ return Binary._content_image_get_response(status, headers, image_base64)
+
+ # ----------------------------------------------------------------
+ # JSON ROUTES to begin / continue survey (ajax navigation) + Tools
+ # ----------------------------------------------------------------
+
@http.route('/survey/begin/<string:survey_token>/<string:answer_token>', type='json', auth='public', website=True)
def survey_begin(self, survey_token, answer_token, **post):
""" Route used to start the survey user input and display the first survey page. """
@@ -427,6 +447,7 @@ class Survey(http.Controller):
'review': review,
'survey': survey_sudo,
'answer': answer_sudo,
+ 'scoring_display_correction': survey_sudo.scoring_type == 'scoring_with_answers' and answer_sudo,
'format_datetime': lambda dt: format_datetime(request.env, dt, dt_format=False),
'format_date': lambda date: format_date(request.env, date)
})
@@ -464,23 +485,8 @@ class Survey(http.Controller):
return self._generate_report(succeeded_attempt, download=True)
- def _generate_report(self, user_input, download=True):
- report = request.env.ref('survey.certification_report').sudo().render_qweb_pdf([user_input.id], data={'report_type': 'pdf'})[0]
-
- report_content_disposition = content_disposition('Certification.pdf')
- if not download:
- content_split = report_content_disposition.split(';')
- content_split[0] = 'inline'
- report_content_disposition = ';'.join(content_split)
-
- return request.make_response(report, headers=[
- ('Content-Type', 'application/pdf'),
- ('Content-Length', len(report)),
- ('Content-Disposition', report_content_disposition),
- ])
-
# ------------------------------------------------------------
- # REPORTING SURVEY ROUTES
+ # REPORTING SURVEY ROUTES AND TOOLS
# ------------------------------------------------------------
@http.route('/survey/results/<model("survey.survey"):survey>', type='http', auth='user', website=True)
@@ -509,6 +515,21 @@ class Survey(http.Controller):
'search_finished': post.get('finished') == 'true',
})
+ def _generate_report(self, user_input, download=True):
+ report = request.env.ref('survey.certification_report').sudo().render_qweb_pdf([user_input.id], data={'report_type': 'pdf'})[0]
+
+ report_content_disposition = content_disposition('Certification.pdf')
+ if not download:
+ content_split = report_content_disposition.split(';')
+ content_split[0] = 'inline'
+ report_content_disposition = ';'.join(content_split)
+
+ return request.make_response(report, headers=[
+ ('Content-Type', 'application/pdf'),
+ ('Content-Length', len(report)),
+ ('Content-Disposition', report_content_disposition),
+ ])
+
def _extract_filters_data(self, survey, post):
search_filters = []
line_filter_domain, line_choices = [], []
diff --git a/addons/survey/data/survey_demo_certification.xml b/addons/survey/data/survey_demo_certification.xml
index 5ea4351605a..e2f438b3c92 100644
--- a/addons/survey/data/survey_demo_certification.xml
+++ b/addons/survey/data/survey_demo_certification.xml
@@ -26,6 +26,7 @@
<field name="description" type="html"><p>Test your vendor skills!</p></field>
<field name="certification_give_badge">True</field>
<field name="certification_badge_id" ref="vendor_certification_badge"/>
+ <field name="background_image" type="base64" file="survey/static/src/img/survey_background_2.jpg"/>
</record>
<!-- Page 1 -->
<record model="survey.question" id="vendor_certification_page_1">
diff --git a/addons/survey/data/survey_demo_quiz.xml b/addons/survey/data/survey_demo_quiz.xml
index c4202ef081a..7a6f5347d7a 100644
--- a/addons/survey/data/survey_demo_quiz.xml
+++ b/addons/survey/data/survey_demo_quiz.xml
@@ -12,6 +12,7 @@
<field name="questions_layout">page_per_section</field>
<field name="description" type="html">
<p>This small quiz will test your knowledge about our Company. Be prepared !</p></field>
+ <field name="background_image" type="base64" file="survey/static/src/img/survey_background.jpg"/>
</record>
<!-- Page 1: general informations -->
@@ -279,4 +280,45 @@
<field name="sequence">4</field>
<field name="value">Winter</field>
</record>
+
+ <!-- Page 4: Feedback - non scored question -->
+ <record id="survey_demo_quiz_p4" model="survey.question">
+ <field name="title">Your feeling</field>
+ <field name="survey_id" ref="survey_demo_quiz"/>
+ <field name="sequence">26</field>
+ <field name="question_type" eval="False"/>
+ <field name="is_page" eval="True"/>
+ <field name="description" type="html">
+ <p>We may be interested by your input.</p></field>
+ </record>
+ <record id="survey_demo_quiz_p4_q1" model="survey.question">
+ <field name="survey_id" ref="survey_demo_quiz"/>
+ <field name="sequence">27</field>
+ <field name="title">What do you think about this survey ?</field>
+ <field name="description" type="html"><span>If you don't like us, please try to be as objective as possible.</span></field>
+ <field name="question_type">simple_choice</field>
+ <field name="comments_allowed" eval="True"/>
+ <field name="comment_count_as_answer" eval="True"/>
+ <field name="constr_mandatory" eval="False"/>
+ </record>
+ <record id="survey_demo_quiz_p4_q1_sug1" model="survey.question.answer">
+ <field name="question_id" ref="survey_demo_quiz_p4_q1"/>
+ <field name="sequence">1</field>
+ <field name="value">Good</field>
+ </record>
+ <record id="survey_demo_quiz_p4_q1_sug2" model="survey.question.answer">
+ <field name="question_id" ref="survey_demo_quiz_p4_q1"/>
+ <field name="sequence">2</field>
+ <field name="value">Not Good, Not Bad</field>
+ </record>
+ <record id="survey_demo_quiz_p4_q1_sug3" model="survey.question.answer">
+ <field name="question_id" ref="survey_demo_quiz_p4_q1"/>
+ <field name="sequence">3</field>
+ <field name="value">Iznogoud</field>
+ </record>
+ <record id="survey_demo_quiz_p4_q1_sug4" model="survey.question.answer">
+ <field name="question_id" ref="survey_demo_quiz_p4_q1"/>
+ <field name="sequence">4</field>
+ <field name="value">I have no idea, I'm a dog!</field>
+ </record>
</data></odoo>
diff --git a/addons/survey/models/survey_survey.py b/addons/survey/models/survey_survey.py
index f12a34ad5fe..6c6d36168a8 100644
--- a/addons/survey/models/survey_survey.py
+++ b/addons/survey/models/survey_survey.py
@@ -30,6 +30,7 @@ class Survey(models.Model):
description_done = fields.Html(
"End Message", translate=True,
help="This message will be displayed when survey is completed")
+ background_image = fields.Binary("Background Image")
active = fields.Boolean("Active", default=True)
state = fields.Selection(selection=[
('draft', 'Draft'), ('open', 'In Progress'), ('closed', 'Closed')
@@ -49,6 +50,10 @@ class Survey(models.Model):
('random', 'Randomized per section')],
string="Selection", required=True, default='all',
help="If randomized is selected, add the number of random questions next to the section.")
+ progression_mode = fields.Selection([
+ ('percent', 'Percentage'),
+ ('number', 'Number')], string='Progression Mode', default='percent',
+ help="If Number is selected, it will display the number of questions answered on the total number of question to answer.")
# attendees
user_input_ids = fields.One2many('survey.user_input', 'survey_id', string='User responses', readonly=True, groups='survey.group_survey_user')
# security / access
diff --git a/addons/survey/static/src/img/survey_background.jpg b/addons/survey/static/src/img/survey_background.jpg
new file mode 100644
index 00000000000..ba7c4f0263a
--- /dev/null
+++ b/addons/survey/static/src/img/survey_background.jpg
Binary files differ
diff --git a/addons/survey/static/src/img/survey_background_2.jpg b/addons/survey/static/src/img/survey_background_2.jpg
new file mode 100644
index 00000000000..b2e076ed2ba
--- /dev/null
+++ b/addons/survey/static/src/img/survey_background_2.jpg
Binary files differ
diff --git a/addons/survey/static/src/js/survey_form.js b/addons/survey/static/src/js/survey_form.js
index 02f9e567365..eb8ac3a95be 100644
--- a/addons/survey/static/src/js/survey_form.js
+++ b/addons/survey/static/src/js/survey_form.js
@@ -6,11 +6,13 @@ var publicWidget = require('web.public.widget');
var time = require('web.time');
var core = require('web.core');
var _t = core._t;
+var dom = require('web.dom');
publicWidget.registry.SurveyFormWidget = publicWidget.Widget.extend({
selector: '.o_survey_form',
events: {
'change .o_survey_form_choice_item': '_onChangeChoiceItem',
+ 'click .o_survey_matrix_btn': '_onMatrixBtnClick',
'click button[type="submit"]': '_onSubmit',
},
custom_events: {
@@ -29,6 +31,7 @@ publicWidget.registry.SurveyFormWidget = publicWidget.Widget.extend({
this.fadeInOutDelay = 400;
return this._super.apply(this, arguments).then(function () {
self.options = self.$target.find('form').data();
+ // Init fields
if (!self.options.isStartScreen) {
self._initTimer();
self._initBreadcrumb();
@@ -36,6 +39,13 @@ publicWidget.registry.SurveyFormWidget = publicWidget.Widget.extend({
self.$('div.o_survey_form_date').each(function () {
self._initDateTimePicker($(this));
});
+ self._initChoiceItems();
+ self._initTextArea();
+ self._focusOnFirstInput();
+ // Init event listener
+ if (!self.options.readonly) {
+ $(document).on('keypress', self._onKeyPress.bind(self));
+ }
});
},
@@ -46,6 +56,35 @@ publicWidget.registry.SurveyFormWidget = publicWidget.Widget.extend({
// Handlers
// -------------------------------------------------------------------------
+ _onKeyPress: function (event) {
+ // If user is answering a textarea, do not handle keyPress
+ if (this.$("textarea").is(":focus")) {
+ return;
+ }
+
+ var self = this;
+ var keyCode = event.keyCode;
+ var letter = String.fromCharCode(keyCode).toUpperCase();
+
+ // Handle Start / Next / Submit
+ if (keyCode === 13) { // Enter : go Next
+ event.preventDefault();
+ this._submitForm({});
+ } else if (self.options.questionsLayout === 'page_per_question'
+ && letter.match(/[a-z]/i)) {
+ var $choiceInput = this.$(`input[data-selection-key=${letter}]`);
+ if ($choiceInput.length === 1) {
+ if ($choiceInput.attr('type') === 'radio') {
+ $choiceInput.prop("checked", true).trigger('change');
+ } 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();
+ }
+ }
+ },
+
/**
* Checks, if the 'other' choice is checked. Applies only if the comment count as answer.
* If not checked : Clear the comment textarea and disable it
@@ -55,7 +94,8 @@ publicWidget.registry.SurveyFormWidget = publicWidget.Widget.extend({
* @param {Event} event
*/
_onChangeChoiceItem: function (event) {
- var $choiceItemGroup = $(event.currentTarget).parents('.o_survey_form_choice');
+ var $target = $(event.currentTarget);
+ var $choiceItemGroup = $target.closest('.o_survey_form_choice');
var $otherItem = $choiceItemGroup.find('.o_survey_js_form_other_comment');
var $commentInput = $choiceItemGroup.find('textarea[type="text"]');
@@ -68,6 +108,36 @@ publicWidget.registry.SurveyFormWidget = publicWidget.Widget.extend({
$commentInput.val('');
$commentInput.enable(false);
}
+
+ var $matrixBtn = $target.closest('.o_survey_matrix_btn');
+ if ($target.attr('type') === 'radio') {
+ if ($matrixBtn.length > 0) {
+ $matrixBtn.closest('tr').find('td').removeClass('o_survey_selected');
+ $matrixBtn.addClass('o_survey_selected');
+ } else {
+ $choiceItemGroup.find('label').removeClass('o_survey_selected');
+ $target.closest('label').addClass('o_survey_selected');
+ }
+ } else { // $target.attr('type') === 'checkbox'
+ if ($matrixBtn.length > 0) {
+ $matrixBtn.toggleClass('o_survey_selected', !$matrixBtn.hasClass('o_survey_selected'));
+ } else {
+ var $label = $target.closest('label');
+ $label.toggleClass('o_survey_selected', !$label.hasClass('o_survey_selected'));
+ }
+ }
+ },
+
+ _onMatrixBtnClick: function (event) {
+ if (!this.options.readonly) {
+ var $target = $(event.currentTarget);
+ var $input = $target.find('input');
+ if ($input.attr('type') === 'radio') {
+ $input.prop("checked", true).trigger('change');
+ } else {
+ $input.prop("checked", !$input.prop("checked")).trigger('change');
+ }
+ }
},
_onSubmit: function (event) {
@@ -177,8 +247,11 @@ publicWidget.registry.SurveyFormWidget = publicWidget.Widget.extend({
} else {
this._updateBreadcrumb();
}
+ self._initChoiceItems();
+ self._initTextArea();
this.$('.o_survey_form_content').fadeIn(this.fadeInOutDelay);
$("html, body").animate({ scrollTop: 0 }, this.fadeInOutDelay);
+ self._focusOnFirstInput();
}
else if (result && result.fields && result.error === 'validation') {
this.$('.o_survey_form_content').fadeIn(0);
@@ -321,7 +394,7 @@ publicWidget.registry.SurveyFormWidget = publicWidget.Widget.extend({
*/
_prepareSubmitValues: function (formData, params) {
var self = this;
- formData.forEach(function (value, key){
+ formData.forEach(function (value, key) {
switch (key) {
case 'csrf_token':
case 'token':
@@ -463,6 +536,25 @@ publicWidget.registry.SurveyFormWidget = publicWidget.Widget.extend({
// INIT FIELDS TOOLS
// -------------------------------------------------------------------------
+ /**
+ * Will allow the textarea to resize on carriage return instead of showing scrollbar.
+ */
+ _initTextArea: function () {
+ this.$('textarea').each(function () {
+ dom.autoresize($(this));
+ });
+ },
+
+ _initChoiceItems: function () {
+ this.$("input[type='radio'],input[type='checkbox']").each(function () {
+ var matrixBtn = $(this).parents('.o_survey_matrix_btn');
+ if ($(this).prop("checked")) {
+ var $target = matrixBtn.length > 0 ? matrixBtn : $(this).closest('label');
+ $target.addClass('o_survey_selected');
+ }
+ });
+ },
+
/**
* Will initialize the breadcrumb widget that handles navigation to a previously filled in page.
*
@@ -573,6 +665,17 @@ publicWidget.registry.SurveyFormWidget = publicWidget.Widget.extend({
}
},
+ /**
+ * Will automatically focus on the first input to allow the user to complete directly the survey,
+ * without having to manually get the focus (only if the input has the right type - can write something inside -)
+ */
+ _focusOnFirstInput: function () {
+ var $inputs = this.$("input[type='text'],input[type='number'],textarea").not('.o_survey_comment');
+ if ($inputs.length > 0) {
+ $inputs.first().focus();
+ }
+ },
+
// ERRORS TOOLS
// -------------------------------------------------------------------------
@@ -591,10 +694,12 @@ publicWidget.registry.SurveyFormWidget = publicWidget.Widget.extend({
var scrollLocation = $target.offset().top;
var navbarHeight = $('.o_main_navbar').height();
if (navbarHeight) {
- scrollLocation -= navbarHeight;
+ // In overflow auto, scrollLocation of target can be negative if target is out of screen (up side)
+ scrollLocation = scrollLocation >= 0 ? scrollLocation - navbarHeight : scrollLocation + navbarHeight;
}
- $('html, body').animate({
- scrollTop: scrollLocation
+ var scrollinside = $("#wrapwrap").scrollTop();
+ $('#wrapwrap').animate({
+ scrollTop: scrollinside + scrollLocation
}, 500);
},
diff --git a/addons/survey/static/src/js/survey_print.js b/addons/survey/static/src/js/survey_print.js
new file mode 100644
index 00000000000..5e4b8118aec
--- /dev/null
+++ b/addons/survey/static/src/js/survey_print.js
@@ -0,0 +1,31 @@
+odoo.define('survey.print', function (require) {
+'use strict';
+
+var publicWidget = require('web.public.widget');
+var dom = require('web.dom');
+
+publicWidget.registry.SurveyPrintWidget = publicWidget.Widget.extend({
+ selector: '.o_survey_print',
+
+ //--------------------------------------------------------------------------
+ // Widget
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ start: function () {
+ var self = this;
+ return this._super.apply(this, arguments).then(function () {
+ // Will allow the textarea to resize if any carriage return instead of showing scrollbar.
+ self.$('textarea').each(function () {
+ dom.autoresize($(this));
+ });
+ });
+ },
+
+});
+
+return publicWidget.registry.SurveyPrintWidget;
+
+});
diff --git a/addons/survey/static/src/scss/survey_form.scss b/addons/survey/static/src/scss/survey_form.scss
new file mode 100644
index 00000000000..7c54bed6738
--- /dev/null
+++ b/addons/survey/static/src/scss/survey_form.scss
@@ -0,0 +1,193 @@
+.o_survey_wrap {
+ min-height: 100%;
+}
+
+/**********************************************************
+ Common Style
+ **********************************************************/
+
+.o_survey_form, .o_survey_print {
+ .o_survey_question_error {
+ height: 0px;
+ transition: height .5s ease;
+ line-height: 4rem;
+ &.slide_in {
+ height: 4rem;
+ }
+ }
+
+ .o_survey_question_text_box,
+ .o_survey_question_date,
+ .o_survey_question_datetime,
+ .o_survey_question_numerical_box {
+ border: 0px;
+ border-bottom: 2px solid $o-brand-primary;
+ &:disabled {
+ color: black !important;
+ border-color: $gray-600;
+ border-bottom: 2px solid $gray-600;
+ }
+ &:focus {
+ border-color: $o-brand-primary;
+ }
+ }
+
+ .o_survey_form_date .input-group-append {
+ right: 0;
+ .input-group-text i {
+ font-size: large;
+ }
+ }
+
+ .o_survey_choice_btn {
+ transition: background-color 0.3s ease;
+ flex: 1 0 300px;
+
+ span {
+ line-height: 25px;
+ }
+ i {
+ top: 0px;
+ font-size: large;
+ &.fa-check-circle,&.fa-check-square {
+ display: none;
+ }
+ }
+
+ &.o_survey_selected i {
+ display: none;
+ &.fa-check-circle,&.fa-check-square {
+ display: inline;
+ }
+ }
+ }
+
+ .o_survey_question_matrix {
+ td {
+ min-width: 100px;
+ i {
+ font-size: 22px;
+ display: none;
+ &.o_survey_matrix_empty_checkbox {
+ display: inline;
+ }
+ }
+ .o_survey_choice_key > span > span {
+ top: 0px;
+ }
+
+ &.o_survey_selected {
+ i {
+ display: inline;
+ &.o_survey_matrix_empty_checkbox {
+ display: none;
+ }
+ }
+ }
+ }
+ }
+}
+
+/**********************************************************
+ Form Specific Style
+ **********************************************************/
+
+.o_survey_form {
+ min-height: 100%;
+
+ .o_survey_choice_btn {
+ background-color: rgba($o-brand-primary, 0.5);
+ border: 2px solid $o-brand-primary;
+ cursor: pointer;
+
+ &.o_survey_selected {
+ background-color: $o-brand-primary;
+ }
+
+ &:hover {
+ background-color: rgba($o-brand-primary, 0.8);
+ .o_survey_choice_key span.o_survey_key {
+ opacity: 1;
+ }
+ }
+ }
+
+ .o_survey_choice_key {
+ width: 25px;
+ height: 25px;
+ border: 2px solid $o-brand-primary;
+ span {
+ font-size: smaller;
+ top: -2px;
+ &.o_survey_key {
+ width: inherit;
+ right: 10px;
+ border: 2px solid $o-brand-primary;
+ border-right: 0px;
+ height: 25px;
+ opacity: 0;
+ transition: opacity 0.4s ease;
+ white-space: nowrap;
+ }
+ }
+ }
+
+ .o_survey_question_matrix {
+ th {
+ background-color: $o-brand-primary;
+ }
+ td {
+ background-color: rgba($o-brand-primary, 0.2);
+
+ &:hover {
+ background-color: rgba($o-brand-primary, 0.5);
+ cursor: pointer;
+ .o_survey_choice_key span.o_survey_key {
+ opacity: 1;
+ }
+ }
+ }
+ }
+
+ .o_survey_progress {
+ height:0.5em;
+ }
+}
+
+/**********************************************************
+ Print Specific Style
+ **********************************************************/
+
+.o_survey_print {
+ .o_survey_choice_btn {
+ background-color: $gray-500;
+ border-color: transparent;
+ cursor: default;
+
+ &.bg-success, &.bg-danger {
+ opacity: 0.6;
+ }
+ &.o_survey_selected {
+ background-color: $gray-600;
+ opacity: 1;
+ }
+ i.fa-square, i.fa-circle {
+ display: none;
+ }
+ }
+ .o_survey_question_matrix {
+ th {
+ /* important needed to force override bg-primary set on th in the template */
+ background-color: $gray-600 !important;
+ }
+ td {
+ background-color: $gray-200;
+ &:hover {
+ cursor: default;
+ }
+ }
+ i.fa-check-square, i.fa-check-circle, i.o_survey_matrix_empty_checkbox {
+ color: $gray-600;
+ }
+ }
+}
diff --git a/addons/survey/static/src/scss/survey_templates.scss b/addons/survey/static/src/scss/survey_templates.scss
deleted file mode 100644
index 4a53c4ac0af..00000000000
--- a/addons/survey/static/src/scss/survey_templates.scss
+++ /dev/null
@@ -1,28 +0,0 @@
-.o_survey_header {
- padding-top: 15px;
- padding-bottom: 25px;
-}
-
-.o_survey_title {
- padding-bottom: 15px;
-}
-
-.js_question-wrapper {
- padding-bottom: 25px;
-}
-
-.o_survey_breadcrumb_container {
- min-height: 3rem;
-}
-
-.o_survey_question_error {
- overflow: hidden;
- height: 0px;
- border: 0px;
- padding: 0rem 0.75rem;
- transition: height .5s ease;
- line-height: 4rem;
- &.slide_in {
- height: 4rem;
- }
-}
diff --git a/addons/survey/static/src/xml/survey_breadcrumb_templates.xml b/addons/survey/static/src/xml/survey_breadcrumb_templates.xml
index 8893d711815..1df7f54a88a 100644
--- a/addons/survey/static/src/xml/survey_breadcrumb_templates.xml
+++ b/addons/survey/static/src/xml/survey_breadcrumb_templates.xml
@@ -2,10 +2,11 @@
<templates id="template" xml:space="preserve">
<t t-name="survey.survey_breadcrumb_template">
- <ol class="breadcrumb justify-content-end">
+ <ol class="breadcrumb justify-content-end bg-transparent">
<t t-set="canGoBack" t-value="widget.canGoBack"/>
<t t-foreach="widget.pages" t-as="page">
- <li t-att-class="'breadcrumb-item' + (page.id === widget.currentPageId ? ' active' : '')"
+ <t t-set="isActivePage" t-value="page.id === widget.currentPageId"/>
+ <li t-att-class="'breadcrumb-item' + (isActivePage ? ' active font-weight-bold' : '')"
t-att-data-page-id="page.id"
t-att-data-page-title="page.title">
<t t-if="widget.currentPageId === page.id">
@@ -14,12 +15,13 @@
<t t-set="canGoBack" t-value="false" />
</t>
<t t-if="canGoBack">
- <a href="#">
+ <a class="text-primary" href="#">
<span t-esc="page.title" />
</a>
</t>
<t t-else="">
- <span t-esc="page.title" />
+ <span t-att-class="(isActivePage ? 'text-black' : 'text-muted')"
+ t-esc="page.title" />
</t>
</li>
</t>
diff --git a/addons/survey/static/tests/tours/certification_failure.js b/addons/survey/static/tests/tours/certification_failure.js
index fa6849e63e9..2094ee1925f 100644
--- a/addons/survey/static/tests/tours/certification_failure.js
+++ b/addons/survey/static/tests/tours/certification_failure.js
@@ -24,43 +24,43 @@ var failSteps = [{ // Page-1
trigger: 'button.btn.btn-primary.btn-lg:contains("Start Certification")',
}, { // Question: Do we sell Acoustic Bloc Screens?
content: "Selecting answer 'No'",
- trigger: 'div.js_question-wrapper:contains("Do we sell Acoustic Bloc Screens") label:contains("No") input',
+ trigger: 'div.js_question-wrapper:contains("Do we sell Acoustic Bloc Screens") label:contains("No")',
}, { // Question: Select all the existing products
content: "Ticking answer 'Fanta'",
- trigger: 'div.js_question-wrapper:contains("Select all the existing products") label:contains("Fanta") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the existing products") label:contains("Fanta")'
}, {
content: "Ticking answer 'Drawer'",
- trigger: 'div.js_question-wrapper:contains("Select all the existing products") label:contains("Drawer") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the existing products") label:contains("Drawer")'
}, {
content: "Ticking answer 'Conference chair'",
- trigger: 'div.js_question-wrapper:contains("Select all the existing products") label:contains("Conference chair") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the existing products") label:contains("Conference chair")'
}, { // Question: Select all the available customizations for our Customizable Desk
content: "Ticking answer 'Color'",
- trigger: 'div.js_question-wrapper:contains("Select all the available customizations for our Customizable Desk") label:contains("Color") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the available customizations for our Customizable Desk") label:contains("Color")'
}, {
content: "Ticking answer 'Height'",
- trigger: 'div.js_question-wrapper:contains("Select all the available customizations for our Customizable Desk") label:contains("Height") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the available customizations for our Customizable Desk") label:contains("Height")'
}, { // Question: How many versions of the Corner Desk do we have?
content: "Selecting answer '2'",
- trigger: 'div.js_question-wrapper:contains("How many versions of the Corner Desk do we have") label:contains("2") input',
+ trigger: 'div.js_question-wrapper:contains("How many versions of the Corner Desk do we have") label:contains("2")',
}, { // Question: Do you think we have missing products in our catalog? (not rated)
content: "Missing products",
trigger: 'div.js_question-wrapper:contains("Do you think we have missing products in our catalog") textarea',
run: "text I don't know products enough to be able to answer that",
}, { // Page-2 Question: How much do we sell our Cable Management Box?
content: "Selecting answer '80$'",
- trigger: 'div.js_question-wrapper:contains("How much do we sell our Cable Management Box") label:contains("80$") input',
+ trigger: 'div.js_question-wrapper:contains("How much do we sell our Cable Management Box") label:contains("80$")',
}, { // Question: Select all the the products that sell for 100$ or more
content: "Ticking answer 'Corner Desk Right Sit'",
- trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for 100$ or more") label:contains("Corner Desk Right Sit") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for 100$ or more") label:contains("Corner Desk Right Sit")'
}, {
content: "Ticking answer 'Desk Combination'",
- trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for 100$ or more") label:contains("Desk Combination") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for 100$ or more") label:contains("Desk Combination")'
}, {
content: "Ticking answer 'Office Chair Black'",
- trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for 100$ or more") label:contains("Office Chair Black") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for 100$ or more") label:contains("Office Chair Black")'
}, { // Question: What do you think about our prices (not rated)?
- trigger: 'div.js_question-wrapper:contains("What do you think about our prices") label:contains("Correctly priced") input',
+ trigger: 'div.js_question-wrapper:contains("What do you think about our prices") label:contains("Correctly priced")',
}, {
content: "Finish Survey",
trigger: 'button[type="submit"]',
diff --git a/addons/survey/static/tests/tours/certification_success.js b/addons/survey/static/tests/tours/certification_success.js
index 584c357f7ba..360efb1c16b 100644
--- a/addons/survey/static/tests/tours/certification_success.js
+++ b/addons/survey/static/tests/tours/certification_success.js
@@ -23,44 +23,44 @@ tour.register('test_certification_success', {
trigger: 'button.btn.btn-primary.btn-lg:contains("Start Certification")',
}, { // Question: Do we sell Acoustic Bloc Screens?
content: "Selecting answer 'Yes'",
- trigger: 'div.js_question-wrapper:contains("Do we sell Acoustic Bloc Screens") label:contains("Yes") input',
+ trigger: 'div.js_question-wrapper:contains("Do we sell Acoustic Bloc Screens") label:contains("Yes")',
}, { // Question: Select all the existing products
content: "Ticking answer 'Chair floor protection'",
- trigger: 'div.js_question-wrapper:contains("Select all the existing products") label:contains("Chair floor protection") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the existing products") label:contains("Chair floor protection")'
}, {
content: "Ticking answer 'Drawer'",
- trigger: 'div.js_question-wrapper:contains("Select all the existing products") label:contains("Drawer") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the existing products") label:contains("Drawer")'
}, {
content: "Ticking answer 'Conference chair'",
- trigger: 'div.js_question-wrapper:contains("Select all the existing products") label:contains("Conference chair") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the existing products") label:contains("Conference chair")'
}, { // Question: Select all the available customizations for our Customizable Desk
content: "Ticking answer 'Color'",
- trigger: 'div.js_question-wrapper:contains("Select all the available customizations for our Customizable Desk") label:contains("Color") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the available customizations for our Customizable Desk") label:contains("Color")'
}, {
content: "Ticking answer 'Legs'",
- trigger: 'div.js_question-wrapper:contains("Select all the available customizations for our Customizable Desk") label:contains("Legs") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the available customizations for our Customizable Desk") label:contains("Legs")'
}, { // Question: How many versions of the Corner Desk do we have?
content: "Selecting answer '2'",
- trigger: 'div.js_question-wrapper:contains("How many versions of the Corner Desk do we have") label:contains("2") input',
+ trigger: 'div.js_question-wrapper:contains("How many versions of the Corner Desk do we have") label:contains("2")',
}, { // Question: Do you think we have missing products in our catalog? (not rated)
content: "Missing products",
trigger: 'div.js_question-wrapper:contains("Do you think we have missing products in our catalog") textarea',
run: "text I think we should make more versions of the customizable desk, it's such an amazing product!",
}, { // Page-2 Question: How much do we sell our Cable Management Box?
content: "Selecting answer '80$' (wrong one)",
- trigger: 'div.js_question-wrapper:contains("How much do we sell our Cable Management Box") label:contains("80$") input',
+ trigger: 'div.js_question-wrapper:contains("How much do we sell our Cable Management Box") label:contains("80$")',
}, { // Question: Select all the the products that sell for 100$ or more
content: "Ticking answer 'Corner Desk Right Sit'",
- trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for 100$ or more") label:contains("Corner Desk Right Sit") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for 100$ or more") label:contains("Corner Desk Right Sit")'
}, {
content: "Ticking answer 'Desk Combination'",
- trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for 100$ or more") label:contains("Desk Combination") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for 100$ or more") label:contains("Desk Combination")'
}, {
content: "Ticking answer 'Large Desk'",
- trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for 100$ or more") label:contains("Large Desk") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for 100$ or more") label:contains("Large Desk")'
}, { // Question: What do you think about our prices (not rated)?
content: "Selecting answer 'Underpriced'",
- trigger: 'div.js_question-wrapper:contains("What do you think about our prices") label:contains("Underpriced") input',
+ trigger: 'div.js_question-wrapper:contains("What do you think about our prices") label:contains("Underpriced")',
}, {
content: "Finish Survey",
trigger: 'button[type="submit"]',
diff --git a/addons/survey/static/tests/tours/survey.js b/addons/survey/static/tests/tours/survey.js
index fce408f9cbe..22344bd2d99 100644
--- a/addons/survey/static/tests/tours/survey.js
+++ b/addons/survey/static/tests/tours/survey.js
@@ -21,7 +21,7 @@ tour.register('test_survey', {
run: 'text 05/05/1980',
}, {
content: 'Answer How frequently do you buy products online',
- trigger: 'div.js_question-wrapper:contains("How frequently do you buy products online") label:contains("Once a month") input',
+ trigger: 'div.js_question-wrapper:contains("How frequently do you buy products online") label:contains("Once a month")',
}, {
content: 'Answer How many times did you order products on our website',
trigger: 'div.js_question-wrapper:contains("How many times did you order products on our website") input',
@@ -33,25 +33,25 @@ tour.register('test_survey', {
// Page-2
{
content: 'Answer Which of the following words would you use to describe our products (High Quality)',
- trigger: 'div.js_question-wrapper:contains("Which of the following words would you use to describe our products") label:contains("High quality") input',
+ trigger: 'div.js_question-wrapper:contains("Which of the following words would you use to describe our products") label:contains("High quality")',
}, {
content: 'Answer Which of the following words would you use to describe our products (Good value for money)',
- trigger: 'div.js_question-wrapper:contains("Which of the following words would you use to describe our products") label:contains("Good value for money") input',
+ trigger: 'div.js_question-wrapper:contains("Which of the following words would you use to describe our products") label:contains("Good value for money")',
}, {
content: 'Answer What do your think about our new eCommerce (The new layout and design is fresh and up-to-date)',
- trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("The new layout and design is fresh and up-to-date") input:first',
+ trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("The new layout and design is fresh and up-to-date") td:first',
}, {
content: 'Answer What do your think about our new eCommerce (It is easy to find the product that I want)',
- trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("It is easy to find the product that I want") input:eq(2)',
+ trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("It is easy to find the product that I want") td:eq(2)',
}, {
content: 'Answer What do your think about our new eCommerce (The tool to compare the products is useful to make a choice)',
- trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("The tool to compare the products is useful to make a choice") input:eq(3)',
+ trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("The tool to compare the products is useful to make a choice") td:eq(3)',
}, {
content: 'Answer What do your think about our new eCommerce (The checkout process is clear and secure)',
- trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("The checkout process is clear and secure") input:eq(2)',
+ trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("The checkout process is clear and secure") td:eq(2)',
}, {
content: 'Answer What do your think about our new eCommerce (I have added products to my wishlist)',
- trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("I have added products to my wishlist") input:last',
+ trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("I have added products to my wishlist") td:last',
}, {
content: 'Answer Do you have any other comments, questions, or concerns',
trigger: 'div.js_question-wrapper:contains("Do you have any other comments, questions, or concerns") textarea',
diff --git a/addons/survey/static/tests/tours/survey_prefill.js b/addons/survey/static/tests/tours/survey_prefill.js
index 89242a0a5d0..223b824cb1b 100644
--- a/addons/survey/static/tests/tours/survey_prefill.js
+++ b/addons/survey/static/tests/tours/survey_prefill.js
@@ -16,7 +16,7 @@ tour.register('test_survey_prefill', {
trigger: 'div.js_question-wrapper:contains("When is your date of birth ?") input',
run: 'text 05/05/1980',
}, { // Question: How frequently do you buy products online ?
- trigger: 'div.js_question-wrapper:contains("How frequently do you buy products online ?") label:contains("Once a week") input',
+ trigger: 'div.js_question-wrapper:contains("How frequently do you buy products online ?") label:contains("Once a week")',
}, { // Question: How many times did you order products on our website ?
trigger: 'div.js_question-wrapper:contains("How many times did you order products on our website ?") input',
run: 'text 42',
@@ -27,25 +27,25 @@ tour.register('test_survey_prefill', {
// Page-2
{ // Question: Which of the following words would you use to describe our products ?
content: 'Answer Which of the following words would you use to describe our products (High Quality)',
- trigger: 'div.js_question-wrapper:contains("Which of the following words would you use to describe our products") label:contains("High quality") input',
+ trigger: 'div.js_question-wrapper:contains("Which of the following words would you use to describe our products") label:contains("High quality")',
}, {
content: 'Answer Which of the following words would you use to describe our products (Good value for money)',
- trigger: 'div.js_question-wrapper:contains("Which of the following words would you use to describe our products") label:contains("Good value for money") input',
+ trigger: 'div.js_question-wrapper:contains("Which of the following words would you use to describe our products") label:contains("Good value for money")',
}, {
content: 'Answer What do your think about our new eCommerce (The new layout and design is fresh and up-to-date)',
- trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("The new layout and design is fresh and up-to-date") input:first',
+ trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("The new layout and design is fresh and up-to-date") td:first',
}, {
content: 'Answer What do your think about our new eCommerce (It is easy to find the product that I want)',
- trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("It is easy to find the product that I want") input:eq(2)',
+ trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("It is easy to find the product that I want") td:eq(2)',
}, {
content: 'Answer What do your think about our new eCommerce (The tool to compare the products is useful to make a choice)',
- trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("The tool to compare the products is useful to make a choice") input:eq(3)',
+ trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("The tool to compare the products is useful to make a choice") td:eq(3)',
}, {
content: 'Answer What do your think about our new eCommerce (The checkout process is clear and secure)',
- trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("The checkout process is clear and secure") input:eq(2)',
+ trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("The checkout process is clear and secure") td:eq(2)',
}, {
content: 'Answer What do your think about our new eCommerce (I have added products to my wishlist)',
- trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("I have added products to my wishlist") input:last',
+ trigger: 'div.js_question-wrapper:contains("What do your think about our new eCommerce") tr:contains("I have added products to my wishlist") td:last',
}, {
content: 'Answer Do you have any other comments, questions, or concerns',
trigger: 'div.js_question-wrapper:contains("Do you have any other comments, questions, or concerns") textarea',
diff --git a/addons/survey/views/assets.xml b/addons/survey/views/assets.xml
index 07f2d902d5b..b1f3df0a00e 100644
--- a/addons/survey/views/assets.xml
+++ b/addons/survey/views/assets.xml
@@ -10,11 +10,13 @@
<script type="text/javascript" src="/survey/static/src/js/survey_timer.js" />
<script type="text/javascript" src="/survey/static/src/js/survey_breadcrumb.js" />
<script type="text/javascript" src="/survey/static/src/js/survey_form.js" />
+ <script type="text/javascript" src="/survey/static/src/js/survey_print.js" />
<script type="text/javascript" src="/survey/static/src/js/survey_result.js" />
+ <t t-call="web._assets_helpers"/>
<link href="/survey/static/src/css/survey_print.css" rel="stylesheet" type="text/css"/>
<link href="/survey/static/src/css/survey_result.css" rel="stylesheet" type="text/css"></link>
- <link rel="stylesheet" type="text/scss" href="/survey/static/src/scss/survey_templates.scss"/>
+ <link rel="stylesheet" type="text/scss" href="/survey/static/src/scss/survey_form.scss"/>
</template>
<template id="survey_report_assets_pdf" inherit_id="web.report_assets_pdf">
diff --git a/addons/survey/views/survey_survey_views.xml b/addons/survey/views/survey_survey_views.xml
index cc63f536271..9dd428ee87f 100644
--- a/addons/survey/views/survey_survey_views.xml
+++ b/addons/survey/views/survey_survey_views.xml
@@ -42,6 +42,7 @@
</button>
</div>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
+ <field name="background_image" widget="image" class="oe_avatar"/>
<div class="oe_title" style="width: 100%;">
<label for="title" class="oe_edit_only"/>
<h1><field name="title" placeholder="e.g. Satisfaction Survey"/></h1>
@@ -75,6 +76,7 @@
<group name="options">
<group string="Questions" name="questions">
<field name="questions_layout" widget="radio" />
+ <field name="progression_mode" widget="radio" />
<label for="is_time_limited" string="Time Limit"/>
<div>
<field name="is_time_limited" nolabel="1"/>
diff --git a/addons/survey/views/survey_templates.xml b/addons/survey/views/survey_templates.xml
index f80bbdf55f1..f8d1c136fb3 100644
--- a/addons/survey/views/survey_templates.xml
+++ b/addons/survey/views/survey_templates.xml
@@ -3,6 +3,9 @@
<data>
<!-- Main survey layout -->
<template id="survey.layout" name="Survey Layout" inherit_id="web.frontend_layout" primary="True">
+ <xpath expr="//div[@id='wrapwrap']" position="attributes">
+ <attribute name="t-att-style" add="('height: 100%; overflow: auto; background: url(' + '/survey/get_background_image/%s/%s' % (survey.access_token, answer.access_token) + ') no-repeat fixed center; box-shadow: inset 0 0 0 10000px rgba(255,255,255,.7); background-size: cover;') if survey and survey.background_image and answer else 'height: 100%; overflow: auto;'"/>
+ </xpath>
<xpath expr="//head/t[@t-call-assets][last()]" position="after">
<t t-call-assets="survey.survey_assets" lazy_load="True"/>
</xpath>
@@ -17,8 +20,8 @@
<template id="survey_page_fill" name="Survey: main page (take survey)">
<t t-call="survey.layout">
- <div class="wrap">
- <div class="container o_survey_form">
+ <div class="wrap o_survey_wrap mt16 pb16 d-flex">
+ <div class="container o_survey_form d-flex flex-column">
<t t-if="answer.test_entry" t-call="survey.survey_button_form_view" />
<t t-call="survey.survey_fill_header" />
@@ -29,7 +32,7 @@
</template>
<template id="survey_fill_header" name="Survey: main page header">
- <div class="o_page_header o_survey_header">
+ <div class="o_survey_nav pt16 pb24">
<div class="container m-0 p-0">
<div class="row">
<div class="col-lg-8"><h1 t-esc="survey.title"></h1></div>
@@ -38,7 +41,7 @@
</div>
</div>
</div>
- <div t-att-class="'o_survey_breadcrumb_container mt8 bg-200' + (' d-none ' if answer.state != 'in_progress' else '')"
+ <div t-att-class="'o_survey_breadcrumb_container mt8' + (' d-none ' if answer.state != 'in_progress' else '')"
t-if="survey.questions_layout == 'page_per_section' and answer.state != 'done'"
t-att-data-can-go-back="survey.users_can_go_back"
t-att-data-pages="json.dumps(breadcrumb_pages)" />
@@ -48,19 +51,21 @@
<template id="survey_fill_form" name="Survey: main page content">
<t t-set="survey_form_readonly" t-value="false"/>
<form role="form" method="post" t-att-name="survey.id"
+ class="d-flex flex-grow-1 align-items-center"
t-att-data-answer-token="answer.access_token"
t-att-data-survey-token="survey.access_token"
t-att-data-timer="answer.start_datetime.isoformat() if survey.is_time_limited
and answer.start_datetime and answer.state != 'done' else False"
t-att-data-time-limit-minutes="survey.time_limit"
- t-att-data-is-start-screen="answer.state == 'new'">
+ t-att-data-is-start-screen="answer.state == 'new'"
+ t-att-data-questions-layout="survey.questions_layout">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<input type="hidden" name="token" t-att-value="answer.access_token" />
<div class="o_survey_error alert alert-danger d-none" role="alert">
<p>There was an error during the validation of the survey.</p>
</div>
- <div class="o_survey_form_content">
+ <div class="o_survey_form_content w-100">
<t t-if="answer.state == 'new'" t-call="survey.survey_fill_form_start"/>
<t t-elif="answer.state == 'in_progress'" t-call="survey.survey_fill_form_in_progress" />
<t t-else="" t-call="survey.survey_fill_form_done"/>
@@ -83,7 +88,7 @@
</template>
<template id="survey_fill_form_start" name="Survey: start form content">
- <div class="wrap o_survey_start">
+ <div class="wrap o_survey_start pb256">
<div class='mt32 mb32'>
<div t-field='survey.description' class="oe_no_empty"/>
<div t-if="survey.is_time_limited">
@@ -99,7 +104,7 @@
<t t-else="">
Start Survey
</t>
- </button>
+ </button><span class="font-weight-bold ml-2 text-primary d-none d-md-inline">or press Enter</span>
</div>
</div>
</template>
@@ -107,17 +112,18 @@
<template id="survey_fill_form_in_progress" name="Survey: form with questions">
<t t-if="survey.questions_layout == 'one_page'">
<t t-foreach='survey.question_and_page_ids' t-as='question'>
- <h2 t-if="question.is_page" t-field='question.title' class="o_survey_title" />
+ <h2 t-if="question.is_page" t-field='question.title' class="o_survey_title pb16" />
<t t-if="not question.is_page and question in answer.predefined_question_ids" t-call="survey.question_container"/>
</t>
<div class="text-center mt16 mb256">
- <button type="submit" value="finish" class="btn btn-primary">Submit Survey</button>
+ <button type="submit" value="finish" class="btn btn-primary">
+ Submit</button><span class="font-weight-bold ml-2 text-primary d-none d-md-inline">or press Enter</span>
</div>
</t>
<t t-if="survey.questions_layout == 'page_per_section'">
- <h2 t-field='page.title' class="o_survey_title" />
+ <h2 t-field='page.title' class="o_survey_title pb16" />
<div t-field='page.description' class="oe_no_empty"/>
<input type="hidden" name="page_id" t-att-value="page.id" />
@@ -125,12 +131,19 @@
<t t-if="question in answer.predefined_question_ids" t-call="survey.question_container"/>
</t>
- <div class="text-center mt16 mb256">
- <button t-if="survey.users_can_go_back and page != survey.page_ids[0]" type="submit" class="btn btn-secondary"
- name="button_submit" value="previous" t-att-data-previous-page-id="previous_page_id">Previous page</button>
- <button type="submit" t-att-value="'next' if not last else 'finish'" class="btn btn-primary">
- <t t-esc="'Next Page' if not last else 'Submit Survey'"/>
- </button>
+ <div class="row">
+ <div class="offset-3 col-6 text-center mt16 mb128">
+ <button t-if="survey.users_can_go_back and page != survey.page_ids[0]" type="submit" class="btn btn-secondary"
+ name="button_submit" value="previous" t-att-data-previous-page-id="previous_page_id">Back</button>
+ <button type="submit" t-att-value="'next' if not last else 'finish'" class="btn btn-primary">
+ Continue</button><span class="font-weight-bold ml-2 text-primary d-none d-md-inline"> or press Enter</span>
+ </div>
+ <div class="col-3">
+ <t t-call="survey.survey_progression">
+ <t t-set="page_ids" t-value="survey.page_ids.ids"/>
+ <t t-set="page_number" t-value="page_ids.index(page.id) + (1 if survey.progression_mode == 'number' else 0)"/>
+ </t>
+ </div>
</div>
</t>
@@ -138,12 +151,19 @@
<input type="hidden" name="question_id" t-att-value="question.id" />
<t t-call="survey.question_container"/>
- <div class="text-center mt16 mb256">
- <button t-if="survey.users_can_go_back and question != answer.predefined_question_ids[0]" type="submit" class="btn btn-secondary"
- name="button_submit" value="previous" t-att-data-previous-page-id="previous_page_id">Previous page</button>
- <button type="submit" t-att-value="'next' if not last else 'finish'" class="btn btn-primary">
- <t t-esc="'Next Page' if not last else 'Submit Survey'"/>
- </button>
+ <div class="row">
+ <div class="offset-3 col-6 text-center mt16 mb128">
+ <button t-if="survey.users_can_go_back and question != answer.predefined_question_ids[0]" type="submit" class="btn btn-secondary"
+ name="button_submit" value="previous" t-att-data-previous-page-id="previous_page_id">Back</button>
+ <button type="submit" t-att-value="'next' if not last else 'finish'" class="btn btn-primary">
+ Continue</button><span class="font-weight-bold ml-2 text-primary d-none d-md-inline">or press Enter</span>
+ </div>
+ <div class="col-3">
+ <t t-call="survey.survey_progression">
+ <t t-set="page_ids" t-value="survey.question_ids.ids"/>
+ <t t-set="page_number" t-value="page_ids.index(question.id)"/>
+ </t>
+ </div>
</div>
</t>
</template>
@@ -151,7 +171,7 @@
<!-- Finished (taken and finished) survey page -->
<template id="survey_fill_form_done" name="Survey: finished">
<div class="wrap">
- <div class="o_survey_finished mt32 mb32">
+ <div class="o_survey_finished mt32 mb32 pb256">
<h1>Thank you!</h1>
<div t-field="survey.description_done" class="oe_no_empty" />
<div class="row">
@@ -204,7 +224,10 @@
<!-- Question widgets -->
<template id="question_container" name="Survey: question container">
<t t-set="answer_lines" t-value="answer.user_input_line_ids.filtered(lambda line: line.question_id == question)"/>
- <div class="js_question-wrapper" t-att-id="question.id" t-att-data-required="question.constr_mandatory"
+ <!--Use Key selection if number of choices is < 26 to keep Z for other choice if any-->
+ <t t-set="letters" t-value="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
+ <t t-set="useKeySelection" t-value="len(question.suggested_answer_ids) &lt; len(letters) and survey.questions_layout == 'page_per_question'"/>
+ <div class="js_question-wrapper pb-4" t-att-id="question.id" t-att-data-required="question.constr_mandatory"
t-att-data-constr-error-msg="question.constr_error_msg"
t-att-data-validation-error-msg="question.validation_error_msg">
<h4>
@@ -220,26 +243,30 @@
<t t-if="question.question_type == 'simple_choice'"><t t-call="survey.question_simple_choice"/></t>
<t t-if="question.question_type == 'multiple_choice'"><t t-call="survey.question_multiple_choice"/></t>
<t t-if="question.question_type == 'matrix'"><t t-call="survey.question_matrix"/></t>
- <div class="o_survey_question_error alert alert-danger" role="alert"></div>
+ <div class="o_survey_question_error overflow-hidden border-0 py-0 px-3 alert alert-danger" role="alert"></div>
</div>
</template>
<template id="question_text_box" name="Question: free text box">
- <textarea class="form-control o_survey_question_text_box" rows="3" t-att-name="question.id"
- t-att-data-question-type="question.question_type"><t t-if="answer_lines" t-esc="answer_lines[0].value_text_box or None"/></textarea>
+ <div class="o_survey_comment_container py-0 px-1">
+ <textarea class="form-control o_survey_question_text_box font-weight-bold bg-transparent text-primary rounded-0" rows="3" t-att-name="question.id"
+ t-att-data-question-type="question.question_type"><t t-if="answer_lines" t-esc="answer_lines[0].value_text_box or None"/></textarea>
+ </div>
</template>
<template id="question_char_box" name="Question: text box">
- <input t-att-type="'email' if question.validation_email else 'text'"
- class="form-control o_survey_question_text_box" t-att-name="question.id"
+ <div class="o_survey_comment_container py-0 px-1">
+ <input t-att-type="'email' if question.validation_email else 'text'"
+ class="form-control o_survey_question_text_box font-weight-bold bg-transparent text-primary rounded-0" t-att-name="question.id"
t-att-value="answer_lines[0].value_char_box if answer_lines else None"
t-att-data-question-type="question.question_type"
t-att-data-validation-length-min="question.validation_length_min if question.validation_required else False"
t-att-data-validation-length-max="question.validation_length_max if question.validation_required else False"/>
+ </div>
</template>
<template id="question_numerical_box" name="Question: numerical box">
- <input type="number" step="any" class="form-control o_survey_question_numerical_box" t-att-name="question.id" t-att-value="answer_lines[0].value_numerical_box if answer_lines else None"
+ <input type="number" step="any" class="form-control o_survey_question_numerical_box font-weight-bold bg-transparent text-primary rounded-0" t-att-name="question.id" t-att-value="answer_lines[0].value_numerical_box if answer_lines else None"
t-att-data-question-type="question.question_type"
t-att-data-validation-float-min="question.validation_min_float_value if question.validation_required else False"
t-att-data-validation-float-max="question.validation_max_float_value if question.validation_required else False"/>
@@ -249,12 +276,12 @@
<div class="input-group o_survey_form_date" t-attf-id="datetimepicker_#{question.id}" data-target-input="nearest"
t-att-data-mindate="question.validation_min_date"
t-att-data-maxdate="question.validation_max_date">
- <input type="text" class="form-control datetimepicker-input o_survey_question_date"
+ <input type="text" class="form-control datetimepicker-input o_survey_question_date font-weight-bold bg-transparent text-primary rounded-0"
t-attf-data-target="#datetimepicker_#{question.id}" t-att-name="question.id"
t-att-value="format_date(answer_lines[0].value_date) if answer_lines else None"
t-att-data-question-type="question.question_type"/>
- <div t-if="not survey_form_readonly" class="input-group-append" t-attf-data-target="#datetimepicker_#{question.id}" data-toggle="datetimepicker">
- <div class="input-group-text"><i class="fa fa-calendar"></i></div>
+ <div t-if="not survey_form_readonly" class="input-group-append position-absolute" t-attf-data-target="#datetimepicker_#{question.id}" data-toggle="datetimepicker">
+ <div class="input-group-text text-primary border-0 bg-transparent"><i class="fa fa-calendar"></i></div>
</div>
</div>
</template>
@@ -263,12 +290,12 @@
<div class="input-group o_survey_form_date" t-attf-id="datetimepicker_#{question.id}" data-target-input="nearest"
t-att-data-mindate="question.validation_min_datetime"
t-att-data-maxdate="question.validation_max_datetime">
- <input type="text" class="form-control datetimepicker-input o_survey_question_datetime"
+ <input type="text" class="form-control datetimepicker-input o_survey_question_datetime font-weight-bold bg-transparent text-primary rounded-0"
t-attf-data-target="#datetimepicker_#{question.id}" t-att-name="question.id"
t-att-value="format_datetime(answer_lines[0].value_datetime) if answer_lines else None"
t-att-data-question-type="question.question_type"/>
- <div t-if="not survey_form_readonly" class="input-group-append" t-attf-data-target="#datetimepicker_#{question.id}" data-toggle="datetimepicker">
- <div class="input-group-text"><i class="fa fa-calendar"></i></div>
+ <div t-if="not survey_form_readonly" class="input-group-append position-absolute" t-attf-data-target="#datetimepicker_#{question.id}" data-toggle="datetimepicker">
+ <div class="input-group-text text-primary border-0 bg-transparent"><i class="fa fa-calendar"></i></div>
</div>
</div>
</template>
@@ -279,27 +306,58 @@
<div class="row o_survey_form_choice"
t-att-data-name="question.id"
data-question-type="simple_choice_radio">
- <div t-foreach='question.suggested_answer_ids' t-as='label' t-attf-class="col-lg-#{question.column_nb}">
- <label t-att-class="' bg-success ' if quizz_correction and label.answer_score > 0.0 else None">
- <input type="radio" t-att-value='label.id' class="o_survey_form_choice_item"
- t-att-name='question.id'
- t-att-checked="answer_line and answer_line.suggested_answer_id.id == label.id and 'checked' or None"/>
- <span t-field='label.value'/>
- </label>
+ <t t-set="item_idx" t-value="0"/>
+ <div class="d-flex flex-wrap font-weight-bold col-lg-12">
+ <t t-set="has_correct_answer" t-value="scoring_display_correction and any(label.is_correct for label in question.suggested_answer_ids)"/>
+ <t t-foreach='question.suggested_answer_ids' t-as='label'>
+ <t t-set="item_idx" t-value="label_index"/>
+ <t t-set="answer_selected" t-value="answer_line and answer_line.suggested_answer_id.id == label.id"/>
+ <t t-set="is_correct" t-value="label.answer_score > 0.0"/>
+
+ <!--Used for print mode with corrections -->
+ <t t-set="answer_class" t-if="not has_correct_answer" t-value="''" />
+ <t t-set="answer_class" t-elif="is_correct" t-value="'bg-success'" />
+ <t t-set="answer_class" t-elif="not is_correct" t-value="'bg-danger'" />
+
+ <label t-att-for="str(question.id) + '_' + str(label.id)"
+ t-att-class="'o_survey_choice_btn m-1 py-1 px-3 text-white rounded %s %s' % (answer_class, 'o_survey_selected' if answer_selected else '')">
+ <t t-call="survey.survey_selection_key">
+ <t t-set="selection_key_class" t-value="'o_survey_radio_btn float-left d-flex'"/>
+ </t>
+ <span class="ml-2" t-field='label.value'/>
+ <input t-att-id="str(question.id) + '_' + str(label.id)" type="radio" t-att-value='label.id' class="o_survey_form_choice_item invisible position-absolute"
+ t-att-name='question.id'
+ t-att-checked="answer_line and answer_line.suggested_answer_id.id == label.id and 'checked' or None"
+ t-att-data-selection-key="letters[item_idx] if useKeySelection else ''"/>
+ <i class="fa fa-check-circle float-right mt-1 position-relative"></i>
+ <i class="fa fa-circle float-right mt-1 position-relative"></i>
+ </label>
+ </t>
</div>
<div t-if='question.comments_allowed and question.comment_count_as_answer' class="js_comments col-lg-12" >
- <label>
- <input type="radio" class="o_survey_form_choice_item o_survey_js_form_other_comment" value="-1"
- t-att-name='question.id'
- t-att-checked="comment_line and 'checked' or None"/>
- <span t-field="question.comments_message" />
- </label>
- <textarea type="text" class="form-control"
- t-attf-disabled="#{'' if comment_line else 'disabled'}"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
+ <div class="d-flex flex-wrap font-weight-bold">
+ <label t-att-class="'o_survey_choice_btn m-1 py-1 px-3 text-white rounded %s' % ('o_survey_selected' if comment_line else '')">
+ <t t-set="item_idx" t-value="item_idx + 1"/>
+ <t t-call="survey.survey_selection_key">
+ <t t-set="selection_key_class" t-value="'o_survey_radio_btn float-left d-flex'"/>
+ </t>
+ <input type="radio" class="o_survey_form_choice_item o_survey_js_form_other_comment invisible position-absolute" value="-1"
+ t-att-name='question.id'
+ t-att-checked="comment_line and 'checked' or None"
+ t-att-data-selection-key="letters[item_idx] if useKeySelection else ''"/>
+ <span class="ml-2" t-field="question.comments_message" />
+ <i class="fa fa-check-circle float-right mt-1 position-relative"></i>
+ <i class="fa fa-circle float-right mt-1 position-relative"></i>
+ </label>
+ </div>
+ <div class="o_survey_comment_container py-0 px-1">
+ <textarea type="text" class="form-control o_survey_question_text_box font-weight-bold bg-transparent text-primary rounded-0"
+ t-att-disabled="None if comment_line else 'disabled'"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
+ </div>
</div>
- <div t-if='question.comments_allowed and not question.comment_count_as_answer' class="col-lg-12">
- <span t-field="question.comments_message"/>
- <textarea type="text" class="form-control o_survey_comment"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
+ <div t-if='question.comments_allowed and not question.comment_count_as_answer' class="col-lg-12 o_survey_comment_container mx-1 py-0 pl-3 pr-4">
+ <textarea type="text" class="form-control o_survey_comment o_survey_question_text_box font-weight-bold bg-transparent text-primary rounded-0"
+ t-att-placeholder="question.comments_message"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
</div>
</div>
</template>
@@ -309,61 +367,132 @@
<div class="row o_survey_form_choice o_survey_question_multiple_choice"
t-att-data-name="question.id"
t-att-data-question-type="question.question_type">
- <div t-foreach='question.suggested_answer_ids' t-as='label' t-attf-class="col-lg-#{question.column_nb}">
- <t t-set="answer_line" t-value="answer_lines.filtered(lambda line: line.suggested_answer_id == label)"/>
- <label t-att-class="' bg-success ' if quizz_correction and label.answer_score > 0.0 else None">
- <input type="checkbox" t-att-value='label.id' class="o_survey_form_choice_item"
- t-att-name="question.id"
- t-att-checked="'checked' if answer_line else None"/>
- <span t-field='label.value'/>
- </label>
- </div>
+ <t t-set="item_idx" t-value="0"/>
+ <div class="d-flex flex-wrap font-weight-bold col-lg-12">
+ <t t-set="has_correct_answer" t-value="scoring_display_correction and any(label.is_correct for label in question.suggested_answer_ids)"/>
+ <t t-foreach='question.suggested_answer_ids' t-as='label'>
+ <t t-set="item_idx" t-value="label_index"/>
+ <t t-set="answer_line" t-value="answer_lines.filtered(lambda line: line.suggested_answer_id == label)"/>
+ <t t-set="answer_selected" t-value="answer_line and answer_line.suggested_answer_id.id == label.id"/>
+ <t t-set="is_correct" t-value="label.answer_score > 0.0"/>
+
+ <!--Used for print mode with corrections -->
+ <t t-set="answer_class" t-if="not has_correct_answer" t-value="''" />
+ <t t-set="answer_class" t-elif="is_correct" t-value="'bg-success'" />
+ <t t-set="answer_class" t-elif="not is_correct" t-value="'bg-danger'" />
+ <label t-att-class="'o_survey_choice_btn m-1 py-1 px-3 text-white rounded %s %s' % (answer_class, 'o_survey_selected' if answer_line else '')">
+ <t t-call="survey.survey_selection_key">
+ <t t-set="selection_key_class" t-value="'float-left d-flex'"/>
+ </t>
+ <input type="checkbox" t-att-value='label.id' class="o_survey_form_choice_item invisible position-absolute"
+ t-att-name="question.id"
+ t-att-checked="'checked' if answer_line else None"
+ t-att-data-selection-key="letters[item_idx] if useKeySelection else ''"/>
+ <span class="ml-2" t-field='label.value'/>
+ <i class="fa fa-check-square float-right mt-1 position-relative"></i>
+ <i class="fa fa-square float-right mt-1 position-relative"></i>
+ </label>
+ </t>
+ </div>
<div t-if='question.comments_allowed and question.comment_count_as_answer' class="js_ck_comments col-lg-12" >
- <label>
- <input type="checkbox" class="o_survey_form_choice_item o_survey_js_form_other_comment" value="-1"
- t-att-name="question.id"
- t-att-checked="comment_line and 'checked' or None"/>
- <span t-field="question.comments_message" />
- </label>
- <textarea type="text" class="form-control"
- t-attf-disabled="#{'' if comment_line else 'disabled'}"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
+ <div class="d-flex flex-wrap font-weight-bold">
+ <label t-att-class="'o_survey_choice_btn m-1 py-1 px-3 text-white rounded %s' % ('o_survey_selected' if comment_line else '')">
+ <t t-set="item_idx" t-value="item_idx + 1"/>
+ <t t-call="survey.survey_selection_key">
+ <t t-set="selection_key_class" t-value="'float-left d-flex'"/>
+ </t>
+ <input type="checkbox" class="o_survey_form_choice_item o_survey_js_form_other_comment invisible position-absolute" value="-1"
+ t-att-name="question.id"
+ t-att-checked="comment_line and 'checked' or None"
+ t-att-data-selection-key="letters[item_idx] if useKeySelection else ''"/>
+ <span class="ml-2" t-field="question.comments_message" />
+ <i class="fa fa-check-square float-right mt-1 position-relative"></i>
+ <i class="fa fa-square float-right mt-1 position-relative"></i>
+ </label>
+ </div>
+ <div class="o_survey_comment_container py-0 px-1">
+ <textarea type="text" class="form-control o_survey_question_text_box font-weight-bold bg-transparent text-primary rounded-0"
+ t-att-disabled="None if comment_line else 'disabled'"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
+ </div>
</div>
- <div t-if='question.comments_allowed and not question.comment_count_as_answer' class="col-lg-12">
- <span t-field="question.comments_message"/>
- <textarea type="text" class="form-control o_survey_comment"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
+ <div t-if='question.comments_allowed and not question.comment_count_as_answer' class="col-lg-12 o_survey_comment_container mx-1 py-0 pl-3 pr-4">
+ <textarea type="text" class="form-control o_survey_comment o_survey_question_text_box font-weight-bold bg-transparent text-primary rounded-0"
+ t-att-placeholder="question.comments_message"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
</div>
</div>
</template>
<template id="question_matrix" name="Question: matrix">
<t t-set="comment_line" t-value="answer_lines.filtered(lambda line: line.value_char_box)"/>
- <table class="table table-hover o_survey_question_matrix"
+ <table class="table table-hover o_survey_question_matrix text-white text-center mb-0"
t-att-data-name="question.id"
t-att-data-question-type="question.question_type"
t-att-data-sub-questions="question.matrix_row_ids.ids">
<thead>
<tr>
- <th> </th>
- <th t-foreach="question.suggested_answer_ids" t-as="col_label"><span t-field="col_label.value" /></th>
+ <th class="border-0"> </th>
+ <th class="border-0" t-foreach="question.suggested_answer_ids" t-as="col_label"><span t-field="col_label.value" /></th>
</tr>
</thead>
<tbody>
- <tr t-foreach="question.matrix_row_ids" t-as="row_label">
- <th><span t-field="row_label.value" /></th>
- <td t-foreach="question.suggested_answer_ids" t-as="col_label">
+ <t t-set="item_idx" t-value="0"/>
+ <tr class="bg-white text-white" t-foreach="question.matrix_row_ids" t-as="row_label">
+ <th class="border-0"><span t-field="row_label.value" /></th>
+ <t t-foreach="question.suggested_answer_ids" t-as="col_label">
<t t-set="answer" t-value="answer_lines.filtered(lambda line: line.suggested_answer_id == col_label and line.matrix_row_id == row_label)"/>
- <input t-att-type="'checkbox' if question.matrix_subtype == 'multiple' else 'radio'"
- t-att-name="'%s_%s' % (question.id, row_label.id)" t-att-value='col_label.id'
- t-att-checked="'checked' if answer else None"
- t-att-data-row-id="row_label.id"/>
- </td>
+ <td t-att-class="'o_survey_matrix_btn text-primary border-0 %s'
+ % ('o_survey_selected' if answer else '')">
+ <input t-att-type="'checkbox' if question.matrix_subtype == 'multiple' else 'radio'"
+ t-att-name="'%s_%s' % (question.id, row_label.id)" t-att-value='col_label.id'
+ t-att-checked="'checked' if answer else None"
+ t-att-data-row-id="row_label.id"
+ t-att-data-selection-key="letters[item_idx] if useKeySelection else ''"
+ class="o_survey_form_choice_item d-none"/>
+ <i t-att-class="'o_survey_matrix_empty_checkbox fa fa-%s position-relative'
+ % ('square-o' if question.matrix_subtype == 'multiple' else 'circle-thin')"></i>
+ <i t-att-class="'fa fa-check-%s position-relative'
+ % ('square' if question.matrix_subtype == 'multiple' else 'circle')"></i>
+ <t t-call="survey.survey_selection_key">
+ <t t-set="selection_key_class"
+ t-value="'float-right font-weight-bold %s' % ('o_survey_radio_btn' if question.matrix_subtype != 'multiple' else '')"/>
+ </t>
+ <t t-set="item_idx" t-value="item_idx + 1"/>
+ </td>
+ </t>
</tr>
</tbody>
</table>
<div t-if='question.comments_allowed'>
- <span t-field="question.comments_message"/>
- <textarea type="text" class="form-control" t-att-name="'%s_%s' % (question.id, 'comment')"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
+ <textarea type="text" class="form-control o_survey_question_text_box o_survey_comment font-weight-bold bg-transparent text-primary rounded-0"
+ t-att-placeholder="question.comments_message"
+ t-att-name="'%s_%s' % (question.id, 'comment')"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
+ </div>
+ </template>
+
+ <template id="survey_selection_key">
+ <div t-if="useKeySelection" t-att-class="'o_survey_choice_key bg-white position-relative rounded %s' % selection_key_class">
+ <span class="o_survey_key text-center position-absolute bg-white rounded-left py-0 pr-4 pl-2"><span class="text-primary text-center text-center w-100 position-relative">Key</span></span>
+ <span class="text-primary text-center w-100 position-relative" t-esc="letters[item_idx]"/>
+ </div>
+ </template>
+
+ <template id="survey_progression" name="Survey: Progression">
+ <div class="float-right">
+ <t t-if="len(page_ids) > 1">
+ <t t-set="percentage" t-value="round(100*(page_number/len(page_ids)))"/>
+ <t t-if="survey.progression_mode == 'percent'">
+ <span class="o_survey_progress_percent" t-esc="percentage"/> % completed
+ </t>
+ <t t-else="">
+ <span class="o_survey_progress_number" t-esc="page_number"/> of <span t-esc="len(page_ids)"/>
+ <span t-if="survey.questions_layout == 'page_per_question'">answered</span>
+ <span t-else="">pages</span>
+ </t>
+ <div class="o_survey_progress progress flex-grow-1">
+ <div class="progress-bar bg-primary" t-att-style="'width: ' + str(percentage) + '%'"/>
+ </div>
+ </t>
</div>
</template>
</data>
diff --git a/addons/survey/views/survey_templates_management.xml b/addons/survey/views/survey_templates_management.xml
index 7f843717f08..0e1dbaaab2e 100644
--- a/addons/survey/views/survey_templates_management.xml
+++ b/addons/survey/views/survey_templates_management.xml
@@ -74,7 +74,7 @@
<!-- ============================================================ -->
<template id="survey_button_form_view" name="Survey: back to form view">
- <div groups="survey.group_survey_manager" t-ignore="true" class="alert alert-info alert-dismissible rounded-0 mt16 fade show d-print-none css_editable_mode_hidden">
+ <div groups="survey.group_survey_manager" t-ignore="true" class="alert alert-info alert-dismissible rounded-0 fade show d-print-none css_editable_mode_hidden">
<div t-ignore="true" class="text-center">
<a t-attf-href="/web#view_type=form&amp;model=survey.survey&amp;id=#{survey.id}&amp;action=survey.action_survey_form"><i class="fa fa-fw fa-arrow-right"/><span t-if="answer and answer.test_entry">This is a test survey. </span>Edit Survey.</a>
</div>
diff --git a/addons/survey/views/survey_templates_print.xml b/addons/survey/views/survey_templates_print.xml
index 733e0fa995b..d06947c2e20 100644
--- a/addons/survey/views/survey_templates_print.xml
+++ b/addons/survey/views/survey_templates_print.xml
@@ -6,7 +6,7 @@
<t t-call="survey.layout">
<t t-set="survey_form_readonly" t-value="true"/>
<div class="wrap">
- <div class="container">
+ <div class="o_survey_print container">
<t t-if="answer.test_entry" t-call="survey.survey_button_form_view" />
<div class='jumbotron mt32'>
<h1><span t-field='survey.title'/></h1>
@@ -27,7 +27,7 @@
<h2>
<span t-field='question.title'/>
<span t-if="question.constr_mandatory" class="text-danger">*</span>
- <span t-if="quizz_correction" class="badge badge-pill" t-att-data-score-question="question.id"></span>
+ <span t-if="scoring_display_correction" class="badge badge-pill" t-att-data-score-question="question.id"></span>
</h2>
<t t-if="question.description"><div class="text-muted oe_no_empty" t-field='question.description'/></t>
<t t-if="question.question_type == 'text_box'"><t t-call="survey.question_text_box"/></t>
@@ -38,7 +38,7 @@
<t t-if="question.question_type == 'simple_choice'"><t t-call="survey.question_simple_choice"/></t>
<t t-if="question.question_type == 'multiple_choice'"><t t-call="survey.question_multiple_choice"/></t>
<t t-if="question.question_type == 'matrix'"><t t-call="survey.question_matrix"/></t>
- <div class="o_survey_question_error alert alert-danger" role="alert"></div>
+ <div class="o_survey_question_error overflow-hidden border-0 py-0 px-3 alert alert-danger" role="alert"></div>
</div>
</t>
</t>
diff --git a/addons/test_website_slides_full/tests/tours/slides_certification_member.js b/addons/test_website_slides_full/tests/tours/slides_certification_member.js
index c10ec4ac898..eec5f0b7aaf 100644
--- a/addons/test_website_slides_full/tests/tours/slides_certification_member.js
+++ b/addons/test_website_slides_full/tests/tours/slides_certification_member.js
@@ -89,16 +89,16 @@ var failCertificationSteps = [{
trigger: 'button:contains("Start Certification")'
}, { // Question: What type of wood is the best for furniture?
content: 'Survey: selecting answer "Fir"',
- trigger: 'div.js_question-wrapper:contains("What type of wood is the best for furniture") label:contains("Fir") input',
+ trigger: 'div.js_question-wrapper:contains("What type of wood is the best for furniture") label:contains("Fir")'
}, { // Question: Select all the furniture shown in the video
content: 'Survey: ticking answer "Table"',
- trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Table") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Table")'
}, {
content: 'Survey: ticking answer "Bed"',
- trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Bed") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Bed")'
}, {
content: 'Survey: submitting the certification with wrong answers',
- trigger: 'button:contains("Submit Survey")'
+ trigger: 'button:contains("Submit")'
}];
var retrySteps = [{
@@ -111,19 +111,19 @@ var succeedCertificationSteps = [{
trigger: 'button:contains("Start Certification")'
}, { // Question: What type of wood is the best for furniture?
content: 'Survey: selecting answer "Oak"',
- trigger: 'div.js_question-wrapper:contains("What type of wood is the best for furniture") label:contains("Oak") input',
+ trigger: 'div.js_question-wrapper:contains("What type of wood is the best for furniture") label:contains("Oak")',
}, { // Question: Select all the furniture shown in the video
content: 'Survey: ticking answer "Chair"',
- trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Chair") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Chair")'
}, {
content: 'Survey: ticking answer "Shelve"',
- trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Shelve") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Shelve")'
}, {
content: 'Survey: ticking answer "Desk"',
- trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Desk") input'
+ trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Desk")'
}, {
content: 'Survey: submitting the certification with correct answers',
- trigger: 'button:contains("Submit Survey")'
+ trigger: 'button:contains("Submit")'
}];
var certificationCompletionSteps = [{