265 lines
10 KiB
JavaScript
Executable File
265 lines
10 KiB
JavaScript
Executable File
/**
|
|
* @category MyEic
|
|
* @subcategory Libraries
|
|
*/
|
|
class ChatModule{
|
|
|
|
/**
|
|
*
|
|
* @param {*} appContent
|
|
*/
|
|
constructor(appContent) {
|
|
this.appContent = appContent;
|
|
this.unreadChats = {};
|
|
this.chatTargets = {};
|
|
this.onlineUsers = [];
|
|
this.recipientId = null;
|
|
this.currentHistory = [];
|
|
|
|
this.initView();
|
|
|
|
//TODO: inherit API entry_points
|
|
// this.APmeta.xxxx
|
|
this.APIEntries = {
|
|
'chatTargets' :'/api/chatTargets',
|
|
'':'',
|
|
|
|
};
|
|
|
|
//TODO: Do this on opening the chat-panel ? => when is it updated ?
|
|
this.getConversations()
|
|
.then( this.updateChanList.bind(this) )
|
|
.then( this.RequestOnlineUsers.bind(this));
|
|
this.addMsgBusEvents();
|
|
this.RequestUnreadMsgs();
|
|
}
|
|
|
|
addMsgBusEvents(){
|
|
app.events.addEvent('MessageBus.Connected', this.RequestUnreadMsgs.bind(this));
|
|
app.events.addEvent('MessageBus.Closed', this.updateUnreadBadge.bind(this));
|
|
app.events.addEvent('MessageBus.NOTIFS', this.updateUnreadBadge.bind(this));
|
|
app.events.addEvent('MessageBus.ISONLINE', this.updateOnlineBadges.bind(this));
|
|
app.events.addEvent('MessageBus.CHANHIST', this.replaceHisto.bind(this));
|
|
app.events.addEvent('MessageBus.CHATMSG', this.recvBus.bind(this));
|
|
}
|
|
|
|
RequestUnreadMsgs(){
|
|
return(
|
|
app.MessageBus.requestWssGwAction('NOTIFS', null).then(
|
|
(payload) => {
|
|
this.unreadChats = payload.unreadChats;
|
|
//TODO: share the other stuff with friends... (app.something ??)
|
|
this.updateUnreadBadge();
|
|
},
|
|
(err)=>{ console.warn('MSGBUS error:',err) })
|
|
);
|
|
}
|
|
|
|
RequestOnlineUsers(){
|
|
let usrlist = Object.keys(this.chatTargets.users);
|
|
// Request them now
|
|
app.MessageBus.requestWssGwAction('ISONLINE', usrlist);
|
|
// Watch them
|
|
app.MessageBus.requestWssGwAction('WATCHUSERS', usrlist);
|
|
}
|
|
|
|
getConversations(){
|
|
//TODO use app central fetcher ??? => use fake model like in myUser
|
|
return(fetch(this.APIEntries.chatTargets)
|
|
.then((response) => response.json()));
|
|
}
|
|
|
|
recvBus(e){
|
|
let histoDetail = {};
|
|
histoDetail[e.detail.msg.histId] = {
|
|
'msg' : e.detail.msg.msg,
|
|
'sender' : e.detail.msg.sender
|
|
};
|
|
this.replaceHisto({ 'detail': histoDetail });
|
|
}
|
|
|
|
replaceHisto(e){
|
|
let hids = Object.keys(e.detail);
|
|
for(let hid of hids){ // Insert without creating dups
|
|
if(!(hid in this.currentHistory)) this.currentHistory[hid] = e.detail[hid];
|
|
}
|
|
let html = ''; let day = '';
|
|
let user, acro, dat, timestp;
|
|
for(let hid of Object.keys(this.currentHistory).sort()){
|
|
user = this.chatTargets.users[this.currentHistory[hid].sender];
|
|
acro = user.given_name[0].toUpperCase()+'. '+user.family_name;
|
|
dat = new Date(1*hid.substring(0,hid.indexOf('-')));
|
|
timestp = dat.toLocaleString('fr').replace('/'+new Date().getFullYear(),''); // hide current year
|
|
if((day != '') && (day != dat.getDate())) {
|
|
html += `<div class="day-separator">${(dat.getDate()==(new Date()).getDate())?'(today)':''}</div>`;
|
|
}
|
|
html += `<div class="histo-entry ${(this.currentHistory[hid].sender==app.currentUser.userInfo.sub)?'me':''}">
|
|
<span class="sender">${acro} (${timestp})</span><br>
|
|
${this.currentHistory[hid].msg.replace(/\n/g, '<br>')}
|
|
</div><br>`;
|
|
day = dat.getDate();
|
|
}
|
|
this.chatView.el.querySelector('.history').innerHTML = html;
|
|
this.chatView.el.querySelector('.history').scrollTop = this.chatView.el.querySelector('.history').scrollHeight;
|
|
}
|
|
|
|
updateChanList(chatTargets){
|
|
this.chatTargets = chatTargets;
|
|
for(var uid in chatTargets.users){
|
|
if(uid != app.currentUser.userInfo.sub){
|
|
this.addUserChannel(uid, chatTargets.users[uid]);
|
|
}
|
|
}
|
|
for(var chid in chatTargets.lobbies){
|
|
this.addLobbyChannel(chid, chatTargets.lobbies[chid]);
|
|
}
|
|
}
|
|
|
|
addUserChannel(uid, user) {
|
|
let acro = user.given_name[0].toUpperCase()+'. '+user.family_name;
|
|
this.chanlist.addRow('P:'+uid, [ '<span eicbadge danger class="userled"></span>', acro ]);
|
|
}
|
|
|
|
addLobbyChannel(chid, lobby) {
|
|
this.chanlist.addRow('C:'+chid, [ '<span eicbadge info class="lobbyled"></span>', lobby.name]);
|
|
}
|
|
|
|
initView() {
|
|
this.chatView = {
|
|
el: null,
|
|
channels: [],
|
|
active: false,
|
|
currentChannel: null
|
|
};
|
|
this.chatView.el = new DropDown(ui.create(`
|
|
<div eicdropdown>
|
|
<button eicbutton rounded basic small primary class="icon-comment chat-menu"></button>
|
|
<menu eicmenu>
|
|
<li menuitem>
|
|
<div class="eic-chat">
|
|
<div class="chanlist"></div>
|
|
<div class="lobbyname">Lobby name...</div>
|
|
<div class="history"></div>
|
|
<textarea eictextarea class="message" placeholder="Type message here..."></textarea>
|
|
<button eicbutton small primary class="send" eicicon="icon-send"></button>
|
|
</div>
|
|
</li>
|
|
</menu>
|
|
</div>
|
|
`)).el;
|
|
ui.eicfy(this.chatView.el);
|
|
this.appContent.find('header .eic-session').prepend(this.chatView.el);
|
|
this.chanlist = new DataGrid(this.appContent.find('.chanlist'), {
|
|
headers: [
|
|
{label: '', sortable:true },
|
|
{label: 'name', filter: 'text', sortable:true},
|
|
],
|
|
height: '350px',
|
|
});
|
|
this.chanlist.onRowClick= this.selectChan.bind(this);
|
|
this.chatView.el.querySelector('.send').addEventListener('click', this.onSendMessage.bind(this));
|
|
this.chatView.el.querySelector('.message').addEventListener("keyup", this.onKeyUp.bind(this));
|
|
this.updateUnreadBadge();
|
|
this.chatView.tab = new Tab();
|
|
}
|
|
|
|
onKeyUp(event) {
|
|
if(this.aftertypeTo) clearTimeout(this.aftertypeTo);
|
|
if(event.which == 13 && !event.shiftKey) {
|
|
this.onSendMessage(event);
|
|
return
|
|
}
|
|
this.aftertypeTo = setTimeout(() => {
|
|
this.chatView.el.querySelector('.message').value = this.emotiAscii2Utf(this.chatView.el.querySelector('.message').value);
|
|
}, 900);
|
|
}
|
|
|
|
emotiAscii2Utf(txt) {
|
|
let conv = {
|
|
':-)':'🙂',':)':'🙂',';-)':'😉',';)':'😉',':-D':'😄','x-D':'😂',':-P':'😛',
|
|
':P':'😛',':-|':'😑',':|':'😑',':-(':'🙁',':(':'🙁',":'-)":'😂',":')":'😂',
|
|
":'-(":'😢',":'(":'😢','>:(':'😠','>:[':'😡',':-*':'😘',':*':'😘','O:-)':'😇',
|
|
'O:)':'😇',':-J':'😏'
|
|
}
|
|
for(let emoasci of Object.keys(conv)) {
|
|
if(emoasci == txt.substring(txt.length-emoasci.length)){
|
|
return(txt.substring(0,txt.length-emoasci.length)+conv[emoasci]);
|
|
}
|
|
}
|
|
return(txt);
|
|
}
|
|
|
|
selectChan(e){
|
|
let rawid = e.currentTarget.dataset.id;
|
|
if((rawid[0]!='P') && (rawid[0]!='C')) return;
|
|
this.recipientId = rawid;
|
|
for(let el of this.chatView.el.querySelectorAll(`.chanlist li.row`)){
|
|
el.style.backgroundColor = '';
|
|
el.style.color = '';
|
|
}
|
|
e.currentTarget.style.backgroundColor = 'var(--eicui-app-toolbar-bg-color)';
|
|
e.currentTarget.style.color = 'var(--eicui-base-color-white)';
|
|
this.currentHistory = {};
|
|
let realRecipientId = rawid.substring(2);
|
|
let lobbyname;
|
|
if(this.recipientId[0]=='P') {
|
|
lobbyname = this.chatTargets.users[realRecipientId].given_name+' '+this.chatTargets.users[realRecipientId].family_name
|
|
} else if(this.recipientId[0]=='C') {
|
|
lobbyname = this.chatTargets.lobbies[realRecipientId].name;
|
|
}
|
|
this.chatView.el.querySelector('.lobbyname').innerHTML = lobbyname;
|
|
app.MessageBus.requestWssGwAction('STARTCHAT', this.recipientId);
|
|
app.MessageBus.requestWssGwAction('CHANHIST', this.recipientId);
|
|
}
|
|
|
|
onSendMessage(e){
|
|
let txt = this.chatView.el.querySelector('.message').value;
|
|
app.MessageBus.requestWssGwAction('SENDCHAT', {
|
|
'recipient' : this.recipientId,
|
|
'msg': txt
|
|
})
|
|
this.chatView.el.querySelector('.message').value = '';
|
|
}
|
|
|
|
updateUnreadBadge(){
|
|
//updateUnreadBadge is decoupled from the msgbus via nbUnreadMsgs so you can redraw the UI anytime, not depending on a msgbus request
|
|
let totUnRead = 0;
|
|
for(let chan in this.unreadChats) totUnRead += this.unreadChats[chan];
|
|
|
|
if(!app.MessageBus.connected) {
|
|
this.chatView.el.querySelector('button.chat-menu').innerHTML = `<span class="icon-warning" warning xsmall></span>`;
|
|
} else if(totUnRead>0) {
|
|
this.chatView.el.querySelector('button.chat-menu').innerHTML = `<span eicbadge success xxsmall>${totUnRead}</span>`;
|
|
} else {
|
|
this.chatView.el.querySelector('button.chat-menu').innerHTML = '';
|
|
}
|
|
}
|
|
|
|
updateOnlineBadges(event){
|
|
this.onlineUsers = event.detail;
|
|
let el;
|
|
for(el of this.chatView.el.querySelectorAll(`.eic-chat .userled`)){
|
|
el.removeAttribute('success');
|
|
el.setAttribute('danger','');
|
|
}
|
|
for(let uid of this.onlineUsers){
|
|
el = this.chatView.el.querySelector(`[data-id="P:${uid}"] .userled`);
|
|
if(el) {
|
|
el.removeAttribute('danger');
|
|
el.setAttribute('success','');
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
app.registerClass('ChatModule', ChatModule);
|
|
|
|
|
|
//TODOs
|
|
// Lobbies
|
|
// Return to send, shift-return to CRLF
|
|
// Limit displayed / requested history
|
|
// Store my read / unread msg => real unread notifs
|
|
// Smileys
|