diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/website_event_track_quiz/static/src/js | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/website_event_track_quiz/static/src/js')
| -rw-r--r-- | addons/website_event_track_quiz/static/src/js/event_quiz.js | 323 | ||||
| -rw-r--r-- | addons/website_event_track_quiz/static/src/js/event_quiz_leaderboard.js | 34 |
2 files changed, 357 insertions, 0 deletions
diff --git a/addons/website_event_track_quiz/static/src/js/event_quiz.js b/addons/website_event_track_quiz/static/src/js/event_quiz.js new file mode 100644 index 00000000..c6adddc3 --- /dev/null +++ b/addons/website_event_track_quiz/static/src/js/event_quiz.js @@ -0,0 +1,323 @@ +odoo.define('website_event_track_quiz.event.quiz', function (require) { + +'use strict'; + +var publicWidget = require('web.public.widget'); +var core = require('web.core'); +var session = require('web.session'); +var utils = require('web.utils'); + +var QWeb = core.qweb; +var _t = core._t; + +/** + * This widget is responsible of displaying quiz questions and propositions. Submitting the quiz will fetch the + * correction and decorate the answers according to the result. Error message can be displayed. + * + * This widget can be attached to DOM rendered server-side by `gamification_quiz.` + * + */ +var Quiz = publicWidget.Widget.extend({ + template: 'quiz.main', + xmlDependencies: ['/website_event_track_quiz/static/src/xml/quiz_templates.xml'], + events: { + "click .o_quiz_quiz_answer": '_onAnswerClick', + "click .o_quiz_js_quiz_submit": '_submitQuiz', + "click .o_quiz_js_quiz_reset": '_onClickReset', + }, + + /** + * @override + * @param {Object} parent + * @param {Object} data holding all the container information + * @param {Object} quizData : quiz data to display + */ + init: function (parent, data, quizData) { + this._super.apply(this, arguments); + this.track = _.defaults(data, { + id: 0, + name: '', + eventId: '', + completed: false, + isMember: false, + progressBar: false, + isManager: false + }); + this.quiz = quizData || false; + if (this.quiz) { + this.quiz.questionsCount = quizData.questions.length; + } + this.isMember = data.isMember || false; + this.userId = session.user_id; + this.redirectURL = encodeURIComponent(document.URL); + }, + + /** + * @override + */ + willStart: function () { + var defs = [this._super.apply(this, arguments)]; + if (!this.quiz) { + defs.push(this._fetchQuiz()); + } + return Promise.all(defs); + }, + + /** + * Overridden to add custom rendering behavior upon start of the widget. + * + * If the user has answered the quiz before having joined the course, we check + * his answers (saved into his session) here as well. + * + * @override + */ + start: function () { + var self = this; + return this._super.apply(this, arguments).then(function () { + self._renderValidationInfo(); + }); + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + _alertShow: function (alertCode) { + var message = _t('There was an error validating this quiz.'); + if (alertCode === 'quiz_incomplete') { + message = _t('All questions must be answered !'); + } else if (alertCode === 'quiz_done') { + message = _t('This quiz is already done. Retaking it is not possible.'); + } + + this.displayNotification({ + type: 'warning', + title: _t('Quiz validation error'), + message: message, + sticky: true + }); + }, + + /** + * Get all the questions ID from the displayed Quiz + * @returns {Array} + * @private + */ + _getQuestionsIds: function () { + return this.$('.o_quiz_js_quiz_question').map(function () { + return $(this).data('question-id'); + }).get(); + }, + + /** + * @private + * Decorate the answers according to state + */ + _disableAnswers: function () { + var self = this; + this.$('.o_quiz_js_quiz_question').addClass('completed-disabled'); + this.$('input[type=radio]').each(function () { + $(this).prop('disabled', self.track.completed); + }); + }, + + /** + * Decorate the answer inputs according to the correction and adds the answer comment if + * any. + * + * @private + */ + _renderAnswersHighlightingAndComments: function () { + var self = this; + this.$('.o_quiz_js_quiz_question').each(function () { + var $question = $(this); + var questionId = $question.data('questionId'); + var isCorrect = self.quiz.answers[questionId].is_correct; + $question.find('a.o_quiz_quiz_answer').each(function () { + var $answer = $(this); + $answer.find('i.fa').addClass('d-none'); + if ($answer.find('input[type=radio]')[0].checked) { + if (isCorrect) { + $answer.removeClass('list-group-item-danger').addClass('list-group-item-success'); + $answer.find('i.fa-check-circle').removeClass('d-none'); + } else { + $answer.removeClass('list-group-item-success').addClass('list-group-item-danger'); + $answer.find('i.fa-times-circle').removeClass('d-none'); + $answer.find('label input').prop('checked', false); + } + } else { + $answer.removeClass('list-group-item-danger list-group-item-success'); + $answer.find('i.fa-circle').removeClass('d-none'); + } + }); + var comment = self.quiz.answers[questionId].comment; + if (comment) { + $question.find('.o_quiz_quiz_answer_info').removeClass('d-none'); + $question.find('.o_quiz_quiz_answer_comment').text(comment); + } + }); + }, + + /* + * @private + * Update validation box (karma, buttons) according to widget state + */ + _renderValidationInfo: function () { + var $validationElem = this.$('.o_quiz_js_quiz_validation'); + $validationElem.html( + QWeb.render('quiz.validation', {'widget': this}) + ); + }, + + /** + * Get the quiz answers filled in by the User + * + * @private + */ + _getQuizAnswers: function () { + return this.$('input[type=radio]:checked').map(function (index, element) { + return parseInt($(element).val()); + }).get(); + }, + + /** + * Submit a quiz and get the correction. It will display messages + * according to quiz result. + * + * @private + */ + _submitQuiz: function () { + var self = this; + + return this._rpc({ + route: '/event_track/quiz/submit', + params: { + event_id: self.track.eventId, + track_id: self.track.id, + answer_ids: this._getQuizAnswers(), + } + }).then(function (data) { + if (data.error) { + self._alertShow(data.error); + } else { + self.quiz = _.extend(self.quiz, data); + self.quiz.quizPointsGained = data.quiz_points; + if (data.quiz_completed) { + self._disableAnswers(); + self.track.completed = data.quiz_completed; + } + self._renderAnswersHighlightingAndComments(); + self._renderValidationInfo(); + if (data.visitor_uuid) { + utils.set_cookie('visitor_uuid', data.visitor_uuid); + } + } + + return Promise.resolve(data); + }); + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * When clicking on an answer, this one should be marked as "checked". + * + * @private + * @param OdooEvent ev + */ + _onAnswerClick: function (ev) { + ev.preventDefault(); + if (!this.track.completed) { + $(ev.currentTarget).find('input[type=radio]').prop('checked', true); + } + }, + + /** + * Resets the completion of the track so the user can take + * the quiz again + * + * @private + */ + _onClickReset: function () { + this._rpc({ + route: '/event_track/quiz/reset', + params: { + event_id: this.track.eventId, + track_id: this.track.id + } + }).then(function () { + window.location.reload(); + }); + }, + +}); + +publicWidget.registry.Quiz = publicWidget.Widget.extend({ + selector: '.o_quiz_main', + + //---------------------------------------------------------------------- + // Public + //---------------------------------------------------------------------- + + /** + * @override + * @param {Object} parent + */ + start: function () { + var self = this; + this.quizWidgets = []; + var defs = [this._super.apply(this, arguments)]; + this.$('.o_quiz_js_quiz').each(function () { + var data = $(this).data(); + data.quizData = { + questions: self._extractQuestionsAndAnswers(), + sessionAnswers: data.sessionAnswers || [], + quizKarmaMax: data.quizKarmaMax, + quizKarmaWon: data.quizKarmaWon, + quizKarmaGain: data.quizKarmaGain, + quizPointsGained: data.quizPointsGained, + quizAttemptsCount: data.quizAttemptsCount, + }; + defs.push(new Quiz(self, data, data.quizData).attachTo($(this))); + }); + return Promise.all(defs); + }, + + //---------------------------------------------------------------------- + // Private + //--------------------------------------------------------------------- + + /** + * Extract data from exiting DOM rendered server-side, to have the list of questions with their + * relative answers. + * This method should return the same format as /gamification_quiz/quiz/get controller. + * + * @return {Array<Object>} list of questions with answers + */ + _extractQuestionsAndAnswers: function () { + var questions = []; + this.$('.o_quiz_js_quiz_question').each(function () { + var $question = $(this); + var answers = []; + $question.find('.o_quiz_quiz_answer').each(function () { + var $answer = $(this); + answers.push({ + id: $answer.data('answerId'), + text: $answer.data('text'), + }); + }); + questions.push({ + id: $question.data('questionId'), + title: $question.data('title'), + answer_ids: answers, + }); + }); + return questions; + }, +}); + +return Quiz; + +}); diff --git a/addons/website_event_track_quiz/static/src/js/event_quiz_leaderboard.js b/addons/website_event_track_quiz/static/src/js/event_quiz_leaderboard.js new file mode 100644 index 00000000..f624a852 --- /dev/null +++ b/addons/website_event_track_quiz/static/src/js/event_quiz_leaderboard.js @@ -0,0 +1,34 @@ +odoo.define('website_event_track_quiz.event_leaderboard', function (require) { + +'use strict'; + +var publicWidget = require('web.public.widget'); + +publicWidget.registry.EventLeaderboard = publicWidget.Widget.extend({ + selector: '.o_wevent_quiz_leaderboard', + + /** + * Basic override to scroll to current visitor's position. + */ + start: function () { + var self = this; + return this._super(...arguments).then(function () { + var $scrollTo = self.$('.o_wevent_quiz_scroll_to'); + if ($scrollTo.length !== 0) { + var offset = $('.o_header_standard').height(); + var $appMenu = $('.o_main_navbar'); + if ($appMenu.length !== 0) { + offset += $appMenu.height(); + } + window.scrollTo({ + top: $scrollTo.offset().top - offset, + behavior: 'smooth' + }); + } + }); + } +}); + +return publicWidget.registry.EventLeaderboard; + +}); |
