From fd78a40836dad044bfb8c0ab30fcb37fc8ecf9af Mon Sep 17 00:00:00 2001 From: qmo-odoo Date: Fri, 22 Feb 2019 09:47:39 +0000 Subject: [PATCH] [REF] website_slides: revamp fullscreen widget This commit makes the 'Fullscreen' page a complete odoo widgets. We decided to split it into some sub widget: - Fullscreen: will be the master piece, handle communication of components, displaying slide content, setting slide as completed, handling server RPC calls, .... - Sidebar: responsible for slide navigation, based on the table of content. (prev, next, keyboard naviguation, ...) - VideoPlayer: display content for Youtube video and handling player event to auto set as completed, ... The DOM of this page is still rendered serverside. DOM was cleaned in order to be less complex and less deep. CSS style was also reviewed to decrease line of code. Fullscreen is now completely using Quiz widget with events triggered. Task-1942852 --- addons/website_slides/controllers/main.py | 4 +- addons/website_slides/models/slide_slide.py | 2 +- .../src/js/slides_course_fullscreen_player.js | 785 +++++++++++------- .../static/src/js/slides_course_quiz.js | 18 +- .../src/scss/slides_slide_fullscreen.scss | 267 +----- .../static/src/xml/slide_quiz.xml | 2 +- .../src/xml/website_slides_fullscreen.xml | 61 +- ...ite_slides_templates_lesson_fullscreen.xml | 178 ++-- .../views/website_slides_templates.xml | 6 +- .../src/xml/website_slides_fullscreen.xml | 14 +- ...ite_slides_templates_lesson_fullscreen.xml | 6 +- 11 files changed, 646 insertions(+), 697 deletions(-) diff --git a/addons/website_slides/controllers/main.py b/addons/website_slides/controllers/main.py index f8ebb91a70b..70137487c0c 100644 --- a/addons/website_slides/controllers/main.py +++ b/addons/website_slides/controllers/main.py @@ -622,8 +622,10 @@ class WebsiteSlides(WebsiteProfile): 'quizKarmaWon': quiz_info['quiz_karma_won'], } - @http.route('/slides/slide/quiz/submit', type="json", auth="user", website=True) + @http.route('/slides/slide/quiz/submit', type="json", auth="public", website=True) def slide_quiz_submit(self, slide_id, answer_ids): + if request.website.is_public_user(): + return {'error': 'public_user'} fetch_res = self._fetch_slide(slide_id) if fetch_res.get('error'): return fetch_res diff --git a/addons/website_slides/models/slide_slide.py b/addons/website_slides/models/slide_slide.py index 53378df947c..c98d0b9a69f 100644 --- a/addons/website_slides/models/slide_slide.py +++ b/addons/website_slides/models/slide_slide.py @@ -512,7 +512,7 @@ class Slide(models.Model): slide_partner = slide_partners_map.get(slide.id) if slide.question_ids and slide_partner: if slide_partner.quiz_attempts_count: - result[slide.id]['quiz_karma_gain'] = gains[slide_partner.quiz_attempts_count] if slide_partner.quiz_attempts_count <= len(gains) else gains[-1] + result[slide.id]['quiz_karma_gain'] = gains[slide_partner.quiz_attempts_count] if slide_partner.quiz_attempts_count < len(gains) else gains[-1] result[slide.id]['quiz_attempts_count'] = slide_partner.quiz_attempts_count if quiz_done or slide_partner.completed: result[slide.id]['quiz_karma_won'] = gains[slide_partner.quiz_attempts_count-1] if slide_partner.quiz_attempts_count < len(gains) else gains[-1] diff --git a/addons/website_slides/static/src/js/slides_course_fullscreen_player.js b/addons/website_slides/static/src/js/slides_course_fullscreen_player.js index b7165e92d4d..f8c34ee222f 100644 --- a/addons/website_slides/static/src/js/slides_course_fullscreen_player.js +++ b/addons/website_slides/static/src/js/slides_course_fullscreen_player.js @@ -7,414 +7,561 @@ odoo.define('website_slides.fullscreen', function (require) { var core = require('web.core'); var QWeb = core.qweb; - var tag = document.createElement('script'); - - var QuizWidget = require('website_slides.quiz'); - - tag.src = "https://www.youtube.com/iframe_api"; - var firstScriptTag = document.getElementsByTagName('script')[0]; - firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); + var Quiz = require('website_slides.quiz'); - var Fullscreen = Widget.extend({ - custom_events: { - quiz_next_slide: '_goToNextSlide', - quiz_completed: '_onQuizCompleted' - }, - /** - * @override - * @param {Object} el - * @param {Object} data holding channelId and optionally upload and publish control parameters - */ - init: function (el, courseId, slideId, userId) { - this.courseID = parseInt(courseId, 10); - this.slideID = parseInt(slideId, 10); - this.userID = parseInt(userId, 10); - this.course = undefined; - this.slide = undefined; - this.slides = []; - this.nextSlide = undefined; - this.previousSlide = undefined; - this.url = undefined; - this.urlToSmallScreen = undefined; - this.activetab = undefined; - this.player = undefined; - this.goToQuiz = false; - this.slideTitle = undefined; - return this._super.apply(this,arguments); + /** + * Helper: Get the slide dict matching the given criteria + * + * @private + * @param {Array} slideList List of dict reprensenting a slide + * @param {Object} matcher (see https://underscorejs.org/#matcher) + */ + var findSlide = function (slideList, matcher) { + var slideMatch = _.matcher(matcher); + return _.find(slideList, slideMatch); + }; + + /** + * This widget is responsible of display Youtube Player + * + * The widget will trigger an event `change_slide` when the video is at + * its end, and `slide_completed` when the player is at 30 sec before the + * end of the video (30 sec before is considered as completed). + */ + var VideoPlayer = Widget.extend({ + template: 'website.slides.fullscreen.video', + youtubeUrl: 'https://www.youtube.com/iframe_api', + + init: function (parent, slide) { + this.slide = slide; + return this._super.apply(this, arguments); }, start: function (){ var self = this; - this.url = window.location.pathname; - this.urlToSmallScreen = this.url.replace('/fullscreen',''); - this._getSlides(); - this._renderPlayer(); - this._bindListEvents(); - $(document).keydown(this._onKeyDown.bind(this)); - return this._super.apply(this, arguments); - }, - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - /** - * @private - * Renders the player accordingly to the current slide - */ - _renderPlayer: function (){ - var self = this; - - var def = $.Deferred(); - if (this.slide.slide_type === 'webpage') { - this._fetchHtmlContent().then(function () { - self._renderWebpage(); - def.resolve(); - }); - } else { - if (this.slide.slide_type !== 'quiz') { - // no RPC, get slide data from existing DOM - var embed_url = $(this.slide.embed_code).attr('src'); - if (this.slide.slide_type === "video"){ - embed_url = "https://" + embed_url + "&rel=0&autoplay=1&enablejsapi=1&origin=" + window.location.origin; - } - $('.o_wslides_fs_player').html(QWeb.render('website.slides.fullscreen', { - slide: self.slide, - nextSlide: self.nextSlide, - questions: self.slide.quiz ? self.slide.quiz.questions: '', - embed_url: embed_url, - question_count: self.slide.quiz ? self.slide.quiz.questions.length : '', - letters: self.slide.quiz ? self.letters : '', - showMiniQuiz: self.goToQuiz - })); - - if(this.slide.slide_type === "video"){ - this._renderYoutubeIframe(); - } - def.resolve(); - } - } - - if (this.slide.slide_type === "quiz" || this.goToQuiz) { - this._renderQuiz().then(function() { - def.resolve(); - }); - } - - return def.then(function() { - self._renderTitle(); - }); - }, - _renderYoutubeIframe: function (){ - var self = this; - /** - * Due to issues of synchronization between the youtube api script and the widget's instanciation. - */ - try { + return $.when(this._super.apply(this, arguments), this._loadYoutubeAPI()).then(function() { self._setupYoutubePlayer(); - } - catch (error) { - onYouTubeIframeAPIReady = function (){ - var self = this; - self._setupYoutubePlayer(); - }.bind(this); - } - }, - _renderWebpage: function (){ - var self = this; - $(self.slide.htmlContent).appendTo('.o_wslides_fs_webpage_content'); - }, - - _renderQuiz: function (){ - var quizSlideData = _.extend(this.slide, { - completed: this.slide.done, }); - var Quiz = new QuizWidget(this, quizSlideData); - return Quiz.appendTo('.o_wslides_fs_player'); }, + _loadYoutubeAPI: function () { + var def = $.Deferred(); + if ($(document).find('script[src="' + this.youtubeUrl + '"]').length === 0) { + var $youtubeElement = $('