We need to keep a reference to the binded method registered to be able to unregister it. Closes #14425
204 lines
7.2 KiB
JavaScript
204 lines
7.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 _Chat {
|
|
constructor(record) {
|
|
this.notify = this.notify.bind(this);
|
|
this.record = record;
|
|
Sao.Bus.register(`chat:${this.record}`, this.notify);
|
|
this.el = this.__build();
|
|
}
|
|
|
|
unregister() {
|
|
Sao.Bus.unregister(`chat:${this.record}`, this.notify);
|
|
}
|
|
|
|
send_message(message, internal) {
|
|
return Sao.rpc({
|
|
'method': 'model.ir.chat.channel.post',
|
|
'params': [this.record, message, internal ? 'internal' : 'public', {}],
|
|
}, Sao.Session.current_session)
|
|
}
|
|
|
|
get_messages() {
|
|
return Sao.rpc({
|
|
'method': 'model.ir.chat.channel.get',
|
|
'params': [this.record, {}],
|
|
}, Sao.Session.current_session);
|
|
}
|
|
|
|
notify(message) {
|
|
this.refresh();
|
|
}
|
|
|
|
refresh() {
|
|
let prm = this.get_messages();
|
|
prm.done((posts) => {
|
|
this._messages.empty();
|
|
for (let post of posts) {
|
|
this._messages.append(this.create_message(post));
|
|
}
|
|
|
|
let messages = this._messages[this._messages.length - 1];
|
|
messages.scrollTop = messages.scrollHeight;
|
|
});
|
|
}
|
|
|
|
__build() {
|
|
let el = jQuery('<div/>', {
|
|
'class': 'chat',
|
|
});
|
|
|
|
let btn_group = jQuery('<div/>', {
|
|
'class': 'btn-group',
|
|
'role': 'group',
|
|
}).appendTo(el);
|
|
|
|
let subscribe_btn = jQuery('<button/>', {
|
|
'class': 'btn btn-default pull-right',
|
|
'type': 'button',
|
|
'title': Sao.i18n.gettext("Toggle notification"),
|
|
}).append(Sao.common.ICONFACTORY.get_icon_img(
|
|
'tryton-notification'))
|
|
.appendTo(btn_group);
|
|
|
|
Sao.rpc({
|
|
'method': 'model.ir.chat.channel.get_followers',
|
|
'params': [this.record, {}],
|
|
}, Sao.Session.current_session).then((followers) => {
|
|
set_subscribe_state(~followers.users.indexOf(
|
|
Sao.Session.current_session.login));
|
|
})
|
|
|
|
let set_subscribe_state = (subscribed) => {
|
|
let img;
|
|
if (subscribed) {
|
|
img = 'tryton-notification-on';
|
|
subscribe_btn.addClass('active').off().click(unsubscribe);
|
|
} else {
|
|
img = 'tryton-notification-off';
|
|
subscribe_btn.removeClass('active').off().click(subscribe);
|
|
}
|
|
subscribe_btn.html(Sao.common.ICONFACTORY.get_icon_img(img));
|
|
}
|
|
|
|
let subscribe = () => {
|
|
let session = Sao.Session.current_session;
|
|
Sao.rpc({
|
|
'method': 'model.ir.chat.channel.subscribe',
|
|
'params': [this.record, {}],
|
|
}, session).then(() => {
|
|
set_subscribe_state(true);
|
|
})
|
|
};
|
|
|
|
let unsubscribe = () => {
|
|
let session = Sao.Session.current_session;
|
|
Sao.rpc({
|
|
'method': 'model.ir.chat.channel.unsubscribe',
|
|
'params': [this.record, {}],
|
|
}, session).then(() => {
|
|
set_subscribe_state(false);
|
|
})
|
|
};
|
|
|
|
this._messages = jQuery('<div/>', {
|
|
'class': 'chat-messages',
|
|
}).appendTo(jQuery('<div/>', {
|
|
'class': 'chat-messages-outer',
|
|
}).appendTo(el));
|
|
|
|
let input = jQuery('<textarea/>', {
|
|
'class': 'input-sm form-control',
|
|
'placeholder': Sao.i18n.gettext("Enter a message"),
|
|
});
|
|
let submit = jQuery('<button/>', {
|
|
'class': 'btn btn-block btn-default',
|
|
'type': 'submit',
|
|
'aria-label': Sao.i18n.gettext("Submit the message"),
|
|
'title': Sao.i18n.gettext("Send"),
|
|
'text': Sao.i18n.gettext("Send"),
|
|
});
|
|
let internal = jQuery('<input/>', {
|
|
'type': 'checkbox',
|
|
});
|
|
jQuery('<hr/>').appendTo(el);
|
|
let form = jQuery('<form/>')
|
|
.append(jQuery('<div/>', {
|
|
'class': 'form-group',
|
|
}).append(input))
|
|
.append(jQuery('<div/>', {
|
|
'class': 'checkbox',
|
|
}).append(jQuery('<label/>')
|
|
.append(internal)
|
|
.append(Sao.i18n.gettext("Make this an internal message"))))
|
|
.append(submit)
|
|
.appendTo(el);
|
|
|
|
let send = (evt) => {
|
|
evt.preventDefault();
|
|
submit.prop('disabled', true);
|
|
input.prop('disabled', true);
|
|
this.send_message(
|
|
input.val(),
|
|
internal.prop('checked')
|
|
).done(() => {
|
|
input.val('');
|
|
submit.prop('disabled', false);
|
|
input.prop('disabled', false);
|
|
input.trigger('focus');
|
|
internal.prop('checked', false);
|
|
if (!Sao.Bus.listening) {
|
|
this.refresh();
|
|
}
|
|
});
|
|
};
|
|
form.submit(send);
|
|
input.keypress((evt) => {
|
|
if ((evt.which == Sao.common.RETURN_KEYCODE) && evt.ctrlKey) {
|
|
evt.preventDefault();
|
|
form.submit();
|
|
}
|
|
});
|
|
|
|
return el;
|
|
}
|
|
|
|
create_message(message) {
|
|
let avatar_size = 32;
|
|
let timestamp = Sao.common.format_datetime(
|
|
Sao.common.date_format() + ' %X', message.timestamp);
|
|
let avatar_url = '';
|
|
if (message.avatar_url) {
|
|
let url = new URL(message.avatar_url, window.location);
|
|
url.searchParams.set('s', avatar_size);
|
|
avatar_url = url.href;
|
|
}
|
|
return jQuery('<div/>', {
|
|
'class': 'media chat-message',
|
|
}).append(jQuery('<div/>', {
|
|
'class': 'media-left',
|
|
}).append(jQuery('<img/>', {
|
|
'class': 'media-object img-circle chat-avatar',
|
|
'src': avatar_url,
|
|
'alt': message.author,
|
|
'style': `width: ${avatar_size}px; height: ${avatar_size}px;`,
|
|
}))).append(jQuery('<div/>', {
|
|
'class': 'media-body well well-sm',
|
|
}).append(jQuery('<h6/>', {
|
|
'class': 'media-heading',
|
|
}).text(message.author)
|
|
.append(jQuery('<small/>', {
|
|
'class': 'text-muted pull-right',
|
|
}).text(timestamp)))
|
|
.append(jQuery('<div/>', {
|
|
'class': `chat-content chat-content-${message.audience}`,
|
|
}).text(message.content)));
|
|
}
|
|
}
|
|
Sao.Chat = _Chat;
|
|
|
|
}());
|