[FIX] website_sale: de-traw-ify

* direct product attributes seem to not be necessary at all,
  `list_price` and `price` are just numbers
* mark `description_sale` as markup-safe at load
* mark ribbon.html as markup-safe at load
* mark embed code value as safe on rendering
This commit is contained in:
Xavier Morel
2021-07-20 05:47:26 +00:00
parent 2bd0873d44
commit 7f72555f4e
5 changed files with 20 additions and 10 deletions
@@ -56,6 +56,7 @@ var options = require('web_editor.snippets.options');
var publicWidget = require('web.public.widget');
const Wysiwyg = require('web_editor.wysiwyg');
const {qweb, _t} = require('web.core');
const {Markup} = require('web.utils');
Wysiwyg.include({
custom_events: Object.assign(Wysiwyg.prototype.custom_events, {
@@ -79,7 +80,10 @@ Wysiwyg.include({
fields: ['id', 'html', 'bg_color', 'text_color', 'html_class'],
});
}
this.ribbons = Object.fromEntries(ribbons.map(ribbon => [ribbon.id, ribbon]));
this.ribbons = Object.fromEntries(ribbons.map(ribbon => {
ribbon.html = Markup(ribbon.html);
return [ribbon.id, ribbon];
}));
this.originalRibbons = Object.assign({}, this.ribbons);
this.productTemplatesRibbons = [];
this.deletedRibbonClasses = '';
@@ -4,6 +4,7 @@ odoo.define('website_sale.video_field_preview', function (require) {
var AbstractField = require('web.AbstractField');
var core = require('web.core');
const {Markup} = require('web.utils');
var fieldRegistry = require('web.field_registry');
var QWeb = core.qweb;
@@ -16,7 +17,7 @@ var FieldVideoPreview = AbstractField.extend({
_render: function () {
this.$el.html(QWeb.render('productVideo', {
embedCode: this.value,
embedCode: Markup(this.value),
}));
},
});
@@ -5,6 +5,7 @@ const concurrency = require('web.concurrency');
const publicWidget = require('web.public.widget');
const { qweb } = require('web.core');
const { Markup } = require('web.utils');
/**
* @todo maybe the custom autocomplete logic could be extract to be reusable
@@ -56,8 +57,8 @@ publicWidget.registry.productsSearchBar = publicWidget.Widget.extend({
/**
* @private
*/
_fetch: function () {
return this._rpc({
async _fetch() {
const res = await this._rpc({
route: '/shop/products/autocomplete',
params: {
'term': this.$input.val(),
@@ -70,6 +71,10 @@ publicWidget.registry.productsSearchBar = publicWidget.Widget.extend({
},
},
});
if (this.displayDescription) {
res.products.forEach(p => {p.description_sale = Markup(p.description_sale);});
}
return res;
},
/**
* @private
@@ -4,7 +4,7 @@
<t t-name="productVideo">
<div class="embed-responsive embed-responsive-16by9 mt-2" t-if="embedCode">
<t t-raw="embedCode"/>
<t t-out="embedCode"/>
</div>
</t>
@@ -16,18 +16,18 @@
</t>
<div class="media-body px-3">
<t t-set="description" t-value="widget.displayDescription and product['description_sale']"/>
<h6 t-attf-class="font-weight-bold #{description ? '' : 'mb-0'}" t-esc="product['name']"/>
<p t-if="description" class="mb-0" t-raw="description"/>
<h6 t-attf-class="font-weight-bold #{description ? '' : 'mb-0'}" t-out="product['name']"/>
<p t-if="description" class="mb-0" t-out="description"/>
</div>
<div t-if="widget.displayPrice" class="flex-shrink-0">
<t t-if="product['has_discounted_price']">
<span class="text-danger text-nowrap" style="text-decoration: line-through;">
<t t-raw="product['list_price']"/>
<t t-out="product['list_price']"/>
</span>
<br/>
</t>
<b class="text-nowrap">
<t t-raw="product['price']"/>
<t t-out="product['price']"/>
</b>
</div>
</div>
@@ -39,7 +39,7 @@
<!-- Products Search Bar autocomplete item -->
<we-button t-name="website_sale.ribbonSelectItem" t-att-data-set-ribbon="ribbon.id">
<t t-raw="ribbon.html"/>
<t t-out="ribbon.html"/>
<span t-attf-class="fa fa-#{isTag ? 'tag' : 'bookmark'} ml-auto"></span>
<span t-attf-class="fa fa-arrow-#{isLeft ? 'left' : 'right'} ml-1"></span>
<span t-attf-class="o_wsale_color_preview #{colorClasses} ml-1" t-attf-style="background-color: #{ribbon.bg_color}"></span>