/** * @param {SlackChan|SlackGroup} chan * @return {Element} **/ function createChanListItem(chan) { var dom = document.createElement("li"); dom.id = chan.id; if (chan.id[0] === 'D') dom.className = R.klass.chatList.entry + " " +R.klass.chatList.typeDirect; else if (chan.id[0] === 'G') dom.className = R.klass.chatList.entry + " " +R.klass.chatList.typeGroup; else if (chan.id[0] === 'C') dom.className = R.klass.chatList.entry + " " +R.klass.chatList.typeChannel; dom.textContent = chan.name; return dom; } /** * @param {SlackIms} ims * @return {Element} **/ function createImsListItem(ims) { var dom = document.createElement("li"); dom.id = ims.id; dom.className = R.klass.chatList.entry; dom.textContent = ims.user.name; return dom; } function onContextUpdated() { var chanListFram = document.createDocumentFragment(); var sortedChans = SLACK.context.self ? Object.keys(SLACK.context.self.channels) : []; sortedChans.sort(function(a, b) { if (a[0] !== b[0]) { return a[0] - b[0]; } return (SLACK.context.channels[a] || SLACK.context.groups[a]).name.localeCompare((SLACK.context.channels[b] || SLACK.context.groups[b]).name); }); sortedChans.forEach(function(chanId) { var chan = SLACK.context.channels[chanId] || SLACK.context.groups[chanId] ,chanListItem = createChanListItem(chan); if (chanListItem) { chanListFram.appendChild(chanListItem); } }); var sortedUsers = SLACK.context.users ? Object.keys(SLACK.context.users) : []; sortedUsers.sort(function(a, b) { return SLACK.context.users[a].name.localeCompare(SLACK.context.users[b].name); }); sortedUsers.forEach(function(userId) { var ims = SLACK.context.users[userId].ims ,imsListItem = createImsListItem(ims); if (imsListItem) { chanListFram.appendChild(imsListItem); } }); document.getElementById(R.id.chanList).textContent = ""; document.getElementById(R.id.chanList).appendChild(chanListFram); } function onNetworkStateUpdated(isNetworkWorking) { isNetworkWorking ? document.body.classList.remove(R.klass.noNetwork) : document.body.classList.add(R.klass.noNetwork); } function onRoomSelected() { var name = SELECTED_ROOM.name || (SELECTED_ROOM.user ? SELECTED_ROOM.user.name : undefined); if (!name) { var members = []; for (var i in SELECTED_ROOM.members) { members.push(SELECTED_ROOM.members[i].name); } name = members.join(", "); } var roomLi = document.getElementById(SELECTED_ROOM.id); document.getElementById(R.id.currentRoom.title).textContent = name; onRoomUpdated(); markRoomAsRead(SELECTED_ROOM); } function createMessageDom(channelId, msg) { var dom = document.createElement("div") ,ts = document.createElement("div") ,text = document.createElement("div") ,author = document.createElement("div") ,authorImg = document.createElement("img") ,authorName = document.createElement("span") ,hover = document.createElement("ul") ,hoverReply = document.createElement("li") ,sender = msg.raw["user"] ? SLACK.context.users[msg.raw["user"]] : SLACK.context.bots[msg.raw["bot_id"]]; dom.id = channelId +"_" +msg.ts; dom.className = R.klass.msg.item; ts.className = R.klass.msg.ts; text.className = R.klass.msg.msg; author.className = R.klass.msg.author; authorImg.className = R.klass.msg.authorAvatar; authorName.className = R.klass.msg.authorname; hover.className = R.klass.msg.hover.container; hoverReply.className = R.klass.msg.hover.reply; ts.textContent = (new Date(msg.ts * 1000)).toLocaleTimeString(); var msgContent = msg.raw["text"] || ""; msgContent = msgContent .replace(new RegExp('<([@#]?)([^>]*)>', 'g'), function(_, type, entity) { var sub = entity.split('|'); if (type === '@') { if (!sub[1]) { var user = SLACK.context.getMember(sub[0]); sub[1] = user ? user.name : "Unknown member"; // TODO locale } sub[0] = '#' +sub[0]; sub[2] = R.klass.msg.link +' ' +R.klass.msg.linkuser; } else if (type === '#') { if (!sub[1]) { var chan = SLACK.context.getChannel(sub[0]); sub[1] = chan ? ('#' +chan.name) : "Unknown channel"; // TODO locale } else if ('#' !== sub[1][0]) { sub[1] = '#' +sub[1]; } sub[0] = '#' +sub[0]; sub[2] = R.klass.msg.link +' ' +R.klass.msg.linkchan; } else { if (!sub[1]) sub[1] = sub[0]; sub[2] = R.klass.msg.link; } return '' +sub[1] +''; }) ; text.innerHTML = msgContent; authorName.textContent = sender ? sender.name : (msg.raw["username"] || "?"); authorImg.src = sender ? sender.icons.image_48 : ""; author.appendChild(authorImg); author.appendChild(authorName); hover.appendChild(hoverReply); dom.appendChild(author); dom.appendChild(text); dom.appendChild(ts); dom.appendChild(hover); return dom; } function updateTitle() { var hasUnread = 0; for (var i in UNREAD_CHANS) { if (UNREAD_CHANS.hasOwnProperty(i)) { hasUnread += UNREAD_CHANS[i]; } } document.title = (hasUnread ? ("(" +hasUnread +") - ") : "") +SLACK.context.team.name; } /** * @param {SlackChan|SlackGroup|SlackIms} chan * @param {Array.<*>} msg **/ function onMsgReceived(chan, msg) { if (chan && (chan !== SELECTED_ROOM || !window.hasFocus)) { document.getElementById(chan.id).classList.add(R.klass.unread); var count = UNREAD_CHANS[chan.id] || 0; UNREAD_CHANS[chan.id] = count + msg.length; updateTitle(); } } /** * @param {SlackChan|SlackGroup|SlackIms} room **/ function markRoomAsRead(room) { if (UNREAD_CHANS[room.id]) { UNREAD_CHANS[room.id] = 0; updateTitle(); } var roomLi = document.getElementById(room.id); roomLi.classList.remove(R.klass.unread); roomLi.classList.remove(R.klass.unreadHi); } function onRoomUpdated() { var chatFrag = document.createDocumentFragment() ,currentRoomId = SELECTED_ROOM.id; document.getElementById(R.id.currentRoom.content).textContent = ""; if (SLACK.history[currentRoomId]) SLACK.history[currentRoomId].messages.forEach(function(msg) { chatFrag.appendChild(createMessageDom(currentRoomId, msg)); }); var content = document.getElementById(R.id.currentRoom.content); content.appendChild(chatFrag); //TODO scroll lock content.scrollTop = content.scrollHeight -content.clientHeight; } function onChanClick(e) { while (e.target !== e.currentTarget && e.target) { if (e.target.classList.contains(R.klass.chatList.entry)) { var room = (SLACK.context.channels[e.target.id] || SLACK.context.ims[e.target.id] || SLACK.context.groups[e.target.id]); if (room && room !== SELECTED_ROOM) { selectRoom(room); } return; } e.target = e.target.parentElement; } } function replyTo(msg) { console.log("Replying to ", msg); } function chatClickDelegate(e) { var target = e.target ,getMessageId = function(e, target) { target = target || e.target; while (target !== e.currentTarget && target) { if (target.classList.contains(R.klass.msg.item)) { return target.id; } target = target.parentElement; } }; while (target !== e.currentTarget && target) { if (target.classList.contains(R.klass.msg.hover.container)) { return; } else if (target.classList.contains(R.klass.msg.hover.reply)) { var messageId = getMessageId(e, target); if (messageId) { messageId = parseFloat(messageId.split("_")[1]); var history = SLACK.history[SELECTED_ROOM.id].messages; for (var i =0, histLen =history.length; i < histLen && history[i].ts <= messageId; i++) { if (history[i].ts === messageId) { replyTo(history[i]); return; } } } return; } target = target.parentElement; } } document.addEventListener('DOMContentLoaded', function() { document.getElementById(R.id.chatList).addEventListener("click", onChanClick); document.getElementById(R.id.currentRoom.content).addEventListener("click", chatClickDelegate); document.getElementById(R.id.message.form).addEventListener("submit", function(e) { e.preventDefault(); var input =document.getElementById(R.id.message.input); if (SELECTED_ROOM && input.value) { sendMsg(SELECTED_ROOM, input.value); input.value = ""; } return false; }); window.addEventListener('blur', function() { window.hasFocus = false; }); window.addEventListener('focus', function() { window.hasFocus = true; if (SELECTED_ROOM) markRoomAsRead(SELECTED_ROOM); }); window.hasFocus = true; startPolling(); });