[IMP] website(_event): replace old event snippet by new dynamic one

PURPOSE

Replace the old event snippet which was a simple template with a
javascript file doing a rpc by a new one directly inherited by the
dynamic snippet.
The old snippet was displaying a list of the upcoming events based
on the user's localization. With this commit, it will be completely
replaced by the new snippet. The migration will convert the old
snippets to avoid versioning and keeping ugly code.
The new snippet allows the user to set multiples tags to display
only the wanted events on the website.

LINKS

Task-2489680
PR : odoo/odoo#68644

Related: odoo/upgrade#2406
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
Patrick Hoste
2021-11-17 13:05:53 +00:00
parent 2a0ef92a1e
commit b5c87d86ca
16 changed files with 381 additions and 122 deletions

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

+2 -1
View File
@@ -111,7 +111,7 @@
<t id="sale_products_hook"/>
<t t-snippet="website.s_searchbar" t-thumbnail="/website/static/src/img/snippets_thumbs/s_searchbar.svg"/>
<t id="blog_posts_hook"/>
<t id="event_local_events_hook"/>
<t id="event_upcoming_snippet_hook"/>
<t id="snippet_google_map_hook"/>
<t id="mass_mailing_newsletter_block_hook"/>
<t id="mass_mailing_newsletter_popup_hook"/>
@@ -166,6 +166,7 @@
<template id="external_snippets" inherit_id="website.snippets" priority="8">
<xpath expr="//div[@id='snippet_effect']//t[@t-snippet][last()]" position="after">
<t t-install="website_event" string="Events" t-thumbnail="/website/static/src/img/snippets_thumbs/s_event_upcoming_snippet.svg"/>
<t id="newsletter_popup_snippet" t-install="mass_mailing" string="Newsletter Popup" t-thumbnail="/website/static/src/img/snippets_thumbs/newsletter_subscribe_popup.svg"/>
<t t-install="website_mail_group" string="Discussion Group" t-thumbnail="/website/static/src/img/snippets_thumbs/s_group.svg"/>
<t t-install="website_twitter" string="Twitter Scroller" t-thumbnail="/website/static/src/img/snippets_thumbs/s_twitter_scroll.svg"/>
+6 -1
View File
@@ -17,8 +17,11 @@
],
'data': [
'data/event_data.xml',
'data/website_snippet_data.xml',
'views/res_config_settings_views.xml',
'views/event_snippets.xml',
'views/snippets/s_events.xml',
'views/snippets/snippets.xml',
'views/event_templates_list.xml',
'views/event_templates_page.xml',
'views/event_templates_page_registration.xml',
@@ -55,7 +58,6 @@
'website_event/static/src/scss/event_templates_page.scss',
'website_event/static/src/js/display_timer_widget.js',
'website_event/static/src/js/register_toaster_widget.js',
'website_event/static/src/js/website_geolocation.js',
'website_event/static/src/js/website_event.js',
'website_event/static/src/js/website_event_ticket_details.js',
'website_event/static/src/js/website_event_set_customize_options.js',
@@ -63,6 +65,9 @@
'website.assets_editor': [
'website_event/static/src/js/website_event.editor.js',
],
'website.assets_wysiwyg': [
'/website_event/static/src/snippets/s_events/options.js',
],
},
'license': 'LGPL-3',
}
-25
View File
@@ -375,31 +375,6 @@ class WebsiteEventController(http.Controller):
'event_ticket_ids': request.env['event.event.ticket'],
}
# ------------------------------------------------------------
# TOOLS (JSON)
# ------------------------------------------------------------
@http.route('/event/get_country_event_list', type='json', auth='public', website=True)
def get_country_events(self, **post):
Event = request.env['event.event']
country_code = request.session['geoip'].get('country_code')
result = {'events': [], 'country': False}
events = None
domain = request.website.website_domain()
if country_code:
country = request.env['res.country'].search([('code', '=', country_code)], limit=1)
events = Event.search(domain + ['|', ('address_id', '=', None), ('country_id.code', '=', country_code), ('date_begin', '>=', '%s 00:00:00' % fields.Date.today())], order="date_begin")
if not events:
events = Event.search(domain + [('date_begin', '>=', '%s 00:00:00' % fields.Date.today())], order="date_begin")
for event in events:
if country_code and event.country_id.code == country_code:
result['country'] = country
result['events'].append({
"date": self.get_formated_date(event),
"event": event,
"url": event.website_url})
return request.env['ir.ui.view']._render_template("website_event.country_events_list", result)
# ------------------------------------------------------------
# TOOLS (HELPERS)
# ------------------------------------------------------------
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo><data>
<record id="ir_filters_event_list_snippet" model="ir.filters">
<field name="name">Upcoming Events</field>
<field name="model_id">event.event</field>
<field name="user_id" eval="False" />
<field name="domain">[('date_begin', '&gt;=', context_today())]</field>
<field name="sort">['date_begin desc']</field>
</record>
<record id="website_snippet_filter_event_list" model="website.snippet.filter">
<field name="filter_id" ref="website_event.ir_filters_event_list_snippet"/>
<field name="field_names">name,subtitle</field>
<field name="limit" eval="16"/>
<field name="name">Upcoming Events</field>
</record>
</data></odoo>
+1
View File
@@ -8,4 +8,5 @@ from . import event_type
from . import website
from . import website_event_menu
from . import website_menu
from . import website_snippet_filter
from . import website_visitor
@@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import timedelta
from odoo import models, fields, _
class WebsiteSnippetFilter(models.Model):
_inherit = 'website.snippet.filter'
def _get_hardcoded_sample(self, model):
samples = super()._get_hardcoded_sample(model)
if model._name == 'event.event':
data = [{
'cover_properties': '{"background-image": "url(\'/website_event/static/src/img/event_cover_1.jpg\')", "resize_class": "o_record_has_cover o_half_screen_height", "opacity": "0.4"}',
'name': _('Great Reno Ballon Race'),
'date_begin': fields.Date.today() + timedelta(days=10),
'date_end': fields.Date.today() + timedelta(days=11),
}, {
'cover_properties': '{"background-image": "url(\'/website_event/static/src/img/event_cover_2.jpg\')", "resize_class": "o_record_has_cover o_half_screen_height", "opacity": "0.4"}',
'name': _('Conference For Architects'),
'date_begin': fields.Date.today(),
'date_end': fields.Date.today() + timedelta(days=2),
}, {
'cover_properties': '{"background-image": "url(\'/website_event/static/src/img/event_cover_3.jpg\')", "resize_class": "o_record_has_cover o_half_screen_height", "opacity": "0.4"}',
'name': _('Live Music Festival'),
'date_begin': fields.Date.today() + timedelta(weeks=8),
'date_end': fields.Date.today() + timedelta(weeks=8, days=5),
}, {
'cover_properties': '{"background-image": "url(\'/website_event/static/src/img/event_cover_5.jpg\')", "resize_class": "o_record_has_cover o_half_screen_height", "opacity": "0.4"}',
'name': _('Hockey Tournament'),
'date_begin': fields.Date.today() + timedelta(days=7),
'date_end': fields.Date.today() + timedelta(days=7),
}, {
'cover_properties': '{"background-image": "url(\'/website_event/static/src/img/event_cover_7.jpg\')", "resize_class": "o_record_has_cover o_half_screen_height", "opacity": "0.4"}',
'name': _('OpenWood Collection Online Reveal'),
'date_begin': fields.Date.today() + timedelta(days=1),
'date_end': fields.Date.today() + timedelta(days=3),
}, {
'cover_properties': '{"background-image": "url(\'/website_event/static/src/img/event_cover_4.jpg\')", "resize_class": "o_record_has_cover o_half_screen_height", "opacity": "0.4"}',
'name': _('Business Workshops'),
'date_begin': fields.Date.today() + timedelta(days=2),
'date_end': fields.Date.today() + timedelta(days=4),
}]
merged = []
for index in range(0, max(len(samples), len(data))):
merged.append({**samples[index % len(samples)], **data[index % len(data)]})
# merge definitions
samples = merged
return samples
@@ -1,37 +0,0 @@
odoo.define('website_event.geolocation', function (require) {
'use strict';
var publicWidget = require('web.public.widget');
publicWidget.registry.visitor = publicWidget.Widget.extend({
selector: ".oe_country_events, .country_events",
disabledInEditableMode: false,
/**
* @override
*/
start: function () {
var defs = [this._super.apply(this, arguments)];
var self = this;
var $eventList = this.$('.country_events_list');
this._originalContent = $eventList[0].outerHTML;
defs.push(this._rpc({route: '/event/get_country_event_list'}).then(function (data) {
if (data) {
self._$loadedContent = $(data);
self._$loadedContent.attr('contentEditable', false);
$eventList.replaceWith(self._$loadedContent);
}
}));
return Promise.all(defs);
},
/**
* @override
*/
destroy: function () {
this._super.apply(this, arguments);
if (this._$loadedContent) {
this._$loadedContent.replaceWith(this._originalContent);
}
},
});
});
@@ -0,0 +1,28 @@
/** @odoo-module **/
import publicWidget from 'web.public.widget';
import DynamicSnippet from 'website.s_dynamic_snippet';
const DynamicSnippetEvents = DynamicSnippet.extend({
selector: '.s_event_upcoming_snippet',
disabledInEditableMode: false,
/**
* @override
* @private
*/
_getSearchDomain: function () {
const searchDomain = this._super.apply(this, arguments);
const filterByTagIds = JSON.parse(this.$el.get(0).dataset.filterByTagIds || '[]');
if (filterByTagIds.length > 0) {
searchDomain.concat(Array(filterByTagIds.length-1).fill('&'));
for (const tag of filterByTagIds) {
searchDomain.push(['tag_ids', 'in', tag]);
}
}
return searchDomain;
}
});
publicWidget.registry.events = DynamicSnippetEvents;
@@ -0,0 +1,93 @@
.s_dynamic {
.s_events_event_title {
font-weight: $headings-font-weight;
line-height: 1;
}
.s_events_event_subtitle {
font-size: $font-size-base;
}
&.s_event_event_picture {
.s_events_event {
margin: 0;
min-height: 150px;
figcaption {
position: relative;
justify-content: center;
pointer-events: auto;
}
.s_events_event_cover {
min-height: 100%;
.o_record_cover_container {
top: 0;
}
}
.s_events_event_title {
@include font-size($h3-font-size);
margin-bottom: 0.5em;
}
}
.row {
align-items: stretch;
.s_events_event_subtitle {
margin: 0;
}
}
}
&.s_event_event_card {
.card {
height: 100%;
.s_events_event_cover {
height: 150px;
.o_record_cover_container {
background-color: transparent !important;
.o_record_cover_image {
@extend .card-img-top;
height: inherit;
}
}
.s_events_event_date {
top: $card-spacer-x;
right: $card-spacer-x;
display: flex;
flex-direction: column;
justify-content: center;
width: $display4-size;
height: $display4-size;
border-radius: 50%;
text-align: center;
.s_events_event_month {
font-size: $font-size-sm;
font-weight: $font-weight-bold;
text-transform: uppercase;
}
.s_events_event_day {
font-size: $font-size-lg;
font-weight: $font-weight-light;
}
}
}
a {
color: color-yiq($o-brand-primary);
&:hover {
text-decoration: none;
}
}
}
}
}
@@ -0,0 +1,55 @@
/** @odoo-module **/
import options from 'web_editor.snippets.options';
import dynamicSnippetOptions from 'website.s_dynamic_snippet_options';
const dynamicSnippetEventOptions = dynamicSnippetOptions.extend({
/**
* @override
*/
init() {
this._super.apply(this, arguments);
this.modelNameFilter = 'event.event';
this.tagIDs = [];
},
async willStart() {
const _super = this._super.bind(this);
this.tagIDs = JSON.parse(this.$target[0].dataset.filterByTagIds || '[]');
const tags = await this._rpc({
model: 'event.tag',
method: 'search_read',
domain: ['&', ['category_id.website_published', '=', true], ['color', 'not in', ['0', false]]],
fields: ['id', 'display_name'],
});
this.allTagsByID = {};
for (const tag of tags) {
this.allTagsByID[tag.id] = tag;
}
return _super(...arguments);
},
setTags(previewMode, widgetValue, params) {
this.tagIDs = JSON.parse(widgetValue).map(tag => tag.id);
this.selectDataAttribute(previewMode, JSON.stringify(this.tagIDs), params);
},
/**
* @override
*/
async _computeWidgetState(methodName, params) {
if (methodName === 'setTags') {
return JSON.stringify(this.tagIDs.map(id => this.allTagsByID[id]));
}
return this._super(...arguments);
},
_setOptionsDefaultValues() {
this._setOptionValue('numberOfRecords', 4);
this._super.apply(this, arguments);
},
});
options.registry.event_upcoming_snippet = dynamicSnippetEventOptions;
+1 -15
View File
@@ -1,29 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Snippet - Country Events - Placeholder -->
<template id="s_country_events" name="Events">
<div t-attf-class="s_country_events_list oe_country_events #{_classes}">
<div class="country_events_list">
<h6 class="o_wevent_sidebar_title">
<i class="fa fa-globe mr-2"/>Upcoming Events
</h6>
</div>
</div>
</template>
<!-- Snippets and options -->
<template id="snippets" inherit_id="website.snippets">
<xpath expr="//t[@id='event_local_events_hook']" position="replace">
<t t-snippet="website_event.s_country_events" t-thumbnail="/website_event/static/src/img/snippets_thumbs/s_country_events.svg"/>
</xpath>
<xpath expr="//t[@id='event_speaker_bio_hook']" position="replace">
<t t-snippet="website_event.s_speaker_bio" t-thumbnail="/website_event/static/src/img/snippets_thumbs/s_speaker_bio.svg"/>
</xpath>
</template>
<template id="snippet_options" inherit_id="website.snippet_options">
<xpath expr="//*[@t-set='so_content_addition_selector']" position="inside">, .oe_country_events, .s_speaker_bio</xpath>
<xpath expr="//*[@t-set='so_content_addition_selector']" position="inside">, .s_speaker_bio</xpath>
</template>
<template id="event_searchbar_input_snippet_options" inherit_id="website.searchbar_input_snippet_options" name="event search bar snippet options">
@@ -318,13 +318,4 @@
</xpath>
</template>
<!-- Index - Sidebar - Snippet - Country Events -->
<template id="index_sidebar_country_event" inherit_id="website_event.index_sidebar" active="False" customize_show="True" name="Country Events" priority="70">
<xpath expr="//div[@id='o_wevent_index_sidebar']" position="inside">
<div class="o_wevent_sidebar_block">
<t t-snippet-call="website_event.s_country_events"/>
</div>
</xpath>
</template>
</odoo>
@@ -35,40 +35,6 @@
</xpath>
</template>
<!-- Snippet - Country Events - List -->
<template id="country_events_list" name="Country Events List">
<div class="country_events_list">
<t t-if="events">
<h6 class="o_wevent_sidebar_title">
<t t-if="country">
<i class="fa fa-flag mr-2"/>Events: <span t-esc="country.name"/>
<img class="img-fluid" t-att-src="country.image_url" alt=""/>
</t>
<t t-else="">
<i class="fa fa-globe mr-2"/>Upcoming Events
</t>
</h6>
<ul class="list-group mb-3">
<li t-foreach="events[:5]" t-as="event_dict" class="list-group-item d-flex justify-content-between">
<a t-att-href="event_dict['url']">
<i t-if="not event_dict['event'].website_published" class="fa fa-ban text-danger mr-1" role="img" aria-label="Unpublished" title="Unpublished"/>
<span t-esc="event_dict['event'].name" t-attf-class="#{(not event_dict['event'].website_published) and 'text-danger' or ''}"/>
</a>
<span t-esc="event_dict['date']"/>
</li>
</ul>
<div t-if="len(events) &gt; 5">
<t t-if="country">
<a t-attf-href="/event?country=#{country.id}" class="small"><b>See all events from <span t-esc="country.name"/></b></a>
</t>
<t t-else="">
<a href="/event" class="small"><b>View all</b></a>
</t>
</div>
</t>
</div>
</template>
<!-- Timer widget -->
<template id="display_timer_widget" name="Display Timer Widget">
<t t-set="pre_countdown_display" t-value="bool(pre_countdown_text) or pre_countdown_display"/>
@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<template id="s_events" name="Events">
<t t-call="website.s_dynamic_snippet_template">
<t t-set="snippet_name" t-value="'s_events'"/>
<t t-set="snippet_classes" t-value="'s_event_upcoming_snippet'"/>
</t>
</template>
<!--TEMPLATES-->
<template id="dynamic_filter_template_event_event_picture" name="Picture Layout" priority="5">
<figure t-foreach="records" t-as="data" class="w-100 s_events_event">
<t t-set="record" t-value="data['_record']._set_tz_context()"/>
<a class="s_events_event_cover position-relative d-flex flex-column shadow-sm overflow-hidden rounded text-decoration-none"
t-att-href="data['call_to_action_url']">
<t t-call="website.record_cover">
<t t-set="_record" t-value="record"/>
<t t-set="_resize_height" t-value="512"/>
<t t-set="_resize_width" t-value="512"/>
<t t-set="use_filters" t-value="True"/>
<t t-set="additionnal_classes" t-value="'h-100 w-100 bg-600 position-absolute'"/>
</t>
<figcaption class="text-center w-100 h-100 px-3 d-flex flex-column flex-grow-1">
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
<div class="s_events_event_title text-white" t-field="record.name"/>
<time itemprop="startDate" t-att-datetime="record.date_begin" class="text-white">
<span t-out="record.date_begin"
t-options="{'widget': 'datetime', 'date_only': 'true', 'format': 'long'}"/> -
<span t-out="record.date_begin"
t-options="{'widget': 'datetime', 'time_only': 'true', 'format': 'short'}"/>
</time>
</figcaption>
</a>
</figure>
</template>
<template id="dynamic_filter_template_event_event_card" name="Card Layout" priority="10">
<div t-foreach="records" t-as="data" class="pb32 w-100 s_events_event">
<t t-set="record" t-value="data['_record']._set_tz_context()"/>
<div class="card shadow-sm">
<a class="s_events_event_cover" t-att-href="data['call_to_action_url']">
<t t-call="website.record_cover">
<t t-set="_record" t-value="record"/>
<t t-set="_resize_height" t-value="256"/>
<t t-set="_resize_width" t-value="256"/>
<div class="s_events_event_date position-absolute bg-white shadow-sm text-dark">
<span t-field="record.date_begin" t-options="{'format': 'LLL'}" class="s_events_event_month"/>
<span t-field="record.date_begin" t-options="{'format': 'dd'}" class="s_events_event_day"/>
</div>
</t>
</a>
<div class="card-body p-3">
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
<h5 class="mb-0 text-truncate" t-field="record.name"/>
<time itemprop="startDate" t-att-datetime="record.date_begin">
<span t-field="record.date_begin" t-options="{'date_only': 'true', 'format': 'long'}"/> -
<span t-field="record.date_begin" t-options="{'time_only': 'true', 'format': 'short'}"/>
</time>
<div itemprop="location" t-field="record.address_id"
t-options="{'widget': 'contact', 'fields': ['city'], 'no_marker': 'true'}"/>
</div>
</div>
</div>
</template>
<!--SNIPPET OPTIONS -->
<template id="s_events_options" inherit_id="website.snippet_options">
<xpath expr="." position="inside">
<t t-call="website_event.s_dynamic_snippet_options_template">
<t t-set="snippet_name" t-value="'event_upcoming_snippet'"/>
<t t-set="snippet_selector" t-value="'.s_event_upcoming_snippet'"/>
<t t-set="grouping_message">Items per row</t>
</t>
</xpath>
</template>
<template id="s_dynamic_snippet_options_template" inherit_id="website.s_dynamic_snippet_options_template">
<xpath expr="//we-select[@data-name='filter_opt']" position="after">
<we-many2many t-if="snippet_name == 'event_upcoming_snippet'"
string="Event Tags"
data-name="event_tag_opt"
data-model="event.event"
data-m2o-field="tag_ids"
data-domain='[["category_id.website_published", "=", true], ["color", "not in", ["0", false]]]'
data-limit="10"
data-set-tags=""
data-attribute-name="filterByTagIds"
data-no-preview="true"/>
</xpath>
</template>
<!--ASSETS-->
<record id="website_event.s_events_000_scss" model="ir.asset">
<field name="name">Event 000 SCSS</field>
<field name="bundle">web.assets_frontend</field>
<field name="path">website_event/static/src/snippets/s_events/000.scss</field>
</record>
<record id="website_event.s_events_000_js" model="ir.asset">
<field name="name">Event 000 JS</field>
<field name="bundle">web.assets_frontend</field>
<field name="path">website_event/static/src/snippets/s_events/000.js</field>
</record>
</odoo>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<template id="remove_external_snippets" inherit_id="website.external_snippets">
<xpath expr="//t[@t-install='website_event']" position="replace"/>
</template>
<template id="snippets" inherit_id="website.snippets">
<xpath expr="//t[@id='event_upcoming_snippet_hook']" position="replace">
<t t-snippet="website_event.s_events" t-thumbnail="/website/static/src/img/snippets_thumbs/s_event_upcoming_snippet.svg"/>
</xpath>
</template>
</odoo>