summaryrefslogtreecommitdiff
path: root/addons/survey/static/src/js/survey_form.js
diff options
context:
space:
mode:
authorDavid Beguin <dbe@odoo.com>2019-12-10 12:30:21 +0000
committerDavid Beguin <dbe@odoo.com>2020-01-17 16:04:17 +0000
commitaedeccbeeaafe87ec0f80228a05b45dbc7140f72 (patch)
tree08cbc6b22e04a1165928d3f7a8d3cb3731616ec6 /addons/survey/static/src/js/survey_form.js
parent860768b79bd710e97d51fc2ee992eeb41a6dcf96 (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/js/survey_form.js')
-rw-r--r--addons/survey/static/src/js/survey_form.js115
1 files changed, 110 insertions, 5 deletions
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);
},