/** * @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 += `
${(dat.getDate()==(new Date()).getDate())?'(today)':''}
`; } html += `
${acro} (${timestp})
${this.currentHistory[hid].msg.replace(/\n/g, '
')}

`; 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, [ '', acro ]); } addLobbyChannel(chid, lobby) { this.chanlist.addRow('C:'+chid, [ '', lobby.name]); } initView() { this.chatView = { el: null, channels: [], active: false, currentChannel: null }; this.chatView.el = new DropDown(ui.create(`
  • Lobby name...
  • `)).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 = ``; } else if(totUnRead>0) { this.chatView.el.querySelector('button.chat-menu').innerHTML = `${totUnRead}`; } 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