[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) <tde@openerp.com>
This commit is contained in:
Patrick Hoste
2019-12-18 09:11:24 +00:00
parent 6ac675f50f
commit 7b0df05706
5 changed files with 209 additions and 159 deletions
@@ -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');
}
},
@@ -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;
});
@@ -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 {
@@ -84,52 +84,45 @@
</t>
<t t-name="slide.slide.quiz.finish">
<div class="modal o_wslides_quiz_modal pt-5" tabindex="-1" role="dialog" id="slides_quiz_modal">
<div class="modal-backdrop show bg-white" style="z-index:0"/>
<div class="modal-dialog mt-5" role="document">
<div class="modal-content shadow-lg">
<div class="modal-body d-flex p-0">
<button type="button" class="close position-absolute" data-dismiss="modal" aria-label="Close" style="right: 5px">&#215;</button>
<div class="o_wslides_gradient rounded-left d-none d-md-flex flex-shrink-0" style="width: 42%">
<img class="o_wslides_quiz_modal_hero" src="/website_slides/static/src/img/quiz_modal_success.svg" alt=""/>
</div>
<div class="d-flex flex-column flex-grow-1 justify-content-between pl-md-5 p-3 overflow-auto">
<div>
<h1 class="o_wslides_quiz_modal_title mt-3 display-4 font-weight-bold">Amazing!</h1>
<div class="pb-3">
<h4 class="o_wslides_quiz_modal_xp_gained pb-2 d-flex fade">You gained <span class="badge badge-pill badge-success text-white font-weight-bold ml-2 mr-1"><t t-esc="widget.quiz.quizKarmaWon"/> XP</span> !</h4>
<div class="mt-5 mb-4">
<div class="progress">
<div class="progress-bar" role="progressbar" t-att-aria-valuenow="widget.quiz.rankProgress.previous_rank.progress" aria-valuemin="0" aria-valuemax="100"
t-attf-style="width: #{widget.quiz.rankProgress.previous_rank.progress}%"/>
<div class="progress-bar-tooltip" data-toggle="tooltip" data-placement="top" t-att-title="widget.quiz.rankProgress.new_rank.karma" />
</div>
<small class="float-left text-primary font-weight-bold o_wslides_quiz_modal_rank_lower_bound">
<t t-esc="widget.quiz.rankProgress.previous_rank.lower_bound"/>
</small>
<small t-if="widget.quiz.rankProgress.previous_rank.upper_bound" class="float-right font-weight-bold o_wslides_quiz_modal_rank_upper_bound">
<t t-esc="widget.quiz.rankProgress.previous_rank.upper_bound"/>
</small>
</div>
</div>
<div class="pb-3 o_wslides_quiz_modal_rank_motivational">
<t t-set="showLastRankDescription" t-value="widget.quiz.rankProgress.last_rank &amp;&amp; !widget.quiz.rankProgress.level_up" />
<t t-raw="showLastRankDescription ? widget.quiz.rankProgress.description : widget.quiz.rankProgress.previous_rank.motivational" />
</div>
</div>
<div class="o_wslides_quiz_modal_dismiss align-self-end d-none">
<t t-if="widget.quiz.rankProgress.level_up">
<a type="button" target="_blank" t-attf-href="/profile/user/#{widget.userId}" class="btn btn-light border">Check Profile</a>
</t>
<t t-if="widget.slide.hasNext">
<button type="button" class="btn btn-light border o_wslides_quiz_modal_btn">Next <i class="fa fa-chevron-right"/></button>
</t>
<t t-else="">
<a type="button" href="/slides" class="btn btn-light border">End course</a>
</t>
<div>
<button type="button" class="o_wslides_quiz_modal_close_btn close position-absolute" data-dismiss="modal" aria-label="Close">&#215;</button>
<div class="o_wslides_gradient d-none d-md-flex flex-shrink-0">
<img class="o_wslides_quiz_modal_hero" src="/website_slides/static/src/img/quiz_modal_success.svg" alt=""/>
</div>
<div class="d-flex flex-column flex-grow-1 justify-content-between pl-md-5 p-3 overflow-auto">
<div>
<h1 class="o_wslides_quiz_modal_title mt-3 display-4 font-weight-bold">Amazing!</h1>
<div class="pb-3">
<h4 class="o_wslides_quiz_modal_xp_gained pb-2 d-flex fade">You gained <span class="badge badge-pill badge-success text-white font-weight-bold ml-2 mr-1"><t t-esc="widget.quiz.quizKarmaWon"/> XP</span> !</h4>
<div class="mt-5 mb-4">
<div class="progress">
<div class="progress-bar" role="progressbar" t-att-aria-valuenow="widget.quiz.rankProgress.previous_rank.progress" aria-valuemin="0" aria-valuemax="100"
t-attf-style="width: #{widget.quiz.rankProgress.previous_rank.progress}%"/>
<div class="progress-bar-tooltip" data-toggle="tooltip" data-placement="top" t-att-title="widget.quiz.rankProgress.new_rank.karma" />
</div>
<small class="float-left text-primary font-weight-bold o_wslides_quiz_modal_rank_lower_bound">
<t t-esc="widget.quiz.rankProgress.previous_rank.lower_bound"/>
</small>
<small t-if="widget.quiz.rankProgress.previous_rank.upper_bound" class="float-right font-weight-bold o_wslides_quiz_modal_rank_upper_bound">
<t t-esc="widget.quiz.rankProgress.previous_rank.upper_bound"/>
</small>
</div>
</div>
<div class="pb-3 o_wslides_quiz_modal_rank_motivational">
<t t-set="showLastRankDescription" t-value="widget.quiz.rankProgress.last_rank &amp;&amp; !widget.quiz.rankProgress.level_up" />
<t t-raw="showLastRankDescription ? widget.quiz.rankProgress.description : widget.quiz.rankProgress.previous_rank.motivational" />
</div>
</div>
<div class="o_wslides_quiz_modal_dismiss align-self-end d-none">
<t t-if="widget.quiz.rankProgress.level_up">
<a type="button" target="_blank" t-attf-href="/profile/user/#{widget.userId}" class="btn btn-light border">Check Profile</a>
</t>
<t t-if="widget.hasNext">
<button type="button" class="btn btn-light border o_wslides_quiz_modal_btn">Next <i class="fa fa-chevron-right"/></button>
</t>
<t t-else="">
<a type="button" href="/slides" class="btn btn-light border">End course</a>
</t>
</div>
</div>
</div>
+1
View File
@@ -29,6 +29,7 @@
<script type="text/javascript" src="/website_slides/static/src/js/slides_course_join.js"/>
<script type="text/javascript" src="/website_slides/static/src/js/slides_course_quiz.js"/>
<script type="text/javascript" src="/website_slides/static/src/js/slides_course_quiz_question_form.js"/>
<script type="text/javascript" src="/website_slides/static/src/js/slides_course_quiz_finish.js"/>
<script type="text/javascript" src="/website_slides/static/src/js/slides_course_unsubscribe.js"/>
</xpath>
</template>