context.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /**
  2. * @constructor
  3. **/
  4. function ChatInfo(id) {
  5. /** @const @type {string} */
  6. this.id = id;
  7. /** @type {string} */
  8. this.name;
  9. /** @type {number} */
  10. this.version = 0;
  11. };
  12. ChatInfo.prototype.toStatic = function(t) {
  13. return t >= this.version ? undefined : {
  14. "id": this.id
  15. ,"name": this.name
  16. };
  17. };
  18. ChatInfo.prototype.update = function(data, t) {
  19. if (data["name"] !== undefined) this.name = data["name"];
  20. this.version = Math.max(this.version, t);
  21. };
  22. /**
  23. * @constructor
  24. * @param {*} data
  25. **/
  26. function Command(data) {
  27. /** @const @type {string} */
  28. this.desc = data["desc"];
  29. /** @const @type {string} */
  30. this.name = data["name"];
  31. /** @const @type {string} */
  32. this.type = data["type"];
  33. /** @const @type {string} */
  34. this.usage = data["usage"];
  35. /** @const @type {string} */
  36. this.category = data["category"];
  37. };
  38. /**
  39. * @param {number} t
  40. * @return {Object}
  41. **/
  42. Command.prototype.toStatic = function(t) {
  43. return {
  44. "desc": this.desc
  45. ,"name": this.name
  46. ,"type": this.type
  47. ,"usage": this.usage
  48. ,"category": this.category
  49. };
  50. };
  51. /**
  52. * @constructor
  53. **/
  54. function SelfPreferences() {
  55. /** @type {Object.<string, number>} */
  56. this.favoriteEmojis = {};
  57. /** @type {Array.<string>} */
  58. this.highlights = [];
  59. };
  60. /**
  61. * @param {*} prefs
  62. **/
  63. SelfPreferences.prototype.update = function(prefs, t) {
  64. this.favoriteEmojis = /** @type {Object<string,number>} */ (JSON.parse(prefs["emoji_use"]));
  65. if (prefs["highlight_words"])
  66. this.highlights = (prefs["highlight_words"]||"").split(',').filter(function(i) {
  67. return i.trim() !== '';
  68. });
  69. else if (prefs["highlights"])
  70. this.highlights = prefs["highlights"];
  71. this.version = Math.max(this.version, t);
  72. };
  73. SelfPreferences.prototype.toStatic = function(t) {
  74. return this.version > t ? null : {
  75. "emoji_use": JSON.stringify(this.favoriteEmojis)
  76. ,"highlights": this.highlights
  77. };
  78. };
  79. /**
  80. * @constructor
  81. **/
  82. function ChatContext() {
  83. /** @type {ChatInfo} */
  84. this.team = null;
  85. /** @type {Object.<string, Room>} */
  86. this.channels = {};
  87. /** @type {Object.<string, Chatter>} */
  88. this.users = {};
  89. /** @type {Chatter} */
  90. this.self = null;
  91. /** @type {{version: number, data: Object.<string, string>}} */
  92. this.emojis = { version: 0, data: {} };
  93. /** @type {{version: number, data: Object.<string, Command>}} */
  94. this.commands = {version: 0, data: {} };
  95. /** @type {Object.<string, Object.<string, number>>} */
  96. this.typing = {};
  97. /** @type {number} */
  98. this.staticV = 0;
  99. /** @type {number} */
  100. this.liveV = 0;
  101. };
  102. ChatContext.prototype.userFactory = function(userData) {
  103. return new Chatter(userData["id"]);
  104. };
  105. ChatContext.prototype.roomFactory = function(roomData) {
  106. return roomData["pv"] ?
  107. new PrivateMessageRoom(roomData["id"], this.users[roomData["user"]]) :
  108. new Room(roomData["id"]);
  109. };
  110. ChatContext.prototype.teamFactory = function(id) {
  111. return new ChatInfo(id);
  112. };
  113. ChatContext.prototype.commandFactory = function(data) {
  114. return new Command(data);
  115. };
  116. /**
  117. * @param {*} data
  118. * @param {number} t
  119. **/
  120. ChatContext.prototype.updateStatic = function(data, t) {
  121. if (data["users"]) for (var i =0, nbUsers = data["users"].length; i < nbUsers; i++) {
  122. var userObj = this.users[data["users"][i]["id"]];
  123. if (!userObj)
  124. userObj = this.users[data["users"][i]["id"]] = this.userFactory(data["users"][i]);
  125. userObj.update(data["users"][i], t);
  126. }
  127. if (data["channels"]) for (var i =0, nbChan = data["channels"].length; i < nbChan; i++) {
  128. var chanObj = this.channels[data["channels"][i]["id"]];
  129. if (!chanObj)
  130. chanObj = this.channels[data["channels"][i]["id"]] = this.roomFactory(data["channels"][i]);
  131. chanObj.update(data["channels"][i], this, t);
  132. }
  133. if (data["emojis"]) {
  134. this.emojis.data = data["emojis"];
  135. this.emojis.version = t;
  136. }
  137. if (data["commands"] !== undefined){
  138. this.commands.data = {};
  139. for (var i in data["commands"]) {
  140. this.commands.data[i] = this.commandFactory(data["commands"][i]);
  141. }
  142. this.commands.version = t;
  143. }
  144. if (data["team"]) {
  145. if (!this.team) this.team = this.teamFactory(data["team"]["id"]);
  146. this.team.update(data["team"], t);
  147. }
  148. this.staticV = Math.max(this.staticV, t);
  149. if (data["self"]) {
  150. this.self = this.users[data["self"]["id"]] || null;
  151. if (this.self) {
  152. if (!this.self.prefs)
  153. this.self.prefs = new SelfPreferences();
  154. this.self.prefs.update(data["self"]["prefs"], t);
  155. } else {
  156. this.staticV = 0;
  157. }
  158. }
  159. if (data["typing"] !== undefined) {
  160. this.typing = {};
  161. for (var i in data["typing"]) {
  162. this.typing[i] = {};
  163. for (var j in data["typing"][i])
  164. this.typing[i][j] = t;
  165. }
  166. }
  167. };
  168. /**
  169. * @param {number} t
  170. * @param {number} now
  171. **/
  172. ChatContext.prototype.toStatic = function(t, now) {
  173. var channels = []
  174. ,users = [];
  175. var res = {
  176. "team": this.team.toStatic(t)
  177. ,"self": {
  178. "id": this.self.id
  179. ,"prefs": this.self.prefs.toStatic(t)
  180. }
  181. ,"emojis": this.emojis.version > t ? this.emojis.data : undefined
  182. };
  183. if (this.commands.version > t) {
  184. res["commands"] = {};
  185. for (var i in this.commands.data)
  186. res["commands"][i] = this.commands.data[i].toStatic(t);
  187. }
  188. for (var chanId in this.channels) {
  189. var chan = this.channels[chanId].toStatic(t);
  190. if (chan)
  191. channels.push(chan);
  192. }
  193. if (channels.length)
  194. res["channels"] = channels;
  195. for (var userId in this.users) {
  196. var user = this.users[userId].toStatic(t);
  197. if (user)
  198. users.push(user);
  199. }
  200. if (users.length)
  201. res["users"] = users;
  202. for (var typingChan in this.typing) {
  203. var tChan = null;
  204. for (var typingUser in this.typing[typingChan]) {
  205. if (this.typing[typingChan][typingUser] +3000 >= now) {
  206. if (!tChan) tChan = {};
  207. tChan[typingUser] = 1;
  208. } else {
  209. delete this.typing[typingChan][typingUser];
  210. }
  211. }
  212. if (tChan) {
  213. if (res["typing"] === undefined)
  214. res["typing"] = {};
  215. res["typing"][typingChan] = tChan;
  216. }
  217. else
  218. delete this.typing[typingChan];
  219. }
  220. return res;
  221. };
  222. /**
  223. * @param {number} now
  224. **/
  225. ChatContext.prototype.cleanTyping = function(now) {
  226. var updated = false;
  227. for (var typingChan in this.typing) {
  228. var chanEmpty = true;
  229. for (var typingUser in this.typing[typingChan]) {
  230. if (this.typing[typingChan][typingUser] +3000 < now) {
  231. delete this.typing[typingChan][typingUser];
  232. updated = true;
  233. } else {
  234. chanEmpty = false;
  235. }
  236. }
  237. if (chanEmpty) {
  238. delete this.typing[typingChan];
  239. updated = true;
  240. }
  241. }
  242. return updated;
  243. };
  244. /** @suppress {undefinedVars,checkTypes} */
  245. (function() {
  246. if (typeof module !== "undefined") {
  247. module.exports.ChatContext = ChatContext;
  248. module.exports.ChatInfo = ChatInfo;
  249. module.exports.Command = Command;
  250. }
  251. })();