summaryrefslogtreecommitdiff
path: root/addons/website_slides/static/src/js
diff options
context:
space:
mode:
Diffstat (limited to 'addons/website_slides/static/src/js')
-rw-r--r--addons/website_slides/static/src/js/slides_category.js148
-rw-r--r--addons/website_slides/static/src/js/slides_course_fullscreen_player.js427
-rw-r--r--addons/website_slides/static/src/js/slides_course_progress_bar.js47
-rw-r--r--addons/website_slides/static/src/js/slides_course_quiz.js206
-rw-r--r--addons/website_slides/static/src/js/slides_course_sidebar_list.js34
-rw-r--r--addons/website_slides/static/src/js/slides_course_slides_list.js251
-rw-r--r--addons/website_slides/static/src/js/slides_delete_slide.js88
-rw-r--r--addons/website_slides/static/src/js/slides_upload.js51
-rw-r--r--addons/website_slides/static/src/js/website_slides.editor.js1
9 files changed, 1246 insertions, 7 deletions
diff --git a/addons/website_slides/static/src/js/slides_category.js b/addons/website_slides/static/src/js/slides_category.js
new file mode 100644
index 00000000000..d1d7efb7747
--- /dev/null
+++ b/addons/website_slides/static/src/js/slides_category.js
@@ -0,0 +1,148 @@
+odoo.define('website_slides.add.section', function (require) {
+ 'use strict';
+
+ var sAnimations = require('website.content.snippets.animation');
+ var core = require('web.core');
+ var Widget = require('web.Widget');
+
+ var _t = core._t;
+
+ var SectionDialog = Widget.extend({
+ template: 'website.slide.add.section',
+ events: {
+ 'hidden.bs.modal': 'destroy',
+ 'click button.save': '_save',
+ 'click button[data-dismiss="modal"]': '_cancel',
+ 'change input#upload': '_slideUpload',
+ 'change input#url': '_slideUrl',
+ 'click .list-group-item': function (ev) {
+ this.$('.list-group-item').removeClass('active');
+ $(ev.target).closest('li').addClass('active');
+ }
+ },
+
+ /**
+ * @override
+ * @param {Object} el
+ * @param {number} channel_id
+ */
+ init: function (el, channelID) {
+ this._super(el, channelID);
+ this.channel_id = parseInt(channelID, 10);
+ this.index_content = '';
+ },
+ /**
+ * @override
+ */
+ start: function () {
+ this.$el.modal({
+ backdrop: 'static'
+ });
+
+ return this._super.apply(this, arguments);
+ },
+ _getValue: function () {
+ var canvas = this.$('#data_canvas')[0],
+ values = {
+ 'channel_id': this.channel_id || '',
+ 'url': this.$('#url').val(),
+ 'name': this.$('#section_name').val()
+ };
+ return values;
+ },
+ /**
+ * @private
+ */
+ _validate: function () {
+ this.$('.form-group').removeClass('o_has_error').find('.form-control, .custom-select').removeClass('is-invalid');
+ if (!this.$('#name').val()) {
+ this.$('#name').closest('.form-group').addClass('o_has_error').find('.form-control, .custom-select').addClass('is-invalid');
+ return false;
+ }
+ var url = this.$('#url').val() ? this.is_valid_url : false;
+ if (!(this.file.name || url)) {
+ this.$('#url').closest('.form-group').addClass('o_has_error').find('.form-control, .custom-select').addClass('is-invalid');
+ return false;
+ }
+ return true;
+ },
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ * @param {Object} ev
+ */
+ _save: function (ev) {
+ var self = this;
+
+ var values = this._getValue();
+ if ($(ev.target).data('published')) {
+ values.website_published = true;
+ }
+ this.$('.oe_slides_upload_loading').show();
+ this.$('.modal-footer, .modal-body').hide();
+ this._rpc({
+ route: '/slides/add_category',
+ params: values,
+ }).then(function (data) {
+ if (data.error) {
+ self._displayAlert(data.error);
+ self.$('.oe_slides_upload_loading').hide();
+ self.$('.modal-footer, .modal-body').show();
+
+ } else {
+ window.location = data.url;
+ }
+ });
+ },
+ /**
+ * @override
+ */
+ _cancel: function () {
+ this.trigger('cancel');
+ },
+
+ });
+
+ sAnimations.registry.websiteSlidesSection = sAnimations.Class.extend({
+ selector: '.oe_slide_js_add_section',
+ xmlDependencies: ['/website_slides/static/src/xml/website_slides_upload.xml'],
+ read_events: {
+ 'click': '_onAddSectionClick',
+ },
+
+ /**
+ * @override
+ */
+ start: function () {
+ // Automatically open the upload dialog if requested from query string
+ if ($.deparam.querystring().enable_slide_upload !== undefined) {
+ this._openDialog(this.$el.attr('channel_id'));
+ }
+ return this._super.apply(this, arguments);
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ _openDialog: function (channelID) {
+ new SectionDialog(this, channelID).appendTo(document.body);
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * @param {Event} ev
+ */
+ _onAddSectionClick: function (ev) {
+ console.log('test');
+ this._openDialog($(ev.currentTarget).attr('channel_id'));
+ },
+ });
+ }); \ No newline at end of file
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
new file mode 100644
index 00000000000..1da173a2f46
--- /dev/null
+++ b/addons/website_slides/static/src/js/slides_course_fullscreen_player.js
@@ -0,0 +1,427 @@
+var onYouTubeIframeAPIReady;
+
+odoo.define('website_slides.fullscreen', function (require) {
+ 'use strict';
+ var sAnimations = require('website.content.snippets.animation');
+ var Widget = require('web.Widget');
+ 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 Fullscreen = Widget.extend({
+ /**
+ * @override
+ * @param {Object} el
+ * @param {Object} data holding channelId and optionally upload and publish control parameters
+ */
+ init: function(el, course_id,slide_id, user_id){
+ this._super.apply(this,arguments);
+ this.courseID = parseInt(course_id, 10);
+ this.slideID = parseInt(slide_id, 10);
+ this.userID = parseInt(user_id, 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.answeredQuestions = [];
+ this.slideTitle = undefined;
+ },
+ 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 embed_url;
+ if(self.slide.slide_type !== 'webpage' || self.slide.htmlContent){
+ if((self.slide.slide_type == "quiz" || self.slide.hasQuiz) && !self.slide.quiz){
+ self._fetchQuiz();
+ } else {
+ embed_url = $(this.slide.embed_code).attr('src');
+ if (self.slide.slide_type === "video"){
+ embed_url = "https://" + embed_url + "&rel=0&autoplay=1&enablejsapi=1&origin=" + window.location.origin;
+ }
+ $('.o_wslides_fullscreen_player').html(QWeb.render('website.slides.fullscreen', {
+ slide: self.slide,
+ nextSlide: self.nextSlide,
+ questions: self.slide.quiz ? self.slide.quiz.questions: '',
+ reward: self.slide.quiz ? self.slide.quiz.nb_attempts < 3 ? self.slide.quiz.possible_rewards[self.slide.quiz.nb_attempts] : self.slide.quiz.possible_rewards[3]: self.slide.maxPoints,
+ embed_url: embed_url,
+ question_count: self.slide.quiz ? self.slide.quiz.questions.length : '',
+ letters: self.slide.quiz ? self.letters : '',
+ showMiniQuiz: self.goToQuiz
+ }));
+ if(self.slide.slide_type === "video"){
+ self._renderYoutubeIframe();
+ }
+ if(self.slide.slide_type == 'webpage'){
+ self._renderWebpage();
+ }
+ if((self.slide.slide_type == "presentation" || self.slide.slide_type == "document" || self.slide.slide_type == "infographic" || self.slide.slide_type == "webpage") && !self.slide.quiz){
+ self._setSlideStateAsDone();
+ }
+ if ((self.slide.quiz && self.slide.slide_type === "quiz") || self.goToQuiz){
+ self._renderQuiz();
+ }
+ }
+ } else {
+ self._fetchHtmlContent();
+ }
+ self._renderTitle();
+ },
+ _renderYoutubeIframe: function(){
+ var self = this;
+ /**
+ * Due to issues of synchronization between the youtube api script and the widget's instanciation.
+ */
+ try{
+ self._setupYoutubePlayer();
+ }
+ catch {
+ onYouTubeIframeAPIReady = function(){
+ var self = this;
+ self._setupYoutubePlayer();
+ }.bind(this)
+ }
+ },
+ _renderWebpage: function(){
+ var self = this;
+ $(self.slide.htmlContent).appendTo('.o_wslides_fullscreen_webpage_content');
+ },
+ _renderQuiz: function(){
+ var self = this;
+ var Quiz = new QuizWidget(this, self.slide);
+ Quiz.appendTo('.o_wslides_fullscreen_player');
+ $('.next-slide').click(function(){
+ self._goToNextSlide();
+ })
+ $('.back-to-video').click(function(){
+ self.goToQuiz = false;
+ self._renderPlayer();
+ });
+ },
+ _renderTitle: function(){
+ var self = this;
+ $('.o_wslides_fullscreen_slide_title').empty().html(QWeb.render('website.course.fullscreen.title', {
+ slide: self.slide,
+ miniQuiz: self.goToQuiz
+ }));
+ },
+ /**
+ * @private
+ * Links the youtube api to the iframe present in the template
+ */
+ _setupYoutubePlayer: function(){
+ var self = this;
+ self.player = new YT.Player('youtube-player', {
+ host: 'https://www.youtube.com',
+ playerVars: {'autoplay': 1, 'origin': window.location.origin},
+ autoplay: 1,
+ events: {
+ 'onReady': self._onPlayerReady,
+ 'onStateChange': this._onPlayerStateChange.bind(self)
+ }
+ });
+ },
+ /**
+ * @param {*} event
+ * Specific method of the youtube api.
+ * Whenever the player starts playing, a setinterval is created.
+ * This setinterval is used to check te user's progress in the video.
+ * Once the user reaches a particular time in the video, the slide will be considered as completed if the video doesn't have a mini-quiz.
+ * This method also allows to automatically go to the next slide (or the quiz associated to the current video) once the video is over
+ */
+ _onPlayerStateChange: function(event){
+ var self = this;
+ var tid;
+ clearInterval(self.tid);
+ if (event.data == YT.PlayerState.PLAYING && !self.slide.done) {
+ self.tid = setInterval(function(){
+ if(event.target.getCurrentTime){
+ var currentTime = event.target.getCurrentTime();
+ var totalTime = event.target.getDuration();
+ if(totalTime && currentTime > totalTime - 30){
+ clearInterval(self.tid);
+ if(!self.slide.hasQuiz && !self.slide.done){
+ self.slide.done = true;
+ self._setSlideStateAsDone();
+ }
+ }
+ }
+ }, 1000);
+ }
+ if(event.data == YT.PlayerState.ENDED){
+ self.player = undefined;
+ self._goToNextSlide();
+ }
+ },
+ /**
+ * @private
+ * Creates slides objects from every slide-list-cells attributes
+ */
+ _getSlides: function(){
+ var self = this;
+ var slides = $('.o_wslides_fullscreen_sidebar_slide_tab');
+ for(var i = 0; i < slides.length;i++){
+ var slide = $(slides[i]);
+ self.slides.push({
+ id: parseInt(slide.attr('slide_id'), 10),
+ name: slide.attr('slide_name'),
+ embed_code: slide.attr('slide_embed_code'),
+ slide_type: slide.attr('slide_type'),
+ done: slide.attr('done'),
+ hasQuiz: slide.attr('quiz'),
+ slug: slide.attr('slide_slug'),
+ htmlContent: undefined
+ });
+ this._getActiveSlide();
+ }
+ },
+ /**
+ * @private
+ * @param {object} slide
+ * Fetch the quiz for a particular slide
+ */
+ _fetchQuiz: function(){
+ var self = this;
+ self._rpc({
+ route:"/slide/quiz/get",
+ params: {
+ 'slide_id': self.slide.id
+ }
+ }).then(function(data){
+ if(data){
+ self.slide.quiz = data;
+ self._renderPlayer();
+ }
+ })
+ },
+ _fetchHtmlContent: function(){
+ var self = this;
+ self._rpc({
+ route:"/slide/html_content/get",
+ params: {
+ 'slide_id': self.slide.id
+ }
+ }).then(function(data){
+ self.slide.htmlContent = data.html_content;
+ self._renderPlayer();
+ })
+ },
+ /**
+ * @private
+ * Once the completion conditions are filled,
+ * sends a json request to the backend to set the relation between the slide and the user as being completed
+ */
+ _setSlideStateAsDone: function(){
+ var self = this;
+ self._rpc({
+ route: '/slides/set_completed',
+ params: {
+ slide_id: self.slide.id,
+ }
+ }).then(function(data){
+ $('#check-'+self.slide.id).replaceWith($('<i class="check-done o_wslides_slide_completed fa fa-check-circle"></i>'))
+ self.slide.done = true;
+ clearInterval(self.tid);
+ self.channelCompletion = data.channel_completion;
+ self._updateProgressbar();
+ });
+ },
+ _updateProgressbar: function(){
+ var self = this;
+ var completion = self.channelCompletion <= 100 ? self.channelCompletion : 100;
+ $('.o_wslides_fullscreen_sidebar_progress_gauge').css('width', completion + "%" );
+ $('.o_wslides_progress_percentage').text(completion);
+ },
+ /**
+ * @private
+ * Creates an array of letters to be used in the quiz with a foreach
+ */
+ _generateQuizLetters: function(){
+ var letters = [];
+ for(var i = 65; i < 91; i++){
+ letters.push(String.fromCharCode(i));
+ }
+ return letters;
+ },
+ _goToNextSlide: function(){
+ var self = this;
+ clearInterval(self.tid);
+ self.player = undefined;
+ self.goToQuiz = self.slide.hasQuiz && !self.goToQuiz;
+ if(self.nextSlide && !self.goToQuiz){
+ self.slide = self.nextSlide;
+ self.index++;
+ self._setActiveTab();
+ self._renderPlayer();
+ self._setPreviousAndNextSlides();
+ self._updateUrl();
+ history.pushState(null,'',self.url);
+ }
+ else if(self.nextSlide){
+ self._renderPlayer();
+ }
+ },
+ _goToPreviousSlide: function(){
+ var self = this;
+ clearInterval(self.tid);
+ self.goToQuiz = false;
+ self.player = undefined;
+ if(self.previousSlide){
+ self.slide = self.previousSlide;
+ self.index--;
+ self._setActiveTab();
+ self._renderPlayer();
+ self._setPreviousAndNextSlides();
+ self._updateUrl();
+ history.pushState(null,'',self.url);
+ }
+ },
+ _setPreviousAndNextSlides: function(){
+ var self = this;
+ self.previousSlide = self.index > 0 ? self.slides[self.index-1] : undefined;
+ self.nextSlide = self.index < (self.slides.length - 1) ? self.slides[self.index+1] : undefined;
+ },
+ /**
+ * Changes the url whenever the user changes slides.
+ * This allows the user to refresh the page and stay at the right video
+ */
+ _updateUrl: function(){
+ var self = this;
+ var url = window.location.pathname.split('/');
+ url[url.length-1] = self.slide.slug;
+ url = url.join('/');
+ self.url = url;
+ self.urlToSmallScreen = self.url;
+ self.url += "?fullscreen=1";
+ $('.o_wslides_small_screen').attr('href', self.urlToSmallScreen);
+ },
+ /**
+ * Whenever the user changes slide, change the active tab
+ */
+ _setActiveTab: function(){
+ var self = this;
+ self.activeTab.removeClass('active');
+ $('li.active').removeClass('active');
+ $('li[slide_id='+self.slide.id+']').addClass('active');
+ self.activeTab = $('.o_wslides_fullscreen_sidebar_slide_tab[index="'+self.index+'"]')
+ self.activeTab.addClass('active');
+ },
+ /**
+ * The first time the user gets on the player,
+ * get the slide that is represented by the active tab in the sidebar
+ */
+ _getActiveSlide: function(){
+ var self = this;
+ self.activeTab = $('.o_wslides_fullscreen_sidebar_slide_tab.active');
+ self.index = parseInt(self.activeTab.attr('index'), 10);
+ self.slide = self.slides[self.index];
+ self._setPreviousAndNextSlides();
+ },
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+ _onListCellClick: function(ev){
+ var self = this;
+ clearInterval(self.tid);
+ self.player = undefined;
+ var target = $(ev.currentTarget);
+ self.goToQuiz = false;
+ if(target[0] !== self.activeTab[0]){
+ self.activeTab.removeClass('active');
+ target.addClass('active');
+ self.index = parseInt(target.attr('index'));
+ self._getActiveSlide();
+ self._renderPlayer();
+ $('li.active').removeClass('active');
+ $('li[slide_id='+self.slide.id+']').addClass('active');
+ self._setPreviousAndNextSlides();
+ self._updateUrl();
+ history.pushState(null,'',self.url);
+ }
+ },
+ _onMiniQuizClick: function(ev){
+ var self = this;
+ self.index = parseInt($(ev.currentTarget).attr('index'));
+ self.slide = self.slides[self.index];
+ self.goToQuiz = true;
+ self._setPreviousAndNextSlides();
+ self._renderPlayer();
+ self._setActiveTab();
+ self._updateUrl();
+ history.pushState(null,'' ,self.url);
+ },
+ /**
+ * @private
+ * Binds events related to the list
+ */
+ _bindListEvents: function(){
+ var self = this;
+ $('.o_wslides_fullscreen_sidebar_slide_tab').each(function () {
+ $(this).click(self._onListCellClick.bind(self));
+ });
+
+ $('.o_wslides_slide_quiz ').each(function(){
+ $(this).click(self._onMiniQuizClick.bind(self));
+ })
+ },
+ _onKeyDown: function(ev){
+ var self = this;
+ switch(ev.key){
+ case "ArrowRight":
+ self._goToNextSlide();
+ break;
+ case "ArrowLeft":
+ self._goToPreviousSlide();
+ break;
+ }
+ },
+ })
+
+ sAnimations.registry.websiteSlidesFullscreenPlayer = Widget.extend({
+ selector: '.oe_js_course_slide',
+ xmlDependencies: ['/website_slides/static/src/xml/website_slides_fullscreen.xml'],
+ init: function(el){
+ this._super.apply(this, arguments);
+ },
+ start: function(){
+ this._super.apply(this, arguments);
+ var user_id = this.$el.attr('user_id');
+ var course_id = this.$el.attr('course_id');
+ var slide_id = this.$el.attr('slide_id');
+ var fullscreen = new Fullscreen(this, course_id, slide_id, user_id);
+ fullscreen.appendTo(".oe_js_course_slide");
+ }
+ });
+
+ return Fullscreen;
+}); \ No newline at end of file
diff --git a/addons/website_slides/static/src/js/slides_course_progress_bar.js b/addons/website_slides/static/src/js/slides_course_progress_bar.js
new file mode 100644
index 00000000000..2412368018f
--- /dev/null
+++ b/addons/website_slides/static/src/js/slides_course_progress_bar.js
@@ -0,0 +1,47 @@
+odoo.define('website_slides.progress.bar', function (require) {
+
+ var sAnimations = require('website.content.snippets.animation');
+ var Widget = require('web.Widget');
+
+ var ProgressBar = Widget.extend({
+
+ /**
+ * @override
+ * @param {Object} el
+ * @param {number} channel_id
+ */
+ init: function (el, completion) {
+ this._super(el);
+ this.completion = completion;
+ },
+ /**
+ * @override
+ */
+ start: function () {
+ this._renderProgressBar();
+ return this._super.apply(this, arguments);
+ },
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+ _renderProgressBar: function (ev) {
+ var self = this;
+ $('.oe_slide_js_progress_bar').css('width', (self.completion <= 100 ? self.completion : 100) + '%');
+ },
+ });
+
+ sAnimations.registry.websiteSlidesProgressBar = sAnimations.Class.extend({
+ selector: '.oe_slide_js_progress_bar',
+ /**
+ * @override
+ */
+ start: function () {
+ var completion = parseInt($('.oe_slide_js_progress_bar').attr('channel_completion'));
+ var progressBar = new ProgressBar(this, completion);
+ progressBar.appendTo(".oe_slide_js_progress_bar");
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ return ProgressBar;
+ });
diff --git a/addons/website_slides/static/src/js/slides_course_quiz.js b/addons/website_slides/static/src/js/slides_course_quiz.js
new file mode 100644
index 00000000000..f98d5b3ed8a
--- /dev/null
+++ b/addons/website_slides/static/src/js/slides_course_quiz.js
@@ -0,0 +1,206 @@
+odoo.define('website_slides.quiz', function (require) {
+ 'use strict';
+ var sAnimations = require('website.content.snippets.animation');
+ var core = require('web.core');
+ var Widget = require('web.Widget');
+
+ var QWeb = core.qweb;
+
+ var Quiz= Widget.extend({
+ /**
+ * @override
+ * @param {Object} el
+ * @param {Object} data holding all the slide elements needed for the quiz
+ * It will either come from the fullscreen widget or the sAnimation at the end of this file
+ */
+ init: function(el, data){
+ this.slide = data;
+ this.answeredQuestions = [];
+ this.fullscreen = el;
+ return this._super.apply(this,arguments);
+ },
+ start: function(){
+ var self = this;
+ self._bindQuizEvents();
+ /**
+ * If the quiz is rendered by the server instead of the fullscreen widget,
+ * questions and their answers will have to be created manually from attributes
+ */
+ if(self.slide.quiz.questions.length === 0){
+ this._setQuestions();
+ }
+ return this._super.apply(this, arguments);
+ },
+ _renderSuccessModal: function(){
+ var self =this;
+ $('.o_wslides_fullscreen_quiz').append(QWeb.render('website.course.quiz.success', {
+ data: data
+ }));
+ $('.submit-quiz').remove();
+ $('.next-slide').css('display', 'inline-block');
+ $('.next-slide').click(function(){
+ self.fullscreen._goToNextSlide();
+ });
+ $('.o_wslides_quiz_success_modal_close').click(function(){
+ $('.o_wslides_quiz_success_modal').remove();
+ $('.o_wslides_quiz_modal_background').remove();
+ });
+ $(".o_wslides_quiz_modal_background").click(function(ev){
+ $(ev.currentTarget).remove();
+ $('.o_wslides_quiz_success_modal').remove();
+ });
+ },
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+ /**
+ * @private
+ * In case the quiz is rendered by the server and the data don't come from the fullscreen widget,
+ * questions and their answers will have to be set here by using attributes
+ */
+ _setQuestions: function(){
+ var self = this;
+ $('.o_wslides_quiz_question').each(function(){
+ self.slide.quiz.questions.push({
+ id: parseInt($(this).attr('id')),
+ title: $(this).attr('title'),
+ answers: []
+ });
+ })
+ for(var i = 0; i < self.slide.quiz.questions.length; i++){
+ self._setAnswersForQuestion(self.slide.quiz.questions[i]);
+ }
+ },
+ _setAnswersForQuestion: function (question){
+ var self = this;
+ $('.o_wslides_quiz_answer[question_id='+question.id+']').each(function (){
+ question.answers.push({
+ id: parseInt($(this).attr('id')),
+ text: $(this).attr('text_value'),
+ is_correct: $(this).attr('is_correct')
+ });
+ });
+ },
+ _updateProgressbar: function (){
+ var self = this;
+ var completion = self.channelCompletion <= 100 ? self.channelCompletion : 100;
+ $('.o_wslides_fullscreen_sidebar_progress_gauge').css('width', completion + "%" );
+ $('.o_wslides_progress_percentage').text(completion);
+ },
+ _bindQuizEvents: function (){
+ var self = this;
+ if (!self.slide.done){
+ $('.o_wslides_quiz_answer').each(function(){
+ $(this).click(self._onAnswerClick.bind(self));
+ });
+ }
+ $('.submit-quiz').click(self._onSubmitQuiz.bind(self));
+ },
+ _highlightAnswers: function (answers){
+ var self = this;
+ self.answeredQuestions = [];
+ for (var i = 0; i < answers.goodAnswers.length; i++){
+ $('#answer'+ answers.goodAnswers[i] +'').addClass('o_wslides_quiz_good_answer');
+ $('#answer'+ answers.goodAnswers[i] +' .o_wslides_quiz_radio_box span').replaceWith($('<i class="fa fa-check-circle"></i>'));
+ var questionID =$('#answer'+ answers.goodAnswers[i] +' .o_wslides_quiz_radio_box input').attr('question_id');
+ self.answeredQuestions.push(questionID);
+ $('.o_wslides_quiz_answer[question_id='+questionID+']:not(.o_wslides_quiz_good_answer)').addClass('o_wslides_quiz_ignored_answer');
+ $('.o_wslides_quiz_answer[question_id='+questionID+']').each(function(){
+ $(this).unbind('click')
+ });
+ $('input[question_id='+questionID+']').each(function(){
+ $(this).prop('disabled',true);
+ });
+ }
+ for (i = 0; i < answers.badAnswers.length; i++){
+ $('#answer'+ answers.badAnswers[i]).removeClass('o_wslides_quiz_good_answer')
+ .addClass('o_wslides_quiz_bad_answer')
+ .unbind('click');
+ $('#answer'+ answers.badAnswers[i] +' .o_wslides_quiz_radio_box span').replaceWith($('<i class="fa fa-times "></i>'));
+ $('#answer'+ answers.badAnswers[i] +' .o_wslides_quiz_radio_box input').prop('checked', false);
+ }
+ },
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+ _onAnswerClick: function (ev){
+ var self = this;
+ var target = $(ev.currentTarget);
+ if ((self.answeredQuestions.indexOf(target.attr('question_id'))) === -1){
+ var id = target.attr('id');
+ var question_id = target.attr('question_id');
+ $('.o_wslides_quiz_answer[question_id='+question_id+']').removeClass('o_wslides_quiz_good_answer');
+ $('#'+id+' input[type=radio]').prop('checked', true);
+ }
+ },
+ _onSubmitQuiz: function (){
+ var self = this;
+ var inputs = $('input[type=radio]:checked');
+ var values = [];
+ for (var i = 0; i < inputs.length; i++){
+ values.push(parseInt($(inputs[i]).val()));
+ }
+ if (values.length === self.slide.quiz.questions.length){
+ $('.quiz-danger').remove();
+ self._rpc({
+ route: "/slide/quiz/submit",
+ params: {
+ slide_id: self.slide.id,
+ answer_ids: values,
+ quiz_id: self.slide.quiz_id
+ }
+ }).then(function(data){
+ self._highlightAnswers(data);
+ self.slide.quiz.nb_attempts = data.attempts_count;
+ if (data.passed){
+ self.channelCompletion = data.channel_completion;
+ self._updateProgressbar();
+ $('#check-'+self.slide.id).replaceWith($('<i class="check-done o_wslides_slide_completed fa fa-check-circle"></i>'));
+ self.slide.done = true;
+ self._renderSuccessModal();
+ }
+ else {
+ $('#quiz-points').text(self.slide.quiz.nb_attempts < 3 ? self.slide.quiz.possible_rewards[self.slide.quiz.nb_attempts] : self.slide.quiz.possible_rewards[self.slide.quiz.possible_rewards.length-1]);
+ }
+ });
+ } else {
+ $('.o_wslides_fullscreen_player').append($('<p class="quiz-danger text-danger mt-1">All questions must be answered !</p>'));
+ }
+ },
+});
+
+ sAnimations.registry.websiteSlidesQuizNoFullscreen = Widget.extend({
+ selector: '.o_w_slides_quiz_no_fullscreen',
+ xmlDependencies: ['/website_slides/static/src/xml/website_slides_fullscreen.xml'],
+ init: function (el){
+ this._super.apply(this, arguments);
+ },
+ start: function (){
+ this._super.apply(this, arguments);
+ var slideID = parseInt(this.$el.attr('slide_id'),10);
+ var slideDone = this.$el.attr('slide_done');
+ var nbAttempts = parseInt(this.$el.attr('nb_attempts'), 10);
+ var firstAttemptReward = this.$el.attr('first_reward');
+ var secondAttemptReward = this.$el.attr('second_reward');
+ var thirdAttemptReward = this.$el.attr('third_reward');
+ var fourthAttemptReward = this.$el.attr('fourth_reward');
+ var possibleRewards = [firstAttemptReward,secondAttemptReward,thirdAttemptReward,fourthAttemptReward]
+ var data = {
+ id: slideID,
+ done: slideDone,
+ quiz: {
+ questions: [],
+ nb_attempts: nbAttempts,
+ possible_rewards: possibleRewards,
+ reward: nbAttempts < possibleRewards.length ? possibleRewards[nbAttempts] : possibleRewards[possibleRewards.length-1]
+ }
+ }
+ if(!slideDone){
+ var NewQuiz = new Quiz(this, data);
+ NewQuiz.appendTo(".o_w_slides_quiz_no_fullscreen");
+ }
+ }
+ });
+
+ return Quiz;
+}); \ No newline at end of file
diff --git a/addons/website_slides/static/src/js/slides_course_sidebar_list.js b/addons/website_slides/static/src/js/slides_course_sidebar_list.js
new file mode 100644
index 00000000000..11b61d4e5ec
--- /dev/null
+++ b/addons/website_slides/static/src/js/slides_course_sidebar_list.js
@@ -0,0 +1,34 @@
+odoo.define('website_slides.sidebar', function (require) {
+ 'use strict';
+ var sAnimations = require('website.content.snippets.animation');
+ var core = require('web.core');
+ var Widget = require('web.Widget');
+
+ var SideBar = Widget.extend({
+ init: function (el){
+ this._super.apply(this,arguments);
+ },
+ start: function (){
+ $('.o_wslides_fullscreen_toggle_sidebar').click(function (ev){
+ ev.preventDefault();
+ $(ev.currentTarget).toggleClass('active');
+ $('.o_wslides_fullscreen_sidebar').toggleClass('o_wslides_fullscreen_sidebar_hidden');
+ $('.o_wslides_fullscreen_player').toggleClass('o_wslides_fullscreen_player_no_sidebar')
+ })
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ sAnimations.registry.websiteSlidesSidebarList = Widget.extend({
+ selector: '.o_wslides_fullscreen_toggle_sidebar',
+ // xmlDependencies: ['/website_slides/static/src/xml/website_slides.xml'],
+ init: function (el){
+ this._super.apply(this, arguments);
+ },
+ start: function (){
+ this._super.apply(this, arguments);
+ var sideBar = new SideBar(this);
+ sideBar.appendTo(".oe_js_side_bar_list");
+ }
+ });
+}); \ No newline at end of file
diff --git a/addons/website_slides/static/src/js/slides_course_slides_list.js b/addons/website_slides/static/src/js/slides_course_slides_list.js
new file mode 100644
index 00000000000..bf634f542e3
--- /dev/null
+++ b/addons/website_slides/static/src/js/slides_course_slides_list.js
@@ -0,0 +1,251 @@
+odoo.define('website_slides.slideslist', function (require) {
+ 'use strict';
+ var sAnimations = require('website.content.snippets.animation');
+ var Widget = require('web.Widget');
+
+ var SlideUpload = require('website_slides.upload_modal');
+
+ var List = Widget.extend({
+ init: function (el){
+ this._super.apply(this,arguments);
+ this.draggedElement = undefined;
+ this.dropTarget = undefined;
+ this.slideCount = undefined;
+ this.slides = [];
+ this.categories = [];
+ },
+ start: function (){
+ this._super.apply(this,arguments);
+ this.slideCount = $('li.content-slide').length;
+ //Change links HREF to fullscreen mode for SEO
+ var links = $(".link-to-slide");
+ for (var i = 0; i < links.length; i++){
+ $(links[i]).attr('href', $(links[i]).attr('href') + "?fullscreen=1");
+ }
+ this._bindEvents();
+ },
+ _bindEvents: function (){
+ var self = this;
+ $('.slide-draggable').each(function (){
+ self._addSlideDragAndDropHandlers($(this));
+ });
+ $('.section-draggable').each(function (){
+ self._addSectionDragAndDropHandlers($(this));
+ });
+ $('.course-section').each(function (){
+ self._addDropSlideOnSectionHandler($(this));
+ });
+ },
+ _unbind: function (className){
+ $("."+className).each(function (){
+ $(this).unbind();
+ });
+ },
+ _unbindAll: function (){
+ this._unbind('slide-draggable');
+ this._unbind('section-draggable');
+ this._unbind('course-section');
+ },
+ _getSlides: function (){
+ var self = this;
+ var slides = $('li.content-slide');
+ for(var i = 0; i < slides.length;i++){
+ var slide = $(slides[i]);
+ self.slides.push({
+ id: parseInt(slide.attr('slide_id')),
+ category_id: parseInt(slide.attr('category_id')),
+ sequence: i
+ });
+ }
+ },
+ _getCategories: function (){
+ var self = this;
+ self.categories = [];
+ var categories = $('.course-section');
+ for (var i = 0; i < categories.length;i++){
+ var category = $(categories[i]);
+ self.categories.push(parseInt(category.attr('category_id')));
+ }
+ },
+ _addDropSlideOnSectionHandler: function (target){
+ var self = this;
+ target.on('drop', function (ev){
+ if (ev.preventDefault){
+ ev.preventDefault();
+ }
+ self.dropTarget = $(ev.currentTarget);
+ self.draggedElement[0].parentNode.removeChild(self.draggedElement[0]);
+ $('ul[category_id='+target.attr('category_id')+']').append(self.draggedElement)
+ self._addSlideDragAndDropHandlers(self.draggedElement);
+ self._reorderSlides();
+ });
+ target.on('dragover', function (ev){
+ if(ev.preventDefault){
+ ev.preventDefault();
+ }
+ });
+ },
+ _addSlideDragAndDropHandlers: function (target){
+ var self = this;
+ target.on('dragstart', function (ev){
+ $('.section-draggable').removeClass('hold')
+ self._unbind('section-draggable');
+ ev.originalEvent.dataTransfer.effectAllowed = 'move';
+ ev.originalEvent.dataTransfer.setData('text/html', this.outerHTML);
+ self.draggedElement = target;
+ self.draggedElement.addClass('hold');
+ });
+ target.on('dragover', function (ev){
+ if ($(ev.currentTarget) !== self.draggedElement){
+ if (ev.preventDefault){
+ ev.preventDefault();
+ }
+ target.addClass('slide-hovered');
+ }
+ });
+ target.on('dragleave', function (ev){
+ if (ev.preventDefault){
+ ev.preventDefault();
+ }
+ target.removeClass('slide-hovered');
+ });
+ target.on('drop', function (ev){
+ if (self.draggedElement.hasClass('slide-draggable') && target.hasClass('slide-draggable')){
+ if (ev.preventDefault){
+ ev.preventDefault();
+ }
+ target.removeClass('slide-hovered');
+ target.removeClass('hold');
+ if (target !== self.draggedElement){
+ self.dropTarget = $(ev.currentTarget);
+ self.draggedElement[0].parentNode.removeChild(self.draggedElement[0]);
+ var dropHTML = ev.originalEvent.dataTransfer.getData('text/html');
+ target[0].insertAdjacentHTML('beforebegin',dropHTML);
+ self.draggedElement = $(target[0].previousSibling);
+ self._reorderSlides();
+ }
+ self._unbindAll();
+ self._bindEvents();
+ }
+ });
+ target.on('dragend', function (ev){
+ if (ev.preventDefault){
+ ev.preventDefault();
+ }
+ target.removeClass('slide-hovered');
+ target.removeClass('hold');
+ });
+ },
+ _addSectionDragAndDropHandlers: function(target){
+ var self = this;
+ target.on('dragstart', function (ev){
+ self._unbind('slide-draggable');
+ self._unbind('course-section');
+ ev.originalEvent.dataTransfer.effectAllowed = 'move';
+ ev.originalEvent.dataTransfer.setData('text/html', this.outerHTML);
+ self.draggedElement = target;
+ self.draggedElement.addClass('hold');
+ });
+ target.on('dragover', function (ev){
+ if (target.hasClass('section-draggable') && self.draggedElement.hasClass('section-draggable')){
+ if (ev.preventDefault){
+ ev.preventDefault();
+ }
+ target.addClass('slide-hovered');
+ }
+ });
+ target.on('dragleave', function (ev){
+ if (ev.preventDefault){
+ ev.preventDefault();
+ }
+ target.removeClass('slide-hovered');
+ });
+ target.on('drop', function (ev){
+ if(ev.preventDefault){
+ ev.preventDefault();
+ }
+ if(self.draggedElement.hasClass('section-draggable') && target.hasClass('section-draggable')){
+ target.removeClass('slide-hovered');
+ target.removeClass('hold');
+ self.dropTarget = $(ev.currentTarget);
+ if(target !== self.draggedElement && $(ev.currentTarget).hasClass('section-draggable')){
+ self.draggedElement[0].parentNode.removeChild(self.draggedElement[0]);
+ var dropHTML = ev.originalEvent.dataTransfer.getData('text/html');
+ target[0].insertAdjacentHTML('beforebegin',dropHTML);
+ self.draggedElement = $(target[0].previousSibling);
+ self._reorderCategories();
+ self._reorderSlides();
+ self._rebindUploadButton(self.draggedElement.attr('category_id'));
+ }
+ self._unbindAll();
+ self._bindEvents();
+ }
+ });
+ target.on('dragend', function (ev){
+ if (ev.preventDefault){
+ ev.preventDefault();
+ }
+ target.removeClass('slide-hovered');
+ target.removeClass('hold');
+ });
+ },
+ _reorderCategories: function (){
+ var self = this;
+ self._getCategories();
+ self._rpc({
+ route: '/web/dataset/resequence',
+ params: {
+ model: "slide.category",
+ ids: self.categories
+ }
+ }).then(function (){
+ self._resetCategoriesIndex();
+ });
+ },
+ _resetCategoriesIndex: function (){
+ var categoriesIndexes = $('.section-index')
+ for (var i = 0; i < categoriesIndexes.length; i++){
+ $(categoriesIndexes[i]).text(i+1)
+ }
+ },
+ _reorderSlides: function(){
+ var self = this;
+ // In case the slide was transfered to another section
+ if (self.draggedElement.hasClass('slide-draggable')){
+ self.draggedElement.attr('category_id', parseInt(self.dropTarget.attr('category_id')))
+ }
+ self.slides = [];
+ self._getSlides();
+ self._rpc({
+ route: "/slides/resequence_slides",
+ params: {
+ slides_data: self.slides
+ }
+ }).then(function(){
+ });
+ },
+ _rebindUploadButton: function(categoryID){
+ var self = this;
+ this.$('.oe_slide_js_upload[data-category-id='+categoryID+']').click(function(ev){
+ ev.preventDefault();
+ var data = $(ev.currentTarget).data();
+ var dialog = new SlideUpload.SlideUploadDialog(self, data);
+ dialog.appendTo(document.body);
+ dialog.open();
+ })
+ }
+ })
+
+ sAnimations.registry.websiteSlidesCourseSlidesList = Widget.extend({
+ selector: '.oe_js_course_slides_list',
+ xmlDependencies: ['/website_slides/static/src/xml/website_slides_upload.xml'],
+ init: function (el){
+ this._super.apply(this, arguments);
+ },
+ start: function (){
+ this._super.apply(this, arguments);
+ var list = new List(this);
+ list.appendTo(".oe_js_course_slides_list");
+ }
+ });
+}); \ No newline at end of file
diff --git a/addons/website_slides/static/src/js/slides_delete_slide.js b/addons/website_slides/static/src/js/slides_delete_slide.js
new file mode 100644
index 00000000000..e3eef38502d
--- /dev/null
+++ b/addons/website_slides/static/src/js/slides_delete_slide.js
@@ -0,0 +1,88 @@
+odoo.define('website_slides.delete.slide', function (require) {
+
+ var sAnimations = require('website.content.snippets.animation');
+ var core = require('web.core');
+ var Widget = require('web.Widget');
+
+ var _t = core._t;
+ var QWeb = core.qweb;
+
+ var DeleteSlideDialog = Widget.extend({
+ template: 'website.slide.delete.slide',
+ events: {
+ 'hidden.bs.modal': 'destroy',
+ 'click button[data-dismiss="modal"]': '_cancel',
+ 'click button.delete': '_delete'
+ },
+
+ /**
+ * @override
+ * @param {Object} el
+ * @param {number} channel_id
+ */
+ init: function (el, slideID) {
+ this._super(el, slideID);
+ this.slide_id = parseInt(slideID, 10);
+ },
+ /**
+ * @override
+ */
+ start: function () {
+ this.$el.modal({
+ backdrop: 'static'
+ });
+ return this._super.apply(this, arguments);
+ },
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+ _delete: function (ev) {
+ var self = this;
+ // TO FIX: CallBack is not executed
+ $('[slide_id='+this.slide_id+']').remove();
+ this._rpc({
+ model: 'slide.slide',
+ method: 'unlink',
+ args: [[self.slide_id]],
+ }).then(function () {
+ $('[slide='+this.slide_id+']').remove();
+ });
+ },
+ /**
+ * @override
+ */
+ _cancel: function () {
+ this.trigger('cancel');
+ }
+ });
+
+ sAnimations.registry.websiteSlidesDeleteSlide = sAnimations.Class.extend({
+ selector: '.oe_slide_js_delete_slide',
+ xmlDependencies: ['/website_slides/static/src/xml/website_slides_upload.xml'],
+ read_events: {
+ 'click': '_onDeleteSlideClick',
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ _openDialog: function (slideID) {
+ new DeleteSlideDialog(this, slideID).appendTo(document.body);
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * @param {Event} ev
+ */
+ _onDeleteSlideClick: function (ev) {
+ var target = $(ev.currentTarget);
+ this._openDialog(target.attr('slide_id'));
+ },
+ });
+ return DeleteSlideDialog;
+ });
diff --git a/addons/website_slides/static/src/js/slides_upload.js b/addons/website_slides/static/src/js/slides_upload.js
index 855b7e52932..7b0a2964bf8 100644
--- a/addons/website_slides/static/src/js/slides_upload.js
+++ b/addons/website_slides/static/src/js/slides_upload.js
@@ -30,6 +30,7 @@ var SlideUploadDialog = Dialog.extend({
this._setup();
this.channelID = parseInt(options.channelId, 10);
+ this.defaultCategoryID = parseInt(options.categoryId,10)
this.canUpload = options.canUpload === 'True';
this.canPublish = options.canPublish === 'True';
@@ -198,6 +199,7 @@ var SlideUploadDialog = Dialog.extend({
*/
_getSelect2DropdownValues: function (){
var result = {};
+ var self = this;
// tags
var tagValues = [];
_.each(this.$('#tag_ids').select2('data'), function (val) {
@@ -211,11 +213,17 @@ var SlideUploadDialog = Dialog.extend({
result['tag_ids'] = tagValues;
}
// category
- var categoryValue = this.$('#category_id').select2('data');
- if (categoryValue && categoryValue.create) {
- result['category_id'] = [0, {'name': categoryValue.text}];
- } else if (categoryValue) {
- result['category_id'] = [categoryValue.id];
+ if(!self.defaultCategoryID){
+ var categoryValue = this.$('#category_id').select2('data');
+ if (categoryValue && categoryValue.create) {
+ result['category_id'] = [0, {'name': categoryValue.text}];
+ } else if (categoryValue) {
+ result['category_id'] = [categoryValue.id];
+ this.categoryID = categoryValue.id;
+ }
+ } else {
+ result['category_id'] = [self.defaultCategoryID];
+ this.categoryID = self.defaultCategoryID;
}
return result;
},
@@ -303,6 +311,25 @@ var SlideUploadDialog = Dialog.extend({
return values;
},
+ _reorderSlidesSequence: function(){
+ var self = this;
+ var slidesElement = $('li.content-slide');
+ var slides = [];
+ for(var i = 0; i < slidesElement.length;i++){
+ slides.push({
+ id: parseInt($(slidesElement[i]).attr('slide_id')),
+ category_id: parseInt($(slidesElement[i]).attr('category_id')),
+ sequence: i
+ })
+ }
+ self._rpc({
+ route: '/slides/resequence_slides',
+ params: {
+ slides_data: slides
+ }
+ }).then(function(){
+ })
+ },
/**
* Init the data relative to the support slide type to upload
*
@@ -325,6 +352,11 @@ var SlideUploadDialog = Dialog.extend({
label: _t('Video'),
template: 'website.slide.upload.modal.video',
},
+ quiz: {
+ icon: 'fa-question-circle',
+ label: _t('Quiz'),
+ template: 'website.slide.upload.quiz'
+ }
};
},
/**
@@ -472,12 +504,11 @@ var SlideUploadDialog = Dialog.extend({
_onChangeSlideUrl: function (ev) {
var self = this;
var url = $(ev.target).val();
-
this._alertRemove();
this.isValidUrl = false;
this.set('can_submit_form', false);
this._fetchUrlPreview(url).then(function (data) {
- this.set('can_submit_form', true);
+ self.set('can_submit_form', true);
if (data.error) {
self._alertDisplay(data.error);
} else {
@@ -508,6 +539,12 @@ var SlideUploadDialog = Dialog.extend({
self.set('state', oldType);
self._alertDisplay(data.error);
} else {
+ //Quick and really dirty fix for reordering issues
+ if(data.channel_type == 'training' && self.categoryID){
+ var categoryElement = $('ul[category_id='+self.categoryID+']');
+ $('<li hidden class="content-slide" slide_id="'+data.slide_id+'" category_id="'+self.categoryID+'">temp</li>').appendTo(categoryElement)
+ self._reorderSlidesSequence();
+ }
window.location = data.url;
}
});
diff --git a/addons/website_slides/static/src/js/website_slides.editor.js b/addons/website_slides/static/src/js/website_slides.editor.js
index 40513e785e2..72a18bb93ee 100644
--- a/addons/website_slides/static/src/js/website_slides.editor.js
+++ b/addons/website_slides/static/src/js/website_slides.editor.js
@@ -5,6 +5,7 @@ var core = require('web.core');
var Dialog = require('web.Dialog');
var QWeb = core.qweb;
var WebsiteNewMenu = require('website.newMenu');
+var wUtils = require('website.utils');
var _t = core._t;