/* jshint sub: true */ var /** * @type {SlackWrapper} **/ DATA, /** * @type {Array.} **/ HIGHLIGHTED_CHANS = []; /** * @constructor * @implements {ChatSystem} * @extends {ChatContext} **/ function SimpleChatSystem() { ChatContext.call(this); } SimpleChatSystem.prototype = Object.create(ChatContext.prototype); SimpleChatSystem.prototype.constructor = SimpleChatSystem; SimpleChatSystem.prototype.getId = function() { return this.team ? this.team.id : null; }; SimpleChatSystem.prototype.getChatContext = function() { return this; }; SimpleChatSystem.prototype.onRequest = function() { console.error("unimplemented"); }; SimpleChatSystem.prototype.sendMeMsg = function(chan, text) { console.error("unimplemented"); }; SimpleChatSystem.prototype.sendMsg = function(chan, text, attachments) { console.error("unimplemented"); }; SimpleChatSystem.prototype.removeMsg = function(chan, ts) { console.error("unimplemented"); }; SimpleChatSystem.prototype.editMsg = function(chan, ts, newText) { console.error("unimplemented"); }; SimpleChatSystem.prototype.addReaction = function(chan, ts, reaction) { console.error("unimplemented"); }; SimpleChatSystem.prototype.removeReaction = function(chan, ts, reaction) { console.error("unimplemented"); }; SimpleChatSystem.prototype.openUploadFileStream = function(chan, contentType, callback) { console.error("unimplemented"); }; SimpleChatSystem.prototype.fetchHistory = function(chan) { console.error("unimplemented"); }; SimpleChatSystem.prototype.sendTyping = function(chan) { console.error("unimplemented"); }; SimpleChatSystem.prototype.markRead = function(chan, ts) { console.error("unimplemented"); }; SimpleChatSystem.prototype.sendCommand = function(chan, cmd, args) { console.error("unimplemented"); }; SimpleChatSystem.prototype.poll = function(knownVersion, now) { console.error("unimplemented"); return null; }; /** * @constructor **/ function SlackWrapper() { /** @type {number} */ this.lastServerVersion = 0; /** @type {MultiChatManager} */ this.context = new MultiChatManager(); /** @type {!Object.} **/ this.history = {}; } SlackWrapper.prototype.update = function(data) { var now = Date.now(), i; if (data["v"]) this.lastServerVersion = data["v"]; if (data["static"]) { for (i in data["static"]) { var ctx = this.context.getById(i); if (!ctx) { ctx = new SimpleChatSystem(); this.context.push(ctx); } ctx.getChatContext().updateStatic(data["static"][i], now); } } this.context.foreachChannels(function(chan) { if (chan.lastMsg === chan.lastRead) { var pos = HIGHLIGHTED_CHANS.indexOf(chan); if (pos !== -1) HIGHLIGHTED_CHANS.splice(pos, 1); } }); if (data["live"]) { for (i in data["live"]) { var history = this.history[i]; if (!history) history = this.history[i] = new UiRoomHistory(i, 250, data["live"][i], now); else history.pushAll(data["live"][i], now); } for (var roomId in data["live"]) { var liveCtx = this.context.getChannelContext(roomId).getChatContext(), chan = liveCtx.channels[roomId]; if (chan) { if (this.history[roomId].messages.length) chan.lastMsg = Math.max(chan.lastMsg, this.history[roomId].lastMessage().ts); if (!chan.archived) { onMsgReceived(liveCtx, chan, data["live"][roomId]); if (SELECTED_ROOM && data["live"][SELECTED_ROOM.id]) onRoomUpdated(); } } else { outOfSync(); } } } if (data["static"]) { onContextUpdated(); } var typingUpdated = false; if (data["typing"]) { this.context.contexts.forEach(function(ctx) { var chatCtx = ctx.getChatContext(); typingUpdated |= chatCtx.updateTyping(data["typing"], now); }, this); } if (data["static"] || typingUpdated) onTypingUpdated(); }; setInterval(function() { var updated = false, now = Date.now(); DATA.context.foreachContext(function(ctx) { if (ctx.getChatContext().cleanTyping(now)) updated = true; }); if (updated) onTypingUpdated(); }, 1000); /** * @param {ChatContext} ctx * @param {string} text * @return {boolean} **/ function isHighlighted(ctx, text) { var highlights = ctx.self.prefs.highlights; for (var i =0, nbHighlights = highlights.length; i < nbHighlights; i++) if (text.indexOf(highlights[i]) !== -1) { return true; } return false; } /** * @param {ChatContext} ctx * @param {Room} chan * @param {Array.<*>} msg **/ function onMsgReceived(ctx, chan, msg) { if (chan !== SELECTED_ROOM || !window.hasFocus) { var selfReg = new RegExp("<@" +ctx.self.id), // FIXME remove context id highligted = false, areNew = false, newHighlited = false; msg.forEach(function(i) { if (parseFloat(i["ts"]) <= chan.lastRead) { return; } areNew = true; if (chan instanceof PrivateMessageRoom || (i["text"] && (i["text"].match(selfReg) || isHighlighted(ctx, i["text"])))) { if (HIGHLIGHTED_CHANS.indexOf(chan) === -1) { newHighlited = true; HIGHLIGHTED_CHANS.push(chan); } highligted = true; } }); if (areNew) { updateTitle(); var dom = document.getElementById("room_" +chan.id); if (dom) { dom.classList.add(R.klass.unread); if (highligted) dom.classList.add(R.klass.unreadHi); } if (newHighlited && !window.hasFocus) { // TODO setting spawnNotification(); } } } } /** * @param {Room} room **/ function markRoomAsRead(room) { var highlightIndex = HIGHLIGHTED_CHANS.indexOf(room); if (room.lastMsg > room.lastRead) { sendReadMArker(room, room.lastMsg); room.lastRead = room.lastMsg; } if (highlightIndex >= 0) { HIGHLIGHTED_CHANS.splice(highlightIndex, 1); updateTitle(); } var roomLi = document.getElementById("room_" +room.id); roomLi.classList.remove(R.klass.unread); roomLi.classList.remove(R.klass.unreadHi); } DATA = new SlackWrapper();