odoo.define('academy.field', (require) => {
const registry = require('web.field_registry');
const Widget = require('web.AbstractField');
const ShareCount = Widget.extend({
xmlDependencies: ['/academy/static/src/xml/field.xml'],
template: 'academy.field',
events: {
'click .js_reset_field': 'resetField',
},
renderElement () {
this.stringValue = Intl.NumberFormat().format(this.value);
return this._super.apply(this, arguments);
},
isSet () {
return true;
},
async resetField (ev) {
ev.preventDefault();
this._setValue('0');
this.renderElement();
}
});
registry.add('share_count', ShareCount);
});
odoo.define('academy.chatter', (require) => {
const { PortalComposer } = require('portal.composer');
PortalComposer.include({
xmlDependencies: ['/academy/static/src/xml/portal.xml'],
events: {
'click .btn-danger': 'clearComment',
},
clearComment (ev) {
ev.preventDefault();
this.$('textarea').val(null);
},
});
});
odoo.define('academy.button', (require) => {
const { Widget, registry } = require('web.public.widget');
const Dialog = require('web.Dialog');
registry.NewButton = Widget.extend({
selector: '.js_class',
events: {
'click button': 'clickEvent',
},
start () {
this._super.apply(this, arguments);
this.button = this.el.querySelector('button');
new ClipboardJS(this.el, {
text: () => document.location.origin + this.button.dataset.url,
});
},
async clickEvent (ev) {
await this._rpc({
route: '/academy/share_count',
params: {
product_id: this.button.dataset.id,
},
});
Dialog.alert(this, 'Now you can share this content', { title: 'Copied!' });
},
});
});
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="assets_frontend" inherit_id="web.assets_frontend">
<xpath expr="//script[last()]" position="after">
<script type="text/javascript" src="/academy/static/src/js/button.js"></script>
<script type="text/javascript" src="/academy/static/src/js/chatter.js"></script>
</xpath>
<xpath expr="//link[last()]" position="after">
<link rel="stylesheet" href="/academy/static/src/sass/chatter.scss" />
</xpath>
</template>
<template id="assets_backend" inherit_id="web.assets_backend">
<xpath expr="//script[last()]" position="after">
<script type="text/javascript" src="/academy/static/src/js/field.js"></script>
</xpath>
<xpath expr="//link[last()]" position="after">
<link rel="stylesheet" href="/academy/static/src/sass/field.scss" />
</xpath>
</template>
</odoo>
<templates id="template" xml:space="preserve">
<t t-name="academy.field">
<div class="border shadow share_count_widget d-inline-flex align-items-center p-2 mx-2">
<div class="d-flex align-items-center">
<b class="field_title">Current<br/>shares</b>
<h3 class="d-flex flex-column ml-2 m-0">
<i class="fa fa-share-alt text-info mb-1" />
<i type="button" class="fa fa-times text-danger js_reset_field" />
</h3>
</div>
<div class="ml-1">
<h1 class="m-0 ml-3" t-esc="widget.stringValue" />
</div>
</div>
</t>
</templates>
<templates id="template" xml:space="preserve">
<t t-extend="portal.Composer">
<t t-jquery="button:last-of-type" t-operation="after">
<button class="btn btn-danger">Cancel</button>
</t>
</t>
</templates>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="button" inherit_id="website_sale.products_item" customize_show="True" name="Wishlist">
<xpath expr="//div[hasclass('o_wsale_product_btn')]" position="inside">
<div class="js_class d-inline">
<button class="btn btn-primary" type="button" role="button"
t-att-data-id="product.id"
t-attf-data-url="/shop/product/{{slug(product)}}">
<i class="fa fa-share-alt" role="img" />
</button>
</div>
</xpath>
</template>
<record id="product_template_form_view" model="ir.ui.view">
<field name="name">product.template.common.form.inherit</field>
<field name="inherit_id" ref="product.product_template_form_view" />
<field name="model">product.template</field>
<field name="arch" type="xml">
<xpath expr="//form/sheet//div[@name='options']" position="inside">
<div>
<field name="share_count" widget="share_count"/>
</div>
</xpath>
</field>
</record>
</odoo>
$shadow: 1px 1px 3px 0.4px grey;
.o_portal_chatter_composer_form {
textarea, &:focus {
box-shadow: $shadow !important;
border-radius: .5px;
border: none;
resize: none;
background-color: rgba(209, 195, 158, 0.17) !important;
}
button {
border-radius: 1px;
box-shadow: $shadow;
float: right;
margin-left: 10px
}
}
.o_portal_chatter_composer {
.o_portal_chatter_avatar {
border-radius: 20px;
margin-top: 1px;
@include size(55px);
animation-name: blinking;
animation-duration: 1.5s;
animation-iteration-count: infinite;
}
}
@keyframes blinking {
0% {
box-shadow: 0 0 0px 0.4px transparent;
}
30% {
box-shadow: 0 0 10px 0.9px cadetblue;
}
100% {
box-shadow: 0 0 0px 0.4px transparent;
}
}
.share_count_widget {
.field_title {
line-height: 16px;
text-align: center;
font-size: 15px;
}
}
from odoo import models, fields
class ProductTemplate(models.Model):
_inherit = 'product.template'
share_count = fields.Integer()
from odoo import http
class Controller(http.Controller):
@http.route('/academy/share_count', auth='public', type='json')
def update_share_count(self, product_id=None):
product = http.request.env['product.template'].sudo().browse(
int(product_id))
product.share_count = product.share_count + 1