From 7b0df05706ef83ea84badec60527e76015a05fb4 Mon Sep 17 00:00:00 2001 From: Patrick Hoste Date: Wed, 4 Dec 2019 10:54:40 +0000 Subject: [PATCH] [MOV/REF] website_slides: move quiz finish modal to its own dialog widget This commit moves the finished quiz modal into a dedicated dialog widget. It will lessen the "slide_course_quiz.js" code length and simplify the dialog template. Task ID : 2126621 PR : #40801 Signed-off-by: Thibault Delavallee (tde) --- .../static/src/js/slides_course_quiz.js | 122 +------------- .../src/js/slides_course_quiz_finish.js | 158 ++++++++++++++++++ .../static/src/scss/website_slides.scss | 8 + .../static/src/xml/slide_quiz.xml | 79 ++++----- addons/website_slides/views/assets.xml | 1 + 5 files changed, 209 insertions(+), 159 deletions(-) create mode 100644 addons/website_slides/static/src/js/slides_course_quiz_finish.js diff --git a/addons/website_slides/static/src/js/slides_course_quiz.js b/addons/website_slides/static/src/js/slides_course_quiz.js index 8842955e60f..ae0d6236512 100644 --- a/addons/website_slides/static/src/js/slides_course_quiz.js +++ b/addons/website_slides/static/src/js/slides_course_quiz.js @@ -8,6 +8,7 @@ odoo.define('website_slides.quiz', function (require) { var CourseJoinWidget = require('website_slides.course.join.widget').courseJoinWidget; var QuestionFormWidget = require('website_slides.quiz.question.form'); + var SlideQuizFinishModal = require('website_slides.quiz.finish'); var QWeb = core.qweb; var _t = core._t; @@ -243,118 +244,6 @@ odoo.define('website_slides.quiz', function (require) { }); }, - /** - * @private - * When the quiz is done and succeed, a congratulation modal appears. - */ - _renderSuccessModal: function () { - var $modal = this.$('#slides_quiz_modal'); - if (!$modal.length) { - this.$el.append(QWeb.render('slide.slide.quiz.finish', {'widget': this})); - $modal = this.$('#slides_quiz_modal'); - } - var self = this; - $modal.on('shown.bs.modal', function () { - var rankProgress = self.quiz.rankProgress; - self._animateText($modal, rankProgress); - self._animateProgressBar($modal, rankProgress); - }); - $modal.modal({ - 'show': true, - }); - $modal.on('hidden.bs.modal', function () { - $modal.remove(); - }); - }, - - /** - * Handles the animation of the karma gain in the following steps: - * 1. Initiate the tooltip which will display the actual Karma - * over the progress bar. - * 2. Animate the tooltip text to increment smoothly from the old - * karma value to the new karma value and updates it to make it - * move as the progress bar moves. - * 3a. The user doesn't level up - * I. When the user doesn't level up the progress bar simply goes - * from the old karma value to the new karma value. - * 3b. The user levels up - * I. The first step makes the progress bar go from the old karma - * value to 100%. - * II. The second step makes the progress bar go from 100% to 0%. - * III. The third and final step makes the progress bar go from 0% - * to the new karma value. It also changes the lower and upper - * bound to match the new rank. - * @param $modal - * @param rankProgress - * @private - */ - _animateProgressBar: function ($modal, rankProgress) { - var self = this; - - this.$('[data-toggle="tooltip"]').tooltip({ - trigger: 'manual', - container: '.progress-bar-tooltip', - }).tooltip('show'); - - $modal.find('.tooltip-inner') - .prop('karma', rankProgress.previous_rank.karma) - .animate({ - karma: rankProgress.new_rank.karma - }, { - duration: rankProgress.level_up ? 1700 : 800, - step: function (newKarma) { - $modal.find('.tooltip-inner').text(Math.ceil(newKarma)); - self.$('[data-toggle="tooltip"]').tooltip('update'); - } - } - ); - - var $progressBar = $modal.find('.progress-bar'); - if (rankProgress.level_up) { - $modal.find('.o_wslides_quiz_modal_title').text(_('Level up!')); - $progressBar.css('width', '100%'); - _.delay(function () { - $modal.find('.o_wslides_quiz_modal_rank_lower_bound') - .text(rankProgress.new_rank.lower_bound); - $modal.find('.o_wslides_quiz_modal_rank_upper_bound') - .text(rankProgress.new_rank.upper_bound || ""); - - // we need to use _.delay to force DOM re-rendering between 0 and new percentage - _.delay(function () { - $progressBar.addClass('no-transition').width('0%'); - }, 1); - _.delay(function () { - $progressBar - .removeClass('no-transition') - .width(rankProgress.new_rank.progress + '%'); - }, 100); - }, 800); - } else { - $progressBar.css('width', rankProgress.new_rank.progress + '%'); - } - }, - - _animateText: function ($modal, rankProgress) { - _.delay(function () { - $modal.find('h4.o_wslides_quiz_modal_xp_gained').addClass('show in'); - $modal.find('.o_wslides_quiz_modal_dismiss').removeClass('d-none'); - }, 800); - - if (rankProgress.level_up) { - _.delay(function () { - $modal.find('.o_wslides_quiz_modal_rank_motivational').addClass('fade'); - _.delay(function () { - $modal.find('.o_wslides_quiz_modal_rank_motivational').html( - rankProgress.last_rank ? - rankProgress.description : - rankProgress.new_rank.motivational - ); - $modal.find('.o_wslides_quiz_modal_rank_motivational').addClass('show in'); - }, 800); - }, 800); - } - }, - /* * @private * Update validation box (karma, buttons) according to widget state @@ -384,7 +273,11 @@ odoo.define('website_slides.quiz', function (require) { } else { self.quiz = _.extend(self.quiz, data); if (data.completed) { - self._renderSuccessModal(data); + new SlideQuizFinishModal(self, { + quiz: self.quiz, + hasNext: self.slide.hasNext, + userId: self.userId + }).open(); self.slide.completed = true; self.trigger_up('slide_completed', {slide: self.slide, completion: data.channel_completion}); } @@ -454,9 +347,6 @@ odoo.define('website_slides.quiz', function (require) { */ _onClickNext: function (ev) { if (this.slide.hasNext) { - if (this.$('#slides_quiz_modal').length !== 0) { - this.$('#slides_quiz_modal').modal('hide'); - } this.trigger_up('slide_go_next'); } }, diff --git a/addons/website_slides/static/src/js/slides_course_quiz_finish.js b/addons/website_slides/static/src/js/slides_course_quiz_finish.js new file mode 100644 index 00000000000..a20d558e368 --- /dev/null +++ b/addons/website_slides/static/src/js/slides_course_quiz_finish.js @@ -0,0 +1,158 @@ +odoo.define('website_slides.quiz.finish', function (require) { +'use strict'; + +var Dialog = require('web.Dialog'); +var core = require('web.core'); +var _t = core._t; + +/** + * This modal is used when the user finishes the quiz. + * It handles the animation of karma gain and leveling up by animating + * the progress bar and the text. + */ +var SlideQuizFinishModal = Dialog.extend({ + template: 'slide.slide.quiz.finish', + events: { + "click .o_wslides_quiz_modal_btn": '_onClickNext', + }, + + init: function(parent, options) { + var self = this; + this.quiz = options.quiz; + this.hasNext = options.hasNext; + this.userId = options.userId; + options = _.defaults(options || {}, { + size: 'medium', + dialogClass: 'd-flex p-0', + $parentNode: parent.$el, + technical: false, + renderHeader: false, + renderFooter: false + }); + this._super.apply(this, arguments); + this.opened(function () { + self._animateProgressBar(); + self._animateText(); + }) + }, + + start: function() { + var self = this; + this._super.apply(this, arguments).then(function () { + self.$modal.addClass('o_wslides_quiz_modal pt-5'); + self.$modal.find('.modal-dialog').addClass('mt-5'); + self.$modal.find('.modal-content').addClass('shadow-lg'); + }); + }, + + //-------------------------------- + // Handlers + //-------------------------------- + + _onClickNext: function() { + this.trigger_up('slide_go_next'); + this.destroy(); + }, + + //-------------------------------- + // Private + //-------------------------------- + + /** + * Handles the animation of the karma gain in the following steps: + * 1. Initiate the tooltip which will display the actual Karma + * over the progress bar. + * 2. Animate the tooltip text to increment smoothly from the old + * karma value to the new karma value and updates it to make it + * move as the progress bar moves. + * 3a. The user doesn't level up + * I. When the user doesn't level up the progress bar simply goes + * from the old karma value to the new karma value. + * 3b. The user levels up + * I. The first step makes the progress bar go from the old karma + * value to 100%. + * II. The second step makes the progress bar go from 100% to 0%. + * III. The third and final step makes the progress bar go from 0% + * to the new karma value. It also changes the lower and upper + * bound to match the new rank. + * @param $modal + * @param rankProgress + * @private + */ + _animateProgressBar: function () { + var self = this; + this.$('[data-toggle="tooltip"]').tooltip({ + trigger: 'manual', + container: '.progress-bar-tooltip', + }).tooltip('show'); + + this.$('.tooltip-inner') + .prop('karma', this.quiz.rankProgress.previous_rank.karma) + .animate({ + karma: this.quiz.rankProgress.new_rank.karma + }, { + duration: this.quiz.rankProgress.level_up ? 1700 : 800, + step: function (newKarma) { + self.$('.tooltip-inner').text(Math.ceil(newKarma)); + self.$('[data-toggle="tooltip"]').tooltip('update'); + } + } + ); + + var $progressBar = this.$('.progress-bar'); + if (this.quiz.rankProgress.level_up) { + this.$('.o_wslides_quiz_modal_title').text(_t('Level up!')); + $progressBar.css('width', '100%'); + _.delay(function () { + self.$('.o_wslides_quiz_modal_rank_lower_bound') + .text(self.quiz.rankProgress.new_rank.lower_bound); + self.$('.o_wslides_quiz_modal_rank_upper_bound') + .text(self.quiz.rankProgress.new_rank.upper_bound || ""); + + // we need to use _.delay to force DOM re-rendering between 0 and new percentage + _.delay(function () { + $progressBar.addClass('no-transition').width('0%'); + }, 1); + _.delay(function () { + $progressBar + .removeClass('no-transition') + .width(self.quiz.rankProgress.new_rank.progress + '%'); + }, 100); + }, 800); + } else { + $progressBar.css('width', this.quiz.rankProgress.new_rank.progress + '%'); + } + }, + + /** + * Handles the animation of the different text such as the karma gain + * and the motivational message when the user levels up. + * @private + */ + _animateText: function () { + var self = this; + _.delay(function () { + self.$('h4.o_wslides_quiz_modal_xp_gained').addClass('show in'); + self.$('.o_wslides_quiz_modal_dismiss').removeClass('d-none'); + }, 800); + + if (this.quiz.rankProgress.level_up) { + _.delay(function () { + self.$('.o_wslides_quiz_modal_rank_motivational').addClass('fade'); + _.delay(function () { + self.$('.o_wslides_quiz_modal_rank_motivational').html( + self.quiz.rankProgress.last_rank ? + self.quiz.rankProgress.description : + self.quiz.rankProgress.new_rank.motivational + ); + self.$('.o_wslides_quiz_modal_rank_motivational').addClass('show in'); + }, 800); + }, 800); + } + }, + +}); + +return SlideQuizFinishModal; + +}); diff --git a/addons/website_slides/static/src/scss/website_slides.scss b/addons/website_slides/static/src/scss/website_slides.scss index 52628a00342..474cb8eeec2 100644 --- a/addons/website_slides/static/src/scss/website_slides.scss +++ b/addons/website_slides/static/src/scss/website_slides.scss @@ -449,6 +449,14 @@ $o-wslides-fs-side-width: 300px; @include media-breakpoint-up (sm) { .modal-body { overflow: visible!important; + + .o_wslides_quiz_modal_close_btn { + right: 5px; + } + + .o_wslides_gradient { + width: 42%; + } } .modal-content { diff --git a/addons/website_slides/static/src/xml/slide_quiz.xml b/addons/website_slides/static/src/xml/slide_quiz.xml index 853bbac5fa4..288aa36f8a1 100644 --- a/addons/website_slides/static/src/xml/slide_quiz.xml +++ b/addons/website_slides/static/src/xml/slide_quiz.xml @@ -84,52 +84,45 @@ -