diff options
| author | David Beguin <dbe@odoo.com> | 2019-12-10 12:30:21 +0000 |
|---|---|---|
| committer | David Beguin <dbe@odoo.com> | 2020-01-17 16:04:17 +0000 |
| commit | aedeccbeeaafe87ec0f80228a05b45dbc7140f72 (patch) | |
| tree | 08cbc6b22e04a1165928d3f7a8d3cb3731616ec6 /addons/survey/static/src | |
| parent | 860768b79bd710e97d51fc2ee992eeb41a6dcf96 (diff) | |
[IMP] survey : redesign frontend layout
In this commit, all the questions type have been redesigned to look more fancy.
(impacted question types : radio and checkboxes, text boxes (textarea and text
inputs, date and datetime inputs and matrix)
For radio and checkboxes, both design have been aligned to work the same way
(except checkboxes can still have more than one selected option).
Selection by key have been applied on those two question types if the number of
option is under 26 (to use all the alphabeat character for selection). This
selection by key is only available on page per question layout.
Tests have been adapted accordingly to the redesign (typically for choice and
matrix inputs)
* Progress Bar
This commit adds a progress bar to the survey to inform the user
where he is in the survey filling process.
There are two progress modes:
- Number : will display the number of the current page on the total number
of pages (or questions if layout mode is question_per_page)
- Percentage : will display the percentage of page or question already done
So this leads to, on last page:
- in Number mode :
the progress bar div is 100% filled 3 / 3 pages [===]
- in percentage mode :
the progress bar is aligned to percentage 66% completed [== ]
* Print Widget
A widget is added for survey print mode in order to resize all textarea to fit
their content, instead of showing a scroll bar. This can be usefull if user
wants to print the results. He will get the entire content of the 'textarea
answers' instead of only the two first lines.
* Misc
This commit also :
- adds background image to survey.
- redo quizz correction and add some data to illustrate non scored
questions rendering in print template
- review breadcrumb style
Note : readonly data option on survey form widget is not set anywhere yet but
the usage is done in prevention of the future work on presenter view for survey
session mode.
Task ID: '2150291'
PR #43237
Diffstat (limited to 'addons/survey/static/src')
| -rw-r--r-- | addons/survey/static/src/img/survey_background.jpg | bin | 0 -> 166837 bytes | |||
| -rw-r--r-- | addons/survey/static/src/img/survey_background_2.jpg | bin | 0 -> 86252 bytes | |||
| -rw-r--r-- | addons/survey/static/src/js/survey_form.js | 115 | ||||
| -rw-r--r-- | addons/survey/static/src/js/survey_print.js | 31 | ||||
| -rw-r--r-- | addons/survey/static/src/scss/survey_form.scss | 193 | ||||
| -rw-r--r-- | addons/survey/static/src/scss/survey_templates.scss | 28 | ||||
| -rw-r--r-- | addons/survey/static/src/xml/survey_breadcrumb_templates.xml | 10 |
7 files changed, 340 insertions, 37 deletions
diff --git a/addons/survey/static/src/img/survey_background.jpg b/addons/survey/static/src/img/survey_background.jpg Binary files differnew file mode 100644 index 00000000000..ba7c4f0263a --- /dev/null +++ b/addons/survey/static/src/img/survey_background.jpg diff --git a/addons/survey/static/src/img/survey_background_2.jpg b/addons/survey/static/src/img/survey_background_2.jpg Binary files differnew file mode 100644 index 00000000000..b2e076ed2ba --- /dev/null +++ b/addons/survey/static/src/img/survey_background_2.jpg 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> |
