diff --git a/addons/website_slides/controllers/main.py b/addons/website_slides/controllers/main.py index e314965f52b3bee74ea9c735c611bce65454aee3..09d220ada811437749a4e132242cfbd03a4d929e 100644 --- a/addons/website_slides/controllers/main.py +++ b/addons/website_slides/controllers/main.py @@ -375,6 +375,7 @@ class WebsiteSlides(WebsiteProfile): if channel.channel_type == "training": values.update(self._get_user_progress(channel)) + values['uncategorized_slides'] = channel.slide_ids.filtered(lambda slide: not slide.category_id) return request.render('website_slides.course_main', values) @@ -419,6 +420,7 @@ class WebsiteSlides(WebsiteProfile): self._set_viewed_slide(slide) if slide.channel_id.channel_type == "training": values.update(self._get_user_progress(slide.channel_id)) + values['uncategorized_slides'] = slide.channel_id.slide_ids.filtered(lambda slide: not slide.category_id) if 'fullscreen' in kwargs: return request.render("website_slides.slide_fullscreen", values) return request.render("website_slides.slide_detail_view", values) @@ -647,7 +649,7 @@ class WebsiteSlides(WebsiteProfile): @http.route('/slides/channel/resequence', type="json", website=True, auth="user") def resequence_slides(self, channel_id, slides_data): """" Reorder the slides within the channel by reassigning their 'sequence' field. - This method also handles slides that are put in a new category. """ + This method also handles slides that are put in a new category (or uncategorized). """ channel = request.env['slide.channel'].browse(int(channel_id)) if not channel.can_publish: return {'error': 'Only the publishers of the channel can edit it'} @@ -660,7 +662,7 @@ class WebsiteSlides(WebsiteProfile): for slide in slides: slide_key = str(slide.id) slide.sequence = slides_data[slide_key]['sequence'] - slide.category_id = slides_data[slide_key]['category_id'] + slide.category_id = slides_data[slide_key]['category_id'] if 'category_id' in slides_data[slide_key] else False @http.route(['/slides/prepare_preview'], type='json', auth='user', methods=['POST'], website=True) def prepare_preview(self, **data): 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 f41c75447e4e9555b3819ac248084a617d907353..034f67231a1c8bad2ca28ad18811e3d61d276e63 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 @@ -22,10 +22,10 @@ odoo.define('website_slides.fullscreen', function (require) { * @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.courseID = parseInt(course_id, 10); - this.slideID = parseInt(slide_id, 10); - this.userID = parseInt(user_id, 10); + 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 = []; @@ -325,7 +325,7 @@ odoo.define('website_slides.fullscreen', function (require) { var self = this; self.activeTab.removeClass('active'); $('li.active').removeClass('active'); - $('li[slide_id='+self.slide.id+']').addClass('active'); + $('li[data-slide-id='+self.slide.id+']').addClass('active'); self.activeTab = $('.o_wslides_fs_sidebar_slide_tab[index="'+self.index+'"]'); self.activeTab.addClass('active'); }, @@ -356,7 +356,7 @@ odoo.define('website_slides.fullscreen', function (require) { self._getActiveSlide(); self._renderPlayer(); $('li.active').removeClass('active'); - $('li[slide_id='+self.slide.id+']').addClass('active'); + $('li[data-slide-id='+self.slide.id+']').addClass('active'); self._setPreviousAndNextSlides(); self._updateUrl(); history.pushState(null,'',self.url); @@ -416,10 +416,10 @@ odoo.define('website_slides.fullscreen', function (require) { }, start: function (){ var defs = [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); + var userId = this.$el.data('userId'); + var courseId = this.$el.data('courseId'); + var slideId = this.$el.data('slideId'); + var fullscreen = new Fullscreen(this, courseId, slideId, userId); defs.push(fullscreen.attachTo(this.$el)); return $.when.apply($, defs); } 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 index 17f0d0893aa54446c821b98dd91f600b18954825..756026b5a0cfef965f054bc2bd3dc5b15360896d 100644 --- a/addons/website_slides/static/src/js/slides_course_slides_list.js +++ b/addons/website_slides/static/src/js/slides_course_slides_list.js @@ -1,4 +1,4 @@ -odoo.define('website_slides.slideslist', function (require) { +odoo.define('website_slides.course.slides.list', function (require) { 'use strict'; var sAnimations = require('website.content.snippets.animation'); @@ -30,23 +30,41 @@ sAnimations.registry.websiteSlidesCourseSlidesList = sAnimations.Class.extend({ _bindSortable: function () { this.$('ul.o_wslides_slides_list_container').sortable({ handle: '.fa-arrows', - stop: this._reorderCategories.bind(this) + stop: this._reorderCategories.bind(this), + items: '.o_wslides_slide_list_category' }); this.$('.o_wslides_slides_list_container ul').sortable({ handle: '.fa-arrows', connectWith: '.o_wslides_slides_list_container ul', stop: this._reorderSlides.bind(this), - items: '.o_wslides_slides_list_slide' + items: '.o_wslides_slides_list_slide:not(.o_wslides_empty_category)' + }); + }, + + /** + * This method will check that a section is empty/not empty + * when the slides are reordered and show/hide the + * "Empty category" placeholder. + * + * @private + */ + _checkForEmptySections: function (){ + this.$('.o_wslides_slides_list_container ul').each(function (){ + var $emptyCategory = $(this).find('.o_wslides_empty_category'); + if ($(this).find('li.o_wslides_slides_list_slide[data-slide-id]').length === 0) { + $emptyCategory.removeClass('d-none').addClass('d-flex'); + } else { + $emptyCategory.addClass('d-none').removeClass('d-flex'); + } }); }, _getCategories: function (){ var categories = []; - this.$('.o_wslides_slide_list_category_container').each(function (){ - categories.push(parseInt($(this).attr('category_id'))); + this.$('.o_wslides_js_category').each(function (){ + categories.push(parseInt($(this).data('categoryId'))); }); - return categories; }, @@ -54,18 +72,25 @@ sAnimations.registry.websiteSlidesCourseSlidesList = sAnimations.Class.extend({ * Returns a slides dict in the form: * {slide_id: {'sequence': slide_sequence, 'category_id': slide.category_id.id}} * + * + * (Uncategorized slides don't have the category_id key) + * * @private */ _getSlides: function (){ var slides = {}; - this.$('li.o_wslides_slides_list_slide').each(function (index){ + this.$('li.o_wslides_slides_list_slide[data-slide-id]').each(function (index){ var $slide = $(this); - slides[$slide.attr('slide_id')] = { - category_id: parseInt( - $slide.closest('.o_wslides_slide_list_category').attr('category_id') - ), + var values = { sequence: index }; + + var categoryId = $slide.closest('.o_wslides_slide_list_category').data('categoryId'); + if (typeof categoryId !== typeof undefined && categoryId !== false) { + values.category_id = categoryId; + } + + slides[$slide.data('slideId')] = values; }); return slides; @@ -79,12 +104,12 @@ sAnimations.registry.websiteSlidesCourseSlidesList = sAnimations.Class.extend({ model: "slide.category", ids: self._getCategories() } - }).then(function (){ - self._resetCategoriesIndex(); }); }, _reorderSlides: function (){ + this._checkForEmptySections(); + this._rpc({ route: "/slides/channel/resequence", params: { @@ -94,15 +119,6 @@ sAnimations.registry.websiteSlidesCourseSlidesList = sAnimations.Class.extend({ }); }, - /** - * Used to reset the categories numbering (1, 2, 3, ...) in the UI - */ - _resetCategoriesIndex: function (){ - this.$('.section-index').each(function (index){ - $(this).text(index + 1); - }); - }, - /** * Change links href to fullscreen mode for SEO. * diff --git a/addons/website_slides/static/src/js/slides_slide_archive.js b/addons/website_slides/static/src/js/slides_slide_archive.js index a5d8747fdbc74443adc228631eecde8b34a0dfa9..7e5db9a5f4990dfabf82ea3a69066a423d53da32 100644 --- a/addons/website_slides/static/src/js/slides_slide_archive.js +++ b/addons/website_slides/static/src/js/slides_slide_archive.js @@ -27,7 +27,7 @@ var SlideArchiveDialog = Dialog.extend({ }); this.$slideTarget = options.slideTarget; - this.slideId = this.$slideTarget.attr('slide_id'); + this.slideId = this.$slideTarget.data('slideId'); this._super(parent, options); }, diff --git a/addons/website_slides/static/src/scss/website_slides.scss b/addons/website_slides/static/src/scss/website_slides.scss index 2324835a4015336333b36880163725101c937523..ea784106b65ee2e43ffdb60a1caf03ca322ba606 100644 --- a/addons/website_slides/static/src/scss/website_slides.scss +++ b/addons/website_slides/static/src/scss/website_slides.scss @@ -230,6 +230,46 @@ $MAX-Z-INDEX : 2147483647 !default; } } +// Slides list reordering widget +.o_wslides_slides_list { + padding: 0; + + ul { + list-style: none; + padding: 0; + } + + .o_wslides_slide_list_category_container { + margin: 0; + background-color: #ddd; + display: flex; + list-style: none; + font-size: 1.05rem; + border-bottom: 1px solid #ccc; + } + + .o_wslides_slides_list_slide { + &.o_not_editable { + height: 0px; + } + + &:nth-child(odd) { + background-color: #f6f6f6; + } + + &:nth-child(even) { + background-color: #f9f9f9; + } + + .o_wslides_slides_list_slide_controls { + i:hover { + color: $primary !important; + cursor: pointer; + } + } + } +} + // New lesson page // ************************************************** diff --git a/addons/website_slides/static/src/scss/website_slides_drag_and_drop_list.scss b/addons/website_slides/static/src/scss/website_slides_drag_and_drop_list.scss deleted file mode 100644 index bbe24c896642eed5ff2ebba13fa133652648839f..0000000000000000000000000000000000000000 --- a/addons/website_slides/static/src/scss/website_slides_drag_and_drop_list.scss +++ /dev/null @@ -1,32 +0,0 @@ -.o_wslides_slides_list { - padding: 0; - - ul { - list-style: none; - padding: 0; - } - - .o_wslides_slide_list_category_container { - margin: 0; - background-color: #ddd; - display: flex; - list-style: none; - font-size: 1.05rem; - border-bottom: 1px solid #ccc; - } - - .o_wslides_slides_list_slide:nth-child(odd) { - background-color: #f6f6f6; - } - - .o_wslides_slides_list_slide:nth-child(even) { - background-color: #f9f9f9; - } - - .o_wslides_slides_list_slide_controls { - i:hover { - color: $primary !important; - cursor: pointer; - } - } -} diff --git a/addons/website_slides/views/assets.xml b/addons/website_slides/views/assets.xml index aa67c1e68e24332eaa226797a6f09d1d59b60aef..e3e005bc93b2594c635c7056576ef34ff0e0179b 100644 --- a/addons/website_slides/views/assets.xml +++ b/addons/website_slides/views/assets.xml @@ -6,7 +6,6 @@ <xpath expr="//link[last()]" position="after"> <link rel="stylesheet" type="text/scss" href="/website_slides/static/src/scss/website_slides.scss" t-ignore="true"/> <link rel="stylesheet" type="text/scss" href="/website_slides/static/src/scss/website_slides_profile.scss"/> - <link rel="stylesheet" type="text/scss" href="/website_slides/static/src/scss/website_slides_drag_and_drop_list.scss" t-ignore="true"/> <link rel="stylesheet" type="text/scss" href="/website_slides/static/src/scss/slide_slide.scss" t-ignore="true"/> <link rel="stylesheet" type="text/scss" href="/website_slides/static/src/scss/slides_slide_fullscreen.scss" t-ignore="true"/> <link rel="stylesheet" type="text/scss" href="/website_slides/static/src/scss/website_slides_quiz.scss"/> diff --git a/addons/website_slides/views/website_slides_templates_course.xml b/addons/website_slides/views/website_slides_templates_course.xml index 352aaf1633c687b3e315d4eb0010a0d89b9ebe08..c42eb4bea30ec8c0ab4693e89072d47478f2e2dd 100644 --- a/addons/website_slides/views/website_slides_templates_course.xml +++ b/addons/website_slides/views/website_slides_templates_course.xml @@ -234,7 +234,7 @@ </div> </div> </div> - <t t-if="channel.channel_type == 'training'" t-call="website_slides.course_content_training"/> + <t t-if="channel.channel_type == 'training'" t-call="website_slides.course_slides_list"/> <t t-if="channel.channel_type == 'documentation'" t-call="website_slides.course_content_documentation"/> </div> </div> @@ -243,54 +243,43 @@ </t> </template> -<template id="course_content_training" name="Content of a training channel"> +<template id="course_slides_list" name="Content of a training channel"> <div class="col-8 d-flex flex-column ml-4"> <div class="o_wslides_slides_list w-100 mt8" t-att-data-channel-id="channel.id"> <ul class="o_wslides_slides_list_container"> - <t t-set="i" t-value="1"/> <t t-set="j" t-value="0"/> - <t t-foreach="channel.category_ids" t-as="category"> - <li class="o_wslides_slide_list_category" t-attf-category_id="#{category.id}"> - <div t-attf-category_id="#{category.id}" class="o_wslides_slide_list_category_container text-muted font-weight-bold pt-0 pb-0 pl-2 pr-2 d-flex justify-content-between align-items-center"> - <div style="width:50%;" class="d-flex align-items-center"> - <i t-if="channel.can_publish" class="fa fa-arrows mr-3 text-muted"></i> - <div class="mr-2">Section <span class="section-index" t-esc="i"/>:</div> - <span t-field="category.name"/> + <li t-if="uncategorized_slides or channel.can_publish"> + <div class="text-muted font-weight-bold pt-0 pb-0 pl-2 pr-2 d-flex justify-content-between align-items-center"> + <t t-call="website_slides.course_slides_list_category"/> + </div> + <ul> + <li t-att-class="('text-muted font-italic o_wslides_slides_list_slide o_wslides_empty_category justify-content-between align-items-center p-2 %s') % ('d-none' if uncategorized_slides else 'd-flex')"> + <div class="content-slide-infos ml-2"> + <span>Empty category</span> </div> - <a class="mr-2 oe_slide_js_upload" - role="button" - aria-label="Upload Presentation" - href="#" - style="font-size: 1.5rem;text-decoration: none;" - t-att-data-channel-id="channel.id" - t-att-data-category-id="category.id" - t-att-data-can-upload="channel.can_upload" - t-att-data-can-publish="channel.can_publish">+</a> - <t t-set="i" t-value="i+1"/> + </li> + <li class="o_wslides_slides_list_slide o_not_editable"></li> + <t t-foreach="uncategorized_slides" t-as="slide"> + <t t-call="website_slides.course_slides_list_slide" /> + <t t-set="j" t-value="j+1"/> + </t> + </ul> + </li> + <t t-foreach="channel.category_ids" t-as="category"> + <li t-if="category.slide_ids or channel.can_publish" class="o_wslides_slide_list_category" t-att-data-category-id="category.id"> + <div t-att-data-category-id="category.id" + class="o_wslides_js_category text-muted font-weight-bold pt-0 pb-0 pl-2 pr-2 d-flex justify-content-between align-items-center"> + <t t-call="website_slides.course_slides_list_category" /> </div> - <ul t-attf-category_id="#{category.id}" > + <ul t-att-data-category-id="category.id"> + <li t-att-class="('text-muted font-italic o_wslides_slides_list_slide o_wslides_empty_category justify-content-between align-items-center p-2 %s') % ('d-none' if category.slide_ids else 'd-flex')"> + <div class="content-slide-infos ml-2"> + <span>Empty category</span> + </div> + </li> + <li class="o_wslides_slides_list_slide o_not_editable"></li> <t t-foreach="category.slide_ids" t-as="slide"> - <li t-att-index="j" t-attf-slide_id="#{slide.id}" t-attf-category_id="#{category.id}" - class="o_wslides_slides_list_slide d-flex justify-content-between align-items-center p-2"> - <div class="ml-2"> - <i t-if="channel.can_publish" class="fa fa-arrows mr-2 text-muted"></i> - <i t-if="slide.slide_type == 'document'" class="fa fa-file-pdf-o mr-2 text-muted"></i> - <i t-if="slide.slide_type == 'infographic'" class="fa fa-file-picture-o mr-2 text-muted"></i> - <i t-if="slide.slide_type == 'video'" class="fa fa-play-circle mr-2 text-muted"></i> - <i t-if="slide.slide_type == 'link'" class="fa fa-file-code-o mr-2 text-muted"></i> - <i t-if="slide.slide_type == 'webpage'" class="fa fa-file-text mr-2 text-muted"></i> - <i t-if="slide.slide_type == 'quiz'" class="fa fa-question-circle mr-2 text-muted"></i> - <i t-if="slide.slide_type == 'certification'" class="fa fa-trophy mr-2 text-muted"></i> - <a class="o_wslides_slides_list_slide_link" t-attf-href="/slides/slide/#{slug(slide)}"><span t-field="slide.name"/></a> - </div> - <div class="o_wslides_slides_list_slide_controls mr-2"> - <i t-if="not slide.id in user_progress or not user_progress[slide.id].completed" class="check-done fa fa-check-circle text-muted mr-1"></i> - <i t-if="slide.id in user_progress and user_progress[slide.id].completed" class="check-done text-primary fa fa-check-circle mr-1"></i> - <a t-if="channel.can_publish and not slide.slide_type == 'webpage'" t-attf-href="/web#id=#{slide.id}&action=#{slide_action}&model=slide.slide&view_type=form"><i class="fa fa-pencil text-muted mr-1"></i></a> - <a t-if="channel.can_publish and slide.slide_type == 'webpage'" t-attf-href="/slides/slide/#{slug(slide)}?enable_editor=1"><i class="fa fa-pencil text-muted mr-1"></i></a> - <i t-if="channel.can_publish" t-attf-slide_id="#{slide.id}" class="fa fa-trash text-muted o_wslides_js_slide_archive"></i> - </div> - </li> + <t t-call="website_slides.course_slides_list_slide" /> <t t-set="j" t-value="j+1"/> </t> </ul> @@ -313,6 +302,55 @@ </div> </template> +<template id="course_slides_list_slide" name="Slide template for a training channel"> + <li t-att-index="j" t-att-data-slide-id="slide.id" t-att-data-category-id="category.id if category else None" + class="o_wslides_slides_list_slide d-flex justify-content-between align-items-center p-2"> + <div class="ml-2"> + <i t-if="channel.can_publish" class="fa fa-arrows mr-2 text-muted"></i> + <i t-if="slide.slide_type == 'document'" class="fa fa-file-pdf-o mr-2 text-muted"></i> + <i t-if="slide.slide_type == 'infographic'" class="fa fa-file-picture-o mr-2 text-muted"></i> + <i t-if="slide.slide_type == 'video'" class="fa fa-play-circle mr-2 text-muted"></i> + <i t-if="slide.slide_type == 'link'" class="fa fa-file-code-o mr-2 text-muted"></i> + <i t-if="slide.slide_type == 'webpage'" class="fa fa-file-text mr-2 text-muted"></i> + <i t-if="slide.slide_type == 'quiz'" class="fa fa-question-circle mr-2 text-muted"></i> + <i t-if="slide.slide_type == 'certification'" class="fa fa-trophy mr-2 text-muted"></i> + <a class="o_wslides_slides_list_slide_link" t-attf-href="/slides/slide/#{slug(slide)}"><span t-field="slide.name"/></a> + </div> + <div class="o_wslides_slides_list_slide_controls mr-2"> + <i t-if="not slide.id in user_progress or not user_progress[slide.id].completed" class="check-done fa fa-check-circle text-muted mr-1"></i> + <i t-if="slide.id in user_progress and user_progress[slide.id].completed" class="check-done text-primary fa fa-check-circle mr-1"></i> + <a t-if="channel.can_publish and not slide.slide_type == 'webpage'" t-attf-href="/web#id=#{slide.id}&action=#{slide_action}&model=slide.slide&view_type=form"> + <i class="fa fa-pencil text-muted mr-1"></i> + </a> + <a t-if="channel.can_publish and slide.slide_type == 'webpage'" t-attf-href="/slides/slide/#{slug(slide)}?enable_editor=1"> + <i class="fa fa-pencil text-muted mr-1"></i> + </a> + <i t-if="channel.can_publish" t-att-data-slide-id="slide.id" class="fa fa-trash text-muted o_wslides_js_slide_archive"></i> + </div> + </li> +</template> + +<template id="course_slides_list_category" name="Category template for a training channel"> + <div style="width:50%;" class="d-flex align-items-center"> + <i t-if="channel.can_publish and category" class="fa fa-arrows mr-3 text-muted"></i> + <t t-if="category"> + <span t-field="category.name"/> + </t> + <t t-else=""> + <span>Uncategorized</span> + </t> + </div> + <a class="mr-2 oe_slide_js_upload" + role="button" + aria-label="Upload Presentation" + href="#" + style="font-size: 1.5rem;text-decoration: none;" + t-att-data-channel-id="channel.id" + t-att-data-category-id="category.id if category else None" + t-att-data-can-upload="channel.can_upload" + t-att-data-can-publish="channel.can_publish">+</a> +</template> + <template id="course_content_documentation" name="Content of a training channel"> <div t-if="not search" class="col-md-8 col-xs-12 mt16 o_wslides_channel_content_promoted"> <div class="row align-items-center"> diff --git a/addons/website_slides/views/website_slides_templates_lesson.xml b/addons/website_slides/views/website_slides_templates_lesson.xml index 84062e64c5eebb8a0b852bb0abc64f7d4f46169d..778baeebd4fbfe52712e2007e264e93650aa20af 100644 --- a/addons/website_slides/views/website_slides_templates_lesson.xml +++ b/addons/website_slides/views/website_slides_templates_lesson.xml @@ -29,43 +29,13 @@ </div> </li> <t t-set="i" t-value="0"/> + <t t-if="uncategorized_slides" t-call="website_slides.slide_detail_list_category_view"> + <t t-set="category_slide_ids" t-value="uncategorized_slides" /> + </t> <t t-foreach="slide.channel_id.category_ids" t-as="category"> - <a data-toggle="collapse" t-attf-href="#collapse-#{category.id}" role="button" aria-expanded="false" t-attf-aria-controls="collapse-#{category.id}"> - <li class="o_wslides_slide_content_list_section"> - <span t-field="category.name"/> - </li> - </a> - <ul class="collapse p-0 m-0" t-attf-id="collapse-#{category.id}" > - <t t-foreach="category.slide_ids" t-as="course_slide"> - <li class="o_wslides_slide_content_list_slide"> - <a t-attf-href="/slides/slide/#{slug(course_slide)}" t-att-index="i" t-att-slide_id="course_slide.id"> - <div t-attf-index="#{i}" t-attf-slide_id="#{course_slide.id}" t-attf-class="#{'active' if slide.id == course_slide.id else ''} d-flex justify-content-between"> - <div> - <i t-if="course_slide.slide_type == 'presentation'" class="fa fa-file-pdf-o mr-2 text-muted"></i> - <i t-if="course_slide.slide_type == 'infographic'" class="fa fa-file-picture-o mr-2 text-muted"></i> - <i t-if="course_slide.slide_type == 'video'" class="fa fa-play-circle mr-2 text-muted"></i> - <i t-if="course_slide.slide_type == 'link'" class="fa fa-file-code-o mr-2 text-muted"></i> - <i t-if="course_slide.slide_type == 'webpage'" class="fa fa-file-text mr-2 text-muted"></i> - <i t-if="course_slide.slide_type == 'quiz'" class="fa fa-question-circle mr-2 text-muted"></i> - <t t-esc="course_slide.name"/> - </div> - <div class="o_wslides_slides_list_slide_controls mr-2"> - <i t-attf-id="check-#{course_slide.id}" t-if="course_slide.id in user_progress and not user_progress[course_slide.id].completed" class="check-done fa fa-check-circle text-muted mr-1"></i> - <i t-attf-id="check-#{course_slide.id}" t-if="course_slide.id in user_progress and user_progress[course_slide.id].completed" class="check-done text-primary fa fa-check-circle mr-1"></i> - </div> - </div> - </a> - <ul t-if="course_slide.link_ids" class="list-group o_wslides_slide_resources"> - <t t-foreach="course_slide.link_ids" t-as="resource"> - <a t-attf-href="#{resource.link}" target="new"> - <li><div class="o_wslides_slide_resource"><i class="fa fa-link"></i><span t-field="resource.link"/></div></li> - </a> - </t> - </ul> - </li> - <t t-set="i" t-value="i+1"/> - </t> - </ul> + <t t-call="website_slides.slide_detail_list_category_view"> + <t t-set="category_slide_ids" t-value="category.slide_ids"/> + </t> </t> </ul> </div> @@ -85,7 +55,7 @@ <a class="o_wslides_slide_button" t-attf-href="/slides/slide/#{previous_slide}">Prev</a> </t> <a t-if="slide.slide_type in ('webpage', 'video', 'document', 'iconographic') and not slide.question_ids and (slide.id in user_progress and not user_progress[slide.id].completed)" - t-att-href="'/slides/slide/%s/set_completed?next_slide=%s' % (slide.id, next_slide.id)" + t-att-href="'/slides/slide/%s/set_completed?%s' % (slide.id, 'next_slide=%s' % next_slide if next_slide else '')" class="o_wslides_slide_button_done">Set Done</a> <t t-if="next_slide"> <a class="o_wslides_slide_button" t-attf-href="/slides/slide/#{next_slide}">Next</a> @@ -446,10 +416,59 @@ </t> </template> +<template id="slide_detail_list_category_view" name="Category item for the slide detailed view list"> + <a data-toggle="collapse" t-att-href="('#collapse-%s') % (category.id if category else 0)" role="button" aria-expanded="true" t-att-aria-controls="('collapse-%s') % (category.id if category else 0)"> + <li class="o_wslides_slide_content_list_section"> + <t t-if="category"> + <span t-field="category.name"/> + </t> + <t t-else=""> + <span>Uncategorized</span> + </t> + </li> + </a> + <ul class="collapse show p-0 m-0" t-att-id="('collapse-%s') % (category.id if category else 0)" > + <t t-foreach="category_slide_ids" t-as="course_slide"> + <li class="o_wslides_slide_content_list_slide"> + <a t-attf-href="/slides/slide/#{slug(course_slide)}" t-att-index="i" t-att-slide_id="course_slide.id"> + <div t-attf-index="#{i}" t-attf-slide_id="#{course_slide.id}" t-attf-class="#{'active' if slide.id == course_slide.id else ''} d-flex justify-content-between"> + <div> + <i t-if="course_slide.slide_type == 'presentation'" class="fa fa-file-pdf-o mr-2 text-muted"></i> + <i t-if="course_slide.slide_type == 'infographic'" class="fa fa-file-picture-o mr-2 text-muted"></i> + <i t-if="course_slide.slide_type == 'video'" class="fa fa-play-circle mr-2 text-muted"></i> + <i t-if="course_slide.slide_type == 'link'" class="fa fa-file-code-o mr-2 text-muted"></i> + <i t-if="course_slide.slide_type == 'webpage'" class="fa fa-file-text mr-2 text-muted"></i> + <i t-if="course_slide.slide_type == 'quiz'" class="fa fa-question-circle mr-2 text-muted"></i> + <t t-esc="course_slide.name"/> + </div> + <div class="o_wslides_slides_list_slide_controls mr-2"> + <i t-attf-id="check-#{course_slide.id}" t-if="course_slide.id in user_progress and not user_progress[course_slide.id].completed" class="check-done fa fa-check-circle text-muted mr-1"></i> + <i t-attf-id="check-#{course_slide.id}" t-if="course_slide.id in user_progress and user_progress[course_slide.id].completed" class="check-done text-primary fa fa-check-circle mr-1"></i> + </div> + </div> + </a> + <ul t-if="course_slide.link_ids" class="list-group"> + <t t-foreach="course_slide.link_ids" t-as="resource"> + <a t-attf-href="#{resource.link}" target="new"> + <li><div><i class="fa fa-link"></i><span t-field="resource.link"/></div></li> + </a> + </t> + </ul> + </li> + <t t-set="i" t-value="i+1"/> + </t> + </ul> +</template> + <!-- Slide template for the fullscreen mode --> <template id="slide_fullscreen" name="Fullscreen"> <t t-call="website.layout"> - <div class="o_wslides_fs_main"> + <div class="o_wslides_fs_main" + t-att-data-user-id="user.id" + t-att-data-course-name="slide.channel_id.name" + t-att-data-course-id="slide.channel_id.id" + t-att-data-course-slug="slug(slide.channel_id)" + t-att-data-slide-id="slide.id"> <div class="o_wslides_slide_fs_header"> <div> <a id="fullscreen_sidebar_button" href="#" class="active o_wslides_fs_toggle_sidebar"><i class="fa fa-bars"></i>Lessons</a> @@ -476,74 +495,87 @@ </div> </div> </li> - <t t-set="i" t-value="0"/> + <t t-if="uncategorized_slides" t-call="website_slides.slide_fullscreen_sidebar_category"> + <t t-set="category_slide_ids" t-value="uncategorized_slides" /> + </t> <t t-foreach="slide.channel_id.category_ids" t-as="category"> - <div class="o_wslides_fs_sidebar_section"> - <a data-toggle="collapse" t-attf-href="#collapse-#{category.id}" role="button" aria-expanded="true" t-attf-aria-controls="collapse-#{category.id}"> - <li> - <span t-field="category.name"/> - </li> - </a> - <ul class="o_wslides_fs_sidebar_section_slides collapsed p-0 m-0" t-attf-id="collapse-#{category.id}" > - <t t-foreach="category.slide_ids" t-as="course_slide"> - <li t-attf-index="#{i}" t-att-slide_id="course_slide.id" t-attf-class="#{'active' if slide.id == course_slide.id else ''}"> - <span> - <span class="o_wslides_top_line"></span> - <i t-attf-id="check-#{course_slide.id}" t-if="not course_slide.id in user_progress or not user_progress[course_slide.id].completed" class="check-done fa fa-circle-thin"></i> - <i t-attf-id="check-#{course_slide.id}" t-if="course_slide.id in user_progress and user_progress[course_slide.id].completed" class="check-done o_wslides_slide_completed fa fa-check-circle"></i> - <span class="o_wslides_bottom_line"></span> - </span> - <a t-att-index="i" t-att-slide_id="course_slide.id"> - <div t-attf-index="#{i}" - t-att-data-slug="slug(course_slide)" - t-att-data-done="course_slide.id in user_progress and user_progress[course_slide.id].completed" - t-att-data-id="course_slide.id" - t-att-data-name="course_slide.name" - t-attf-data-has_quiz="#{True if course_slide.question_ids else False}" - t-att-data-slide_type="course_slide.slide_type" - t-att-data-embed_code="course_slide.embed_code" - t-attf-class="o_wslides_fs_sidebar_slide_tab #{'active' if slide.id == course_slide.id else ''} d-flex justify-content-between"> - <div> - <i t-if="course_slide.slide_type == 'document'" class="fa fa-file-pdf-o mr-2 text-muted"></i> - <i t-if="course_slide.slide_type == 'infographic'" class="fa fa-file-picture-o mr-2 text-muted"></i> - <i t-if="course_slide.slide_type == 'video'" class="fa fa-play-circle mr-2 text-muted"></i> - <i t-if="course_slide.slide_type == 'link'" class="fa fa-file-code-o mr-2 text-muted"></i> - <i t-if="course_slide.slide_type == 'webpage'" class="fa fa-file-text mr-2 text-muted"></i> - <i t-if="course_slide.slide_type == 'quiz'" class="fa fa-question-circle mr-2 text-muted"></i> - <i t-if="course_slide.slide_type == 'certification'" class="fa fa-trophy mr-2 text-muted"></i> - <t t-esc="course_slide.name"/> - </div> - </div> - </a> - </li> - <t t-if="course_slide.link_ids" t-foreach="course_slide.link_ids" t-as="link"> - <li> - <span> - <span class="o_wslides_fs_full_line"/> - </span> - <a class="o_wslides_fs_slide_link" t-att-href="link.link" target="new"><i class="fa fa-link"></i><span t-esc="link.name"/></a> - </li> - </t> - <li t-attf-index="#{i}" t-if="course_slide.question_ids and not course_slide.slide_type =='quiz'"> - <span> - <span class="o_wslides_fs_full_line"/> - </span> - <span class="o_wslides_fs_slide_quiz" t-attf-index="#{i}"><i class="fa fa-flag-checkered"></i>Quiz: <span t-esc="course_slide.name"/></span> - </li> - <t t-set="i" t-value="i+1"/> - </t> - </ul> - </div> + <t t-call="website_slides.slide_fullscreen_sidebar_category"> + <t t-set="category_slide_ids" t-value="category.slide_ids" /> + </t> </t> </ul> </div> - <div class="oe_js_course_slide" t-attf-user_id="#{user.id}" t-attf-course_name="#{slide.channel_id.name}" t-attf-course_id="#{slide.channel_id.id}" t-attf-course_slug="#{slug(slide.channel_id)}" t-attf-slide_id="#{slide.id}"/> <div class="o_wslides_fs_player"/> </div> </div> </t> </template> +<template id="slide_fullscreen_sidebar_category" name="Slides category template for fullscreen view side bar"> + <div class="o_wslides_fs_sidebar_section"> + <a data-toggle="collapse" t-att-href="('#collapse-%s') % (category.id if category else 0)" role="button" aria-expanded="true" t-att-aria-controls="('collapse-%s') % (category.id if category else 0)"> + <li> + <t t-if="category"> + <span t-field="category.name"/> + </t> + <t t-else=""> + <span>Uncategorized</span> + </t> + </li> + </a> + <ul class="o_wslides_fs_sidebar_section_slides collapse show p-0 m-0" t-att-id="('collapse-%s') % (category.id if category else 0)" > + <t t-foreach="category_slide_ids" t-as="course_slide"> + <!-- AWA FIXME: remove that index crap but right now fullscreen JS uses it too much --> + <t t-set="i" t-value="list(slide.channel_id.slide_ids).index(course_slide)"/> + <li t-att-index="i" t-att-data-slide-id="course_slide.id" t-attf-class="#{'active' if slide.id == course_slide.id else ''}"> + <span> + <span class="o_wslides_top_line"></span> + <i t-attf-id="check-#{course_slide.id}" t-if="not course_slide.id in user_progress or not user_progress[course_slide.id].completed" class="check-done fa fa-circle-thin"></i> + <i t-attf-id="check-#{course_slide.id}" t-if="course_slide.id in user_progress and user_progress[course_slide.id].completed" class="check-done o_wslides_slide_completed fa fa-check-circle"></i> + <span class="o_wslides_bottom_line"></span> + </span> + <a t-att-index="i" t-att-data-slide-id="course_slide.id"> + <div t-attf-index="#{i}" + t-att-data-slug="slug(course_slide)" + t-att-data-done="course_slide.id in user_progress and user_progress[course_slide.id].completed" + t-att-data-id="course_slide.id" + t-att-data-name="course_slide.name" + t-attf-data-has_quiz="#{True if course_slide.question_ids else False}" + t-att-data-slide_type="course_slide.slide_type" + t-att-data-embed_code="course_slide.embed_code" + t-attf-class="o_wslides_fs_sidebar_slide_tab #{'active' if slide.id == course_slide.id else ''} d-flex justify-content-between"> + <div> + <i t-if="course_slide.slide_type == 'document'" class="fa fa-file-pdf-o mr-2 text-muted"></i> + <i t-if="course_slide.slide_type == 'infographic'" class="fa fa-file-picture-o mr-2 text-muted"></i> + <i t-if="course_slide.slide_type == 'video'" class="fa fa-play-circle mr-2 text-muted"></i> + <i t-if="course_slide.slide_type == 'link'" class="fa fa-file-code-o mr-2 text-muted"></i> + <i t-if="course_slide.slide_type == 'webpage'" class="fa fa-file-text mr-2 text-muted"></i> + <i t-if="course_slide.slide_type == 'quiz'" class="fa fa-question-circle mr-2 text-muted"></i> + <i t-if="course_slide.slide_type == 'certification'" class="fa fa-trophy mr-2 text-muted"></i> + <t t-esc="course_slide.name"/> + </div> + </div> + </a> + </li> + <t t-if="course_slide.link_ids" t-foreach="course_slide.link_ids" t-as="link"> + <li> + <span> + <span class="o_wslides_fs_full_line"/> + </span> + <a class="o_wslides_fs_slide_link" t-att-href="link.link" target="new"><i class="fa fa-link"></i><span t-esc="link.name"/></a> + </li> + </t> + <li t-att-index="i" t-if="course_slide.question_ids and not course_slide.slide_type =='quiz'"> + <span> + <span class="o_wslides_fs_full_line"/> + </span> + <span class="o_wslides_fs_slide_quiz" t-att-index="i"><i class="fa fa-flag-checkered"></i>Quiz: <span t-esc="course_slide.name"/></span> + </li> + </t> + </ul> + </div> +</template> + <!-- Slide sub-template: display an item in a list of related slides (Related, Most Viewed, ...) --> <template id="related_slides" name="Related Slide"> <li class="media mt-3">