Files
tryton/sao/src/notification.js
T

233 lines
9.2 KiB
JavaScript

/* This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. */
(function() {
'use strict';
class _NotificationMenu {
constructor() {
this.notify = this.notify.bind(this);
this.el = jQuery('<ul/>', {
'class': 'notification-menu dropdown-menu',
'role': 'menu',
});
this.el.on('show.bs.dropdown', () => {
this.fill();
this.indicator.hide();
});
this.indicator = jQuery('<span/>', {
'class': 'notification-badge',
});
let indicator_observer = new MutationObserver(() => {
let indicators = jQuery('.notification-badge').not(this.indicator);
indicators.text(this.indicator.text())
indicators.toggle(this.indicator.css('display') !== 'none');
});
indicator_observer.observe(
this.indicator.get(0), {
characterData: true,
attributes: true,
attributeFilter: ['style'],
});
jQuery(document).ready(() => {
// Wait for the DOM to be ready to let the observer find the
// other indicators
this.indicator.hide();
});
}
fill() {
let Notification = new Sao.Model('res.notification');
Notification.execute('get', []).done((notifications) => {
this.el.empty();
if (!notifications.length) {
jQuery('<li/>', {
'class': 'dropdown-header',
'role': 'presentation',
}).text(Sao.i18n.gettext("No notifications at this time"))
.appendTo(this.el);
} else {
for (let notification of notifications) {
let notification_item = jQuery('<div/>', {
}).append(jQuery('<span/>', {
'class': 'notification-label',
'text': notification.label,
'title': notification.label,
})).append(jQuery('<span/>', {
'class': 'notification-description',
'text': notification.description,
'title': notification.description,
}));
let link = jQuery('<a/>', {
'role': 'menuitem',
'href': '#',
}).click((evt) => {
evt.preventDefault();
this.open(notification)
}).append(notification_item);
let li = jQuery('<li/>', {
'class': 'notification-item',
'role': 'presentation',
});
let img = jQuery('<img/>', {
'class': 'icon',
});
link.prepend(img);
Sao.common.ICONFACTORY.get_icon_url(
notification.icon || 'tryton-notification')
.then(url => {
img.attr('src', url);
// Append only when the url is known to prevent
// layout shifts
li.append(link);
});
if (notification.unread) {
li.addClass('notification-unread');
}
this.el.append(li)
}
this.el.append(
jQuery('<li/>', {
'role': 'presentation',
'class': 'notification-item notification-action',
}).append(jQuery('<a/>', {
'role': 'menuitem',
'href': '#',
'title': Sao.i18n.gettext("All Notifications..."),
}).append(jQuery('<span/>', {
'class': 'caret',
})).click((evt) => {
evt.preventDefault();
let params = {
context: jQuery.extend(
{}, Sao.Session.current_session.context),
domain: [
['user', '=', Sao.Session.current_session.user_id]],
};
params.model = 'res.notification';
Sao.Tab.create(params).done(() => {
this.indicator.hide();
});
}))
);
}
this.el.append(
jQuery('<li/>', {
'role': 'separator',
'class': 'divider',
}));
let items = [
{
'text': Sao.i18n.gettext("Preferences..."),
'icon': 'tryton-launch',
'action': () => Sao.preferences(),
},
{
'text': Sao.i18n.gettext("Help..."),
'icon': 'tryton-question',
'action': () => Sao.help_dialog(),
},
{
'text': Sao.i18n.gettext("Logout"),
'icon': 'tryton-exit',
'action': () => Sao.logout(),
},
];
items.forEach((item) => {
let item_img = jQuery('<img/>', {
'class': 'icon',
});
Sao.common.ICONFACTORY.get_icon_url(item.icon)
.then(url => {
item_img.attr('src', url);
});
let item_li = jQuery('<li/>', {
'class': 'notification-item',
'role': 'presentation',
}).append(
jQuery('<a/>', {
'role': 'menuitem',
'href': '#',
'text': item.text,
}).prepend(item_img
).click((evt) => {
evt.preventDefault();
item.action();
}));
this.el.append(item_li);
});
});
}
open(notification) {
let prms = [];
if (notification.model && notification.records) {
let params = {
context: jQuery.extend({}, Sao.Session.current_session.context),
domain: [['id', 'in', notification.records]],
};
if (notification.records.length == 1) {
params['res_id'] = notification.records[0];
params['mode'] = ['form', 'tree'];
}
params.model = notification.model;
prms.push(Sao.Tab.create(params));
}
if (notification.action) {
prms.push(Sao.Action.execute(notification.action));
}
jQuery.when.apply(jQuery, prms).done(() => {
if (notification.unread) {
let Notification = new Sao.Model('res.notification');
Notification.execute('mark_read', [[notification.id]]);
}
});
}
_update(count) {
if (count > 0) {
if (count < 10) {
this.indicator.text(count);
} else {
// Let's keep the text short
this.indicator.text('9+');
}
this.indicator.show();
} else {
this.indicator.hide();
}
}
notify(message) {
if (message.type == 'user-notification') {
this._update(message.count);
try {
if (Notification.permission == "granted") {
message.content.forEach((body) => {
new Notification(
Sao.config.title, {
'body': body,
});
});
}
} catch (e) {
Sao.Logger.error(e.message, e.stack);
}
}
}
count() {
let Notification = new Sao.Model('res.notification');
Notification.execute('get_count', [])
.done((count) => {
this._update(count);
});
}
}
Sao.NotificationMenu = new _NotificationMenu();
}());