/** @const */ var TYPING_DELAY = 6500; /** * @constructor **/ function ChatInfo(id) { /** @const @type {string} */ this.id = id; /** @type {string} */ this.name; /** @type {number} */ this.version = 0; }; ChatInfo.prototype.toStatic = function(t) { return t >= this.version ? undefined : { "id": this.id ,"name": this.name }; }; ChatInfo.prototype.update = function(data, t) { if (data["name"] !== undefined) this.name = data["name"]; this.version = Math.max(this.version, t); }; /** * @constructor * @param {*} data **/ function Command(data) { /** @const @type {string} */ this.desc = data["desc"]; /** @const @type {string} */ this.name = data["name"]; /** @const @type {string} */ this.type = data["type"]; /** @const @type {string} */ this.usage = data["usage"]; /** @const @type {string} */ this.category = data["category"]; }; /** * @param {number} t * @return {Object} **/ Command.prototype.toStatic = function(t) { return { "desc": this.desc ,"name": this.name ,"type": this.type ,"usage": this.usage ,"category": this.category }; }; /** * @constructor **/ function SelfPreferences() { /** @type {Object.} */ this.favoriteEmojis = {}; /** @type {Array.} */ this.highlights = []; /** @type {number} */ this.version = 0; }; /** * @param {*} prefs **/ SelfPreferences.prototype.update = function(prefs, t) { if (prefs["emoji_use"]) this.favoriteEmojis = /** @type {Object} */ (JSON.parse(prefs["emoji_use"])); if (prefs["highlight_words"]) this.highlights = (prefs["highlight_words"]||"").split(',').filter(function(i) { return i.trim() !== ''; }); else if (prefs["highlights"]) this.highlights = prefs["highlights"]; this.version = Math.max(this.version, t); }; SelfPreferences.prototype.toStatic = function(t) { return this.version <= t ? undefined : { "emoji_use": JSON.stringify(this.favoriteEmojis) ,"highlights": this.highlights }; }; /** * @constructor **/ function ChatContext() { /** @type {ChatInfo} */ this.team = null; /** @type {Object.} */ this.channels = {}; /** @type {Object.} */ this.users = {}; /** @type {Chatter} */ this.self = null; /** @type {{version: number, data: Object.}} */ this.emojis = { version: 0, data: {} }; /** @type {{version: number, data: Object.}} */ this.commands = {version: 0, data: {} }; /** @type {Object.>} */ this.typing = {}; /** @type {Object!} capacities */ this.capacities = {}; /** @type {number} */ this.staticV = 0; /** @type {number} */ this.liveV = 0; /** @type {number} */ this.typingVersion = 0; }; ChatContext.prototype.userFactory = function(userData) { return new Chatter(userData["id"]); }; ChatContext.prototype.roomFactory = function(roomData) { return roomData["pv"] ? new PrivateMessageRoom(roomData["id"], this.users[roomData["user"]]) : new Room(roomData["id"]); }; ChatContext.prototype.teamFactory = function(id) { return new ChatInfo(id); }; ChatContext.prototype.commandFactory = function(data) { return new Command(data); }; /** * @param {*} data * @param {number} t * @param {string=} idPrefix **/ ChatContext.prototype.updateStatic = function(data, t, idPrefix) { idPrefix = idPrefix || ""; if (data["team"]) { if (!this.team) this.team = this.teamFactory(data["team"]["id"]); this.team.update(data["team"], t); } if (data["users"]) for (var i =0, nbUsers = data["users"].length; i < nbUsers; i++) { var userObj = this.users[idPrefix +data["users"][i]["id"]]; if (!userObj) userObj = this.users[idPrefix +data["users"][i]["id"]] = this.userFactory(data["users"][i]); userObj.update(data["users"][i], t); } if (data["channels"]) for (var i =0, nbChan = data["channels"].length; i < nbChan; i++) { var chanObj = this.channels[idPrefix +data["channels"][i]["id"]]; if (!chanObj) chanObj = this.channels[idPrefix +data["channels"][i]["id"]] = this.roomFactory(data["channels"][i]); chanObj.update(data["channels"][i], this, t, idPrefix); } if (data["emojis"]) { this.emojis.data = data["emojis"]; this.emojis.version = t; } if (data["commands"] !== undefined){ this.commands.data = {}; for (var i in data["commands"]) { this.commands.data[i] = this.commandFactory(data["commands"][i]); } this.commands.version = t; } if (data["self"]) { this.self = this.users[idPrefix +data["self"]["id"]] || null; if (!this.self.prefs) this.self.prefs = new SelfPreferences(); if (data["self"]["prefs"]) { this.self.prefs.update(data["self"]["prefs"], t); } } if (data["capacities"]) { this.capacities = {}; data["capacities"].forEach(function(i) { this.capacities[i] = true; }, this); } this.staticV = Math.max(this.staticV, t); }; ChatContext.prototype.updateTyping = function(typing, now) { var updated = false; if (this.typing) for (var i in this.typing) if (typing && !typing[i]) { delete (this.typing[i]); updated = true; } if (typing) { for (var i in typing) { if (this.channels[i]) { if (!this.typing[i]) this.typing[i] = {}; for (var j in typing[i]) { if (!this.typing[i][j]) updated = true; this.typing[i][j] = now; } } } } if (updated) this.typingVersion = now; return updated; }; /** * @param {number} t **/ ChatContext.prototype.toStatic = function(t) { var channels = [] ,users = []; var res = { "team": this.team.toStatic(t) ,"self": { "id": this.self.id ,"prefs": this.self.prefs ? this.self.prefs.toStatic(t) : undefined } ,"emojis": this.emojis.version > t ? this.emojis.data : undefined }; if (this.staticV > t) { res["capacities"] = Object.keys(this.capacities); } if (this.commands.version > t) { res["commands"] = {}; for (var i in this.commands.data) res["commands"][i] = this.commands.data[i].toStatic(t); } for (var chanId in this.channels) { var chan = this.channels[chanId].toStatic(t); if (chan) channels.push(chan); } if (channels.length) res["channels"] = channels; for (var userId in this.users) { var user = this.users[userId].toStatic(t); if (user) users.push(user); } if (users.length) res["users"] = users; return res; }; /** * @param {number} version * @return {Object>|undefined} **/ ChatContext.prototype.getWhoIsTyping = function(version, now) { var res; this.cleanTyping(now); if (this.typingVersion > version) { res = {}; for (var typingChan in this.typing) { res[typingChan] = {}; for (var typingUser in this.typing[typingChan]) res[typingChan][typingUser] = 1; } } return res; }; /** * @param {string} chanNameOrUserName * @return {Room|null} **/ ChatContext.prototype.getRoom = function(chanNameOrUserName) { var chans = this.getChannelsWithName(chanNameOrUserName); if (chans.length) return chans[0]; var users = this.getUsersWithName(chanNameOrUserName); if (users.length) for (var i =0, nbUsers = users.length; i < nbUsers; i++) if (users[i].privateRoom) return users[i].privateRoom; return null; }; ChatContext.prototype.getChannelsWithName = function(name) { var chans = []; if (name[0] === '#') name = name.substr(1); for (var i in this.channels) if (this.channels[i].name === name) chans.push(this.channels[i]); return chans; }; ChatContext.prototype.getUsersWithName = function(name) { var users = []; if (name[0] === '@') name = name.substr(1); for (var i in this.users) if (this.users[i].getName() === name) users.push(this.channels[i]); return users; }; /** * @param {number} now **/ ChatContext.prototype.cleanTyping = function(now) { var updated = false; for (var typingChan in this.typing) { var chanEmpty = true; for (var typingUser in this.typing[typingChan]) { if (this.typing[typingChan][typingUser] +TYPING_DELAY < now) { delete this.typing[typingChan][typingUser]; updated = true; } else { chanEmpty = false; } } if (chanEmpty) { delete this.typing[typingChan]; updated = true; } } if (updated) this.typingVersion = now; return updated; }; ChatContext.prototype.stopTyping = function(chanId, userId, t) { if (this.typing[chanId] && this.typing[chanId][userId]) { delete this.typing[chanId][userId]; var empty = true; for (var i in this.typing[chanId]) { empty = false; break; } if (empty) delete this.typing[chanId]; this.typingVersion = t; } }; /** @suppress {undefinedVars,checkTypes} */ (function() { if (typeof module !== "undefined") { module.exports.ChatContext = ChatContext; module.exports.ChatInfo = ChatInfo; module.exports.Command = Command; } })();