[IMP] website_slides{_survey}: add slide icon class field

Add a slide icon class field to prevent computing
the fa-class icon from the slide type in the template
everytime we need it.
Also, using a template wasn't suitable anymore as we
may need the icon outside of its own <i> tag
(see slide_sidebar_done_button).

Task-3378180

closes odoo/odoo#125859

Related: odoo/upgrade#4802
Signed-off-by: Warnon Aurélien (awa) <awa@odoo.com>
This commit is contained in:
amdi-odoo
2023-08-07 19:57:21 +02:00
parent 0587f914b8
commit c3157da12f
9 changed files with 39 additions and 60 deletions
@@ -183,6 +183,7 @@ class Slide(models.Model):
image_google_url = fields.Char('Image Link', related='url', readonly=False,
help="Link of the image (we currently only support Google Drive as source)")
# content - documents
slide_icon_class = fields.Char('Slide Icon fa-class', compute='_compute_slide_icon_class')
slide_type = fields.Selection([
('image', 'Image'),
('article', 'Article'),
@@ -401,6 +402,23 @@ class Slide(models.Model):
filtered_slides = category.slide_ids.filtered(lambda slide: slide.is_published)
category.completion_time = sum(filtered_slides.mapped("completion_time"))
@api.depends('slide_type')
def _compute_slide_icon_class(self):
icon_per_slide_type = {
'image': 'fa-file-picture-o',
'article': 'fa-file-text-o',
'quiz': 'fa-question-circle-o',
'pdf': 'fa-file-pdf-o',
'sheet': 'fa-file-excel-o',
'doc': 'fa-file-word-o',
'slides': 'fa-file-powerpoint-o',
'youtube_video': 'fa-youtube-play',
'google_drive_video': 'fa-play-circle-o',
'vimeo_video': 'fa-vimeo',
}
for slide in self:
slide.slide_icon_class = icon_per_slide_type.get(slide.slide_type, 'fa-file-o')
@api.depends('slide_category', 'source_type', 'video_source_type')
def _compute_slide_type(self):
""" For 'local content' or specific slide categories, the slide type is directly derived
@@ -63,7 +63,7 @@ export const SlideCoursePage = publicWidget.Widget.extend({
const newButton = QWeb.render('website.slides.sidebar.done.button', {
slideId: slide.id,
slideIcon: $button.data('slideIcon') ?? 'fa-file-o',
uncompletedIcon: $button.data('uncompletedIcon') ?? 'fa-circle-thin',
slideCompleted: completed,
canSelfMarkUncompleted: slide.canSelfMarkUncompleted,
canSelfMarkCompleted: slide.canSelfMarkCompleted,
@@ -4,18 +4,18 @@
<t t-name="website.slides.sidebar.done.button">
<div class="o_wslides_sidebar_done_button"
t-att-data-id="slideId"
t-att-data-slide-icon="slideIcon"
t-att-data-uncompleted-icon="uncompletedIcon"
t-att-data-completed="slideCompleted"
t-att-data-can-self-mark-completed="canSelfMarkCompleted"
t-att-data-can-self-mark-uncompleted="canSelfMarkUncompleted"
t-att-data-is-member="isMember"> <!-- The template is only used for members -->
<button class="o_wslides_button_complete btn btn-sm" t-if="slideCompleted and canSelfMarkUncompleted or !slideCompleted and canSelfMarkCompleted">
<i t-if="slideCompleted" class="o_wslides_slide_completed fa fa-check-circle fa-fw text-success fa-lg" t-att-data-slide-id="slideId" title="Mark as not done"/>
<i t-else="" t-attf-class="fa #{slideIcon or 'fa-circle-thin'} fa-fw fa-lg" t-att-data-slide-id="slideId" title="Mark as done"/>
<i t-else="" t-attf-class="fa #{uncompletedIcon or 'fa-circle-thin'} fa-fw fa-lg" t-att-data-slide-id="slideId" title="Mark as done"/>
</button>
<button class="o_wslides_button_complete btn btn-sm" t-else="" disabled="1">
<i t-if="slideCompleted" class="o_wslides_slide_completed fa fa-check fa-fw text-success fa-lg" t-att-data-slide-id="slideId" title="Can not be marked as not done"/>
<i t-else="" t-attf-class="fa #{slideIcon or 'fa-circle-thin'} fa-fw fa-lg" t-att-data-slide-id="slideId" title="Can not be marked as done"/>
<i t-else="" t-attf-class="fa #{uncompletedIcon or 'fa-circle-thin'} fa-fw fa-lg" t-att-data-slide-id="slideId" title="Can not be marked as done"/>
</button>
</div>
</t>
@@ -595,9 +595,7 @@
<div t-if="channel.can_publish" class=" o_wslides_slides_list_drag m-2 o_not_editable">
<i class="fa fa-sort"></i>
</div>
<t t-call="website_slides.slide_icon">
<t t-set="icon_class" t-value="'py-2 mx-2'"/>
</t>
<i t-attf-class="fa #{slide.slide_icon_class} py-2 mx-2"/>
<div class="text-truncate me-auto">
<a t-if="not invite_preview and (slide.is_preview or channel.is_member or channel.can_publish)" class="o_wslides_js_slides_list_slide_link" t-attf-href="/slides/slide/#{slug(slide)}">
<span t-field="slide.name"/>
@@ -631,6 +629,7 @@
<t t-call="website_slides.slide_sidebar_done_button">
<t t-set="is_member" t-value="channel.is_member"/>
<t t-set="slide_completed" t-value="channel_progress[slide.id].get('completed')"/>
<t t-set="use_slide_icon" t-value="False"/>
</t>
<span t-if="channel.can_publish" class="d-none d-md-flex">
<a t-if="slide.slide_category == 'article'" class="mx-2 o_text_link text-primary o_not_editable" target="_blank" t-attf-href="/slides/slide/#{slug(slide)}?enable_editor=1"><span class="fa fa-pencil"/></a>
@@ -892,19 +891,4 @@
</div>
</template>
<template id="slide_icon">
<t t-set="icon_class" t-value="icon_class if icon_class else 'me-2 text-muted'"/>
<i t-if="slide.slide_type == 'pdf'" t-att-class="'fa fa-file-pdf-o %s' % icon_class"></i>
<i t-if="slide.slide_type == 'sheet'" t-att-class="'fa fa-file-excel-o %s' % icon_class"></i>
<i t-if="slide.slide_type == 'doc'" t-att-class="'fa fa-file-word-o %s' % icon_class"></i>
<i t-if="slide.slide_type == 'slides'" t-att-class="'fa fa-file-powerpoint-o %s' % icon_class"></i>
<i t-if="slide.slide_type == 'image'" t-att-class="'fa fa-file-picture-o %s' % icon_class"></i>
<i t-if="slide.slide_type == 'youtube_video'" t-att-class="'fa fa-youtube-play %s' % icon_class"></i>
<i t-if="slide.slide_type == 'google_drive_video'" t-att-class="'fa fa-play-circle-o %s' % icon_class"></i>
<i t-if="slide.slide_type == 'vimeo_video'" t-att-class="'fa fa-vimeo %s' % icon_class"></i>
<i t-if="slide.slide_type == 'article'" t-att-class="'fa fa-file-text-o %s' % icon_class"></i>
<i t-if="slide.slide_type == 'quiz'" t-att-class="'fa fa-question-circle-o %s' % icon_class"></i>
<i t-if="not slide.slide_type" t-att-class="'fa fa-file-o %s' % icon_class"></i>
</template>
</data></odoo>
@@ -157,20 +157,10 @@
<div t-att-class="'o_wslides_lesson_aside_list_link d-flex p-1 %s%s' % (('bg-100 active' if aside_slide == slide else ''), 'text-muted' if not can_access else '')"
t-att-data-id="slide.id"
t-att-data-completed="slide_completed">
<t t-set="slide_icon" t-if="aside_slide.slide_type == 'pdf'" t-value="'fa-file-pdf-o'"/>
<t t-set="slide_icon" t-elif="aside_slide.slide_type == 'sheet'" t-value="'fa-file-excel-o'"/>
<t t-set="slide_icon" t-elif="aside_slide.slide_type == 'doc'" t-value="'fa-file-word-o'"/>
<t t-set="slide_icon" t-elif="aside_slide.slide_type == 'slides'" t-value="'fa-file-powerpoint-o'"/>
<t t-set="slide_icon" t-elif="aside_slide.slide_type == 'image'" t-value="'fa-file-picture-o'"/>
<t t-set="slide_icon" t-elif="aside_slide.slide_type == 'youtube_video'" t-value="'fa-youtube-play'"/>
<t t-set="slide_icon" t-elif="aside_slide.slide_type == 'google_drive_video'" t-value="'fa-play-circle-o'"/>
<t t-set="slide_icon" t-elif="aside_slide.slide_type == 'vimeo_video'" t-value="'fa-vimeo'"/>
<t t-set="slide_icon" t-elif="aside_slide.slide_type == 'article'" t-value="'fa-file-text-o'"/>
<t t-set="slide_icon" t-elif="aside_slide.slide_type == 'quiz'" t-value="'fa-question-circle-o'"/>
<t t-set="slide_icon" t-else="" t-value="'fa-file-o'"/>
<t t-call="website_slides.slide_sidebar_done_button">
<t t-set="slide" t-value="aside_slide"/>
<t t-set="slide_completed" t-value="channel_progress[aside_slide.id].get('completed')"/>
<t t-set="use_slide_icon" t-value="True"/>
</t>
<a t-att-href="'/slides/slide/%s' % (slug(aside_slide)) if can_access else '#'"
t-attf-class="d-flex text-decoration-none mw-100 overflow-hidden #{'text-muted' if not can_access else ''}">
@@ -233,9 +223,7 @@
<div class="col-12 col-md order-2 order-md-1 d-flex">
<div class="d-flex align-items-start">
<h1 class="h4 my-0 d-flex flex_row">
<t t-call="website_slides.slide_icon">
<t t-set="icon_class" t-valuef="me-2"/>
</t>
<i t-attf-class="fa #{slide.slide_icon_class} me-2"/>
<span t-field="slide.name"/>
</h1>
</div>
@@ -114,20 +114,10 @@
<t t-set="can_access_channel" t-value="is_member or current_slide.channel_id.can_publish"/>
<t t-foreach="slides" t-as="slide">
<t t-set="slide_completed" t-value="channel_progress[slide.id].get('completed')"/>
<t t-set="use_slide_icon" t-value="True"/>
<t t-set="can_access" t-value="can_access_channel or slide.is_preview"/>
<t t-set="is_member" t-value="current_slide.channel_id.is_member"/>
<t t-set="is_member_or_invited" t-value="is_member or current_slide.channel_id.is_member_invited"/>
<t t-set="slide_icon" t-if="slide.slide_type == 'pdf'" t-value="'fa-file-pdf-o'"/>
<t t-set="slide_icon" t-elif="slide.slide_type == 'sheet'" t-value="'fa-file-excel-o'"/>
<t t-set="slide_icon" t-elif="slide.slide_type == 'doc'" t-value="'fa-file-word-o'"/>
<t t-set="slide_icon" t-elif="slide.slide_type == 'slides'" t-value="'fa-file-powerpoint-o'"/>
<t t-set="slide_icon" t-elif="slide.slide_type == 'image'" t-value="'fa-file-picture-o'"/>
<t t-set="slide_icon" t-elif="slide.slide_type == 'youtube_video'" t-value="'fa-youtube-play'"/>
<t t-set="slide_icon" t-elif="slide.slide_type == 'google_drive_video'" t-value="'fa-play-circle-o'"/>
<t t-set="slide_icon" t-elif="slide.slide_type == 'vimeo_video'" t-value="'fa-vimeo'"/>
<t t-set="slide_icon" t-elif="slide.slide_type == 'article'" t-value="'fa-file-text-o'"/>
<t t-set="slide_icon" t-elif="slide.slide_type == 'quiz'" t-value="'fa-question-circle-o'"/>
<t t-set="slide_icon" t-else="" t-value="'fa-file-o'"/>
<li t-attf-class="o_wslides_fs_sidebar_list_item d-flex py-1 #{'active' if slide.id == current_slide.id else ''}"
t-att-data-id="slide.id"
t-att-data-can-access="can_access"
@@ -149,17 +139,15 @@
<div class="ms-2 o_wslides_sidebar_content">
<a t-if="can_access" class="d-block" href="#">
<div class="d-flex">
<t t-set="icon_class" t-value="'me-2'"/>
<t t-if="is_member" t-call="website_slides.slide_sidebar_done_button"/>
<t t-else="" t-call="website_slides.slide_icon"/>
<i t-else="" t-attf-class="fa #{slide.slide_icon_class} me-2"/>
<div class="o_wslides_fs_slide_name" t-esc="slide.name"/>
</div>
</a>
<span t-else="" class="d-block" href="#">
<div class="d-flex">
<t t-set="icon_class" t-value="'me-2 text-600'"/>
<t t-if="is_member" t-call="website_slides.slide_sidebar_done_button"/>
<t t-else="" t-call="website_slides.slide_icon"/>
<i t-else="" t-attf-class="fa #{slide.slide_icon_class} me-2 text-600"/>
<div class="o_wslides_fs_slide_name text-600" t-esc="slide.name"/>
</div>
</span>
@@ -139,21 +139,22 @@
<!-- Python equivalent of the JS template "website.slides.sidebar.done.button" -->
<template id="slide_sidebar_done_button" name="Sidebar Done Button">
<t t-set="uncompleted_icon" t-value="use_slide_icon and slide.slide_icon_class or 'fa-circle-thin'"/>
<div t-if="is_member"
class="o_wslides_sidebar_done_button align-self-start"
t-att-data-id="slide.id"
t-att-data-slide-icon="slide_icon"
t-att-data-uncompleted-icon="uncompleted_icon"
t-att-data-completed="slide_completed"
t-att-data-can-self-mark-completed="slide.can_self_mark_completed"
t-att-data-can-self-mark-uncompleted="slide.can_self_mark_uncompleted"
t-att-data-is-member="is_member">
<button class="o_wslides_button_complete btn btn-sm" t-if="slide_completed and slide.can_self_mark_uncompleted or not slide_completed and slide.can_self_mark_completed">
<i t-if="slide_completed" class="o_wslides_slide_completed fa fa-check-circle fa-fw text-success fa-lg" t-att-data-slide-id="slide.id" title="Mark as not done"/>
<i t-else="" t-attf-class="fa #{slide_icon or 'fa-circle-thin'} fa-fw fa-lg" t-att-data-slide-id="slide.id" title="Mark as done"/>
<i t-else="" t-attf-class="fa #{uncompleted_icon} fa-fw fa-lg" t-att-data-slide-id="slide.id" title="Mark as done"/>
</button>
<button class="o_wslides_button_complete o_wslides_button_uncompleted btn btn-sm" t-else="" disabled="1">
<i t-if="slide_completed" class="o_wslides_slide_completed fa fa-check fa-fw text-success fa-lg" t-att-data-slide-id="slide.id" title="Can not be marked as not done"/>
<i t-else="" t-attf-class="fa #{slide_icon or 'fa-circle-thin'} fa-fw fa-lg" t-att-data-slide-id="slide.id" title="Can not be marked as done"/>
<i t-else="" t-attf-class="fa #{uncompleted_icon} fa-fw fa-lg" t-att-data-slide-id="slide.id" title="Can not be marked as done"/>
</button>
</div>
</template>
@@ -65,6 +65,12 @@ class Slide(models.Model):
if slide.slide_category == 'certification' or not slide.is_preview:
slide.is_preview = False
@api.depends('slide_type')
def _compute_slide_icon_class(self):
certification = self.filtered(lambda slide: slide.slide_type == 'certification')
certification.slide_icon_class = 'fa-trophy'
super(Slide, self - certification)._compute_slide_icon_class()
@api.depends('slide_category', 'source_type')
def _compute_slide_type(self):
super(Slide, self)._compute_slide_type()
@@ -18,12 +18,6 @@
</xpath>
</template>
<template id="slide_icon_inherit_survey" inherit_id="website_slides.slide_icon">
<xpath expr="//i[last()]" position="after">
<i t-if="slide.slide_type == 'certification'" t-att-class="'fa fa-trophy %s' % icon_class"></i>
</xpath>
</template>
<template id="course_slides_list_slide_inherit_survey" inherit_id="website_slides.course_slides_list_slide">
<xpath expr="//a[hasclass('o_wslides_js_slides_list_slide_link')]" position="attributes">
<attribute name="t-attf-href">#{'/slides_survey/slide/get_certification_url?slide_id=%s' %(slide.id) if slide.slide_category == 'certification' and slide.channel_id.total_slides == 1 else '/slides/slide/%s' %(slug(slide))}</attribute>